From 762b1299c10b42fb91bbeb9c9209c407f7915a6a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 10:40:46 +0200 Subject: [PATCH 001/482] - Added Performance Tests --- worlds/stardew_valley/test/__init__.py | 48 ++++++- .../test/performance/TestPerformance.py | 120 ++++++++++++++++++ .../test/performance/__init__.py | 0 3 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 worlds/stardew_valley/test/performance/TestPerformance.py create mode 100644 worlds/stardew_valley/test/performance/__init__.py diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index ba037f7a65da..52c09f486d68 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -1,9 +1,9 @@ import os import unittest from argparse import Namespace -from typing import Dict, FrozenSet, Tuple, Any, ClassVar +from typing import Dict, FrozenSet, Tuple, Any, ClassVar, Iterable -from BaseClasses import MultiWorld +from BaseClasses import MultiWorld, CollectionState from Utils import cache_argsless from test.TestBase import WorldTestBase from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld @@ -21,6 +21,17 @@ class SVTestCase(unittest.TestCase): skip_extra_tests: bool = True """Set to False to run tests that take long""" skip_long_tests: bool = True + """Set to False to run tests that take long""" + skip_performance_tests: bool = True + + def setUp(self) -> None: + super().setUp() + long_tests_key = "long" + if long_tests_key in os.environ: + self.skip_long_tests = not bool(os.environ[long_tests_key]) + performance_tests_key = "performance" + if performance_tests_key in os.environ: + self.skip_performance_tests = not bool(os.environ[performance_tests_key]) class SVTestBase(WorldTestBase, SVTestCase): @@ -29,9 +40,6 @@ class SVTestBase(WorldTestBase, SVTestCase): def world_setup(self, *args, **kwargs): super().world_setup(*args, **kwargs) - long_tests_key = "long" - if long_tests_key in os.environ: - self.skip_long_tests = not bool(os.environ[long_tests_key]) if self.constructed: self.world = self.multiworld.worlds[self.player] # noqa @@ -114,8 +122,7 @@ def allsanity_options_with_mods(): # Mostly a copy of test.general.setup_solo_multiworld, I just don't want to change the core. -def setup_solo_multiworld(test_options=None, seed=None, - _cache: Dict[FrozenSet[Tuple[str, Any]], MultiWorld] = {}) -> MultiWorld: # noqa +def setup_solo_multiworld(test_options=None, seed=None, _cache: Dict[FrozenSet[Tuple[str, Any]], MultiWorld] = {}) -> MultiWorld: # noqa if test_options is None: test_options = {} @@ -138,3 +145,30 @@ def setup_solo_multiworld(test_options=None, seed=None, _cache[frozen_options] = multiworld return multiworld + + +def setup_multiworld(test_options: Iterable[Dict[str, int]] = None, seed=None) -> MultiWorld: # noqa + if test_options is None: + test_options = [] + + multiworld = MultiWorld(len(test_options)) + multiworld.player_name = {} + multiworld.set_seed(seed) + multiworld.state = CollectionState(multiworld) + for i in range(1, len(test_options) + 1): + args = Namespace() + multiworld.game[i] = StardewValleyWorld.game + multiworld.player_name.update({i: f"Tester{i}"}) + for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): + options = {} + for i in range(1, len(test_options) + 1): + player_options = test_options[i-1] + value = option(player_options[name]) if name in player_options else option.from_any(option.default) + options.update({i: value}) + setattr(args, name, options) + multiworld.set_options(args) + + for step in gen_steps: + call_all(multiworld, step) + + return multiworld diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py new file mode 100644 index 000000000000..0abee6eb0f57 --- /dev/null +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -0,0 +1,120 @@ +import time + +from BaseClasses import get_seed +from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, \ + allsanity_options_with_mods, setup_multiworld + +number_generations = 10 +acceptable_deviation = 2 + + +def performance_test_multiworld(tester, options, acceptable_time_per_player): + number_players = len(options) + acceptable_average_time = acceptable_time_per_player * number_players + total_time = 0 + for i in range(number_generations): + seed = get_seed() + with tester.subTest(f"Seed: {seed}"): + time_before = time.time() + multiworld = setup_multiworld(options, seed) + time_after = time.time() + elapsed_time = time_after - time_before + print(f"Multiworld {i + 1}/{number_generations} [{seed}] generated in {elapsed_time} seconds") + total_time += elapsed_time + tester.assertLessEqual(elapsed_time, acceptable_average_time * acceptable_deviation) + size = size_name(number_players) + print(f"Generated {number_generations} {size} multiworlds in {total_time} seconds") + average_time = total_time / number_generations + print(f"Average time per world: {average_time} seconds (Acceptable: {acceptable_average_time})") + tester.assertLessEqual(average_time, acceptable_average_time) + + +def size_name(number_players): + if number_players == 1: + return "solo" + elif number_players == 2: + return "duo" + elif number_players == 3: + return "trio" + return f"{number_players}-player" + + +class TestMinLocationMaxItems(SVTestCase): + acceptable_time_per_player = 0.35 + options = minimal_locations_maximal_items() + + def test_solo_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 1 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_duo_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 2 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_5_player_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 5 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_10_player_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 10 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + +class TestAllsanityWithoutMods(SVTestCase): + acceptable_time_per_player = 0.35 + options = allsanity_options_without_mods() + + def test_solo_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 1 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_duo_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 2 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_5_player_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 5 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_10_player_multiworld(self): + if self.skip_performance_tests: + return + + number_players = 10 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + +# class TestAllsanityWithMods(SVTestCase): +# +# def test_allsanity_with_mods_has_at_least_locations(self): +# allsanity_options = allsanity_options_with_mods() +# multiworld = setup_solo_multiworld(allsanity_options) diff --git a/worlds/stardew_valley/test/performance/__init__.py b/worlds/stardew_valley/test/performance/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 From ac1e61fbbae55506e1d67311007a3a34abfdd4fe Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 11:10:54 +0200 Subject: [PATCH 002/482] - Add default options test --- worlds/stardew_valley/test/__init__.py | 6 ++ .../test/performance/TestPerformance.py | 61 +++++++++++++++---- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 52c09f486d68..1926a64c0ee9 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -73,6 +73,12 @@ def minimal_locations_maximal_items(): return min_max_options +@cache_argsless +def default_options(): + default = {} + return default + + @cache_argsless def allsanity_options_without_mods(): allsanity = { diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 0abee6eb0f57..bf7dfada636a 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -2,10 +2,10 @@ from BaseClasses import get_seed from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, \ - allsanity_options_with_mods, setup_multiworld + allsanity_options_with_mods, setup_multiworld, default_options -number_generations = 10 -acceptable_deviation = 2 +number_generations = 25 +acceptable_deviation = 4 def performance_test_multiworld(tester, options, acceptable_time_per_player): @@ -39,11 +39,48 @@ def size_name(number_players): return f"{number_players}-player" +class TestDefaultOptions(SVTestCase): + acceptable_time_per_player = 0.30 + options = default_options() + + def test_solo(self): + if self.skip_performance_tests: + return + + number_players = 1 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_duo(self): + if self.skip_performance_tests: + return + + number_players = 2 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_5_player(self): + if self.skip_performance_tests: + return + + number_players = 5 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + def test_10_player(self): + if self.skip_performance_tests: + return + + number_players = 10 + multiworld_options = [self.options] * number_players + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + + class TestMinLocationMaxItems(SVTestCase): acceptable_time_per_player = 0.35 options = minimal_locations_maximal_items() - def test_solo_multiworld(self): + def test_solo(self): if self.skip_performance_tests: return @@ -51,7 +88,7 @@ def test_solo_multiworld(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - def test_duo_multiworld(self): + def test_duo(self): if self.skip_performance_tests: return @@ -59,7 +96,7 @@ def test_duo_multiworld(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - def test_5_player_multiworld(self): + def test_5_player(self): if self.skip_performance_tests: return @@ -67,7 +104,7 @@ def test_5_player_multiworld(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - def test_10_player_multiworld(self): + def test_10_player(self): if self.skip_performance_tests: return @@ -77,10 +114,10 @@ def test_10_player_multiworld(self): class TestAllsanityWithoutMods(SVTestCase): - acceptable_time_per_player = 0.35 + acceptable_time_per_player = 0.30 options = allsanity_options_without_mods() - def test_solo_multiworld(self): + def test_solo(self): if self.skip_performance_tests: return @@ -88,7 +125,7 @@ def test_solo_multiworld(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - def test_duo_multiworld(self): + def test_duo(self): if self.skip_performance_tests: return @@ -96,7 +133,7 @@ def test_duo_multiworld(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - def test_5_player_multiworld(self): + def test_5_player(self): if self.skip_performance_tests: return @@ -104,7 +141,7 @@ def test_5_player_multiworld(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - def test_10_player_multiworld(self): + def test_10_player(self): if self.skip_performance_tests: return From a48ce05ab7f14efd16585398858a498a8ecc7b0c Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 11:24:18 +0200 Subject: [PATCH 003/482] - Add cache for weapon rules (hotspot) --- worlds/stardew_valley/logic.py | 39 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index d4476a3f313a..bca90b1135b7 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -82,7 +82,7 @@ fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] -@dataclass(frozen=True, repr=False) +@dataclass(frozen=False, repr=False) class StardewLogic: player: int options: StardewValleyOptions @@ -99,6 +99,11 @@ class StardewLogic: quest_rules: Dict[str, StardewRule] = field(default_factory=dict) festival_rules: Dict[str, StardewRule] = field(default_factory=dict) special_order_rules: Dict[str, StardewRule] = field(default_factory=dict) + any_weapon_rule: StardewRule = None + decent_weapon_rule: StardewRule = None + good_weapon_rule: StardewRule = None + great_weapon_rule: StardewRule = None + galaxy_weapon_rule: StardewRule = None def __post_init__(self): self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) @@ -1250,31 +1255,29 @@ def has_island_transport(self) -> StardewRule: return self.received(Transportation.island_obelisk) | self.received(Transportation.boat_repair) def has_any_weapon(self) -> StardewRule: - return self.has_decent_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups) + if not self.any_weapon_rule: + self.any_weapon_rule = self.has_decent_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups) + return self.any_weapon_rule def has_decent_weapon(self) -> StardewRule: - return (self.has_good_weapon() | - self.received(item.name for item in all_items - if Group.WEAPON in item.groups and - (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups))) + if not self.decent_weapon_rule: + self.decent_weapon_rule = self.has_good_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) + return self.decent_weapon_rule def has_good_weapon(self) -> StardewRule: - return ((self.has_great_weapon() | - self.received(item.name for item in all_items - if Group.WEAPON in item.groups and - (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups))) & - self.received("Adventurer's Guild")) + if not self.good_weapon_rule: + self.good_weapon_rule = self.has_great_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) + return self.good_weapon_rule def has_great_weapon(self) -> StardewRule: - return ((self.has_galaxy_weapon() | - self.received(item.name for item in all_items - if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups)) & - self.received("Adventurer's Guild")) + if not self.great_weapon_rule: + self.great_weapon_rule = self.has_galaxy_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) + return self.great_weapon_rule def has_galaxy_weapon(self) -> StardewRule: - return (self.received(item.name for item in all_items - if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) & - self.received("Adventurer's Guild")) + if not self.galaxy_weapon_rule: + self.galaxy_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) + return self.galaxy_weapon_rule def has_year_two(self) -> StardewRule: return self.has_lived_months(4) From f9fa2dd051c579216b1d3e84250522ed455a9823 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 16:54:34 +0200 Subject: [PATCH 004/482] - Added caching for many hotspot rules --- worlds/stardew_valley/logic.py | 122 ++++++++++++------ .../test/performance/TestPerformance.py | 22 +++- 2 files changed, 99 insertions(+), 45 deletions(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index bca90b1135b7..e11341d656a4 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -99,6 +99,7 @@ class StardewLogic: quest_rules: Dict[str, StardewRule] = field(default_factory=dict) festival_rules: Dict[str, StardewRule] = field(default_factory=dict) special_order_rules: Dict[str, StardewRule] = field(default_factory=dict) + cached_rules: Dict[str, StardewRule] = field(default_factory=dict) any_weapon_rule: StardewRule = None decent_weapon_rule: StardewRule = None good_weapon_rule: StardewRule = None @@ -578,20 +579,21 @@ def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) - return TotalReceived(count, items, self.player) def can_reach_region(self, spot: str) -> StardewRule: - return Reach(spot, "Region", self.player) + key = f"can_reach_region {spot}" + if key not in self.cached_rules: + self.cached_rules[key] = Reach(spot, "Region", self.player) + return self.cached_rules[key] def can_reach_any_region(self, spots: Iterable[str]) -> StardewRule: - return Or(self.can_reach_region(spot) for spot in spots) + spots = list(spots) + key = f"can_reach_any_region {spots}" + if key not in self.cached_rules: + self.cached_rules[key] = Or(self.can_reach_region(spot) for spot in spots) + return self.cached_rules[key] def can_reach_all_regions(self, spots: Iterable[str]) -> StardewRule: return And(self.can_reach_region(spot) for spot in spots) - def can_reach_all_regions_except_one(self, spots: Iterable[str]) -> StardewRule: - num_required = len(list(spots)) - 1 - if num_required <= 0: - num_required = len(list(spots)) - return Count(num_required, [self.can_reach_region(spot) for spot in spots]) - def can_reach_location(self, spot: str) -> StardewRule: return Reach(spot, "Location", self.player) @@ -602,14 +604,24 @@ def can_have_earned_total_money(self, amount: int) -> StardewRule: return self.has_lived_months(min(8, amount // MONEY_PER_MONTH)) def can_spend_money(self, amount: int) -> StardewRule: - if self.options.starting_money == -1: - return True_() - return self.has_lived_months(min(8, amount // (MONEY_PER_MONTH // 5))) + key = f"can_spend_money {amount}" + if key not in self.cached_rules: + if self.options.starting_money == -1: + self.cached_rules[key] = True_() + else: + self.cached_rules[key] = self.has_lived_months(min(8, amount // (MONEY_PER_MONTH // 5))) + return self.cached_rules[key] def can_spend_money_at(self, region: str, amount: int) -> StardewRule: return self.can_reach_region(region) & self.can_spend_money(amount) def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: + key = f"has_tool {tool} {material}" + if key not in self.cached_rules: + self.cached_rules[key] = self._has_tool(tool, material) + return self.cached_rules[key] + + def _has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: if material == ToolMaterial.basic or tool == Tool.scythe: return True_() @@ -619,6 +631,12 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule return self.has(f"{material} Bar") & self.can_spend_money(tool_upgrade_prices[material]) def can_earn_skill_level(self, skill: str, level: int) -> StardewRule: + key = f"can_earn_skill_level {skill} {level}" + if key not in self.cached_rules: + self.cached_rules[key] = self._can_earn_skill_level(skill, level) + return self.cached_rules[key] + + def _can_earn_skill_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -647,6 +665,12 @@ def can_earn_skill_level(self, skill: str, level: int) -> StardewRule: return previous_level_rule & months_rule & xp_rule def has_skill_level(self, skill: str, level: int) -> StardewRule: + key = f"has_skill_level {skill} {level}" + if key not in self.cached_rules: + self.cached_rules[key] = self._has_skill_level(skill, level) + return self.cached_rules[key] + + def _has_skill_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -800,12 +824,15 @@ def can_buy_sapling(self, fruit: str) -> StardewRule: return allowed_buy_sapling & can_buy_sapling def can_grow_crop(self, crop: CropItem) -> StardewRule: - season_rule = self.has_any_season(crop.farm_growth_seasons) - seed_rule = self.has(crop.seed.name) - farm_rule = self.can_reach_region(Region.farm) & season_rule - tool_rule = self.has_tool(Tool.hoe) & self.has_tool(Tool.watering_can) - region_rule = farm_rule | self.can_reach_region(Region.greenhouse) | self.can_reach_region(Region.island_west) - return seed_rule & region_rule & tool_rule + key = f"can_grow_crop {crop.name}" + if key not in self.cached_rules: + season_rule = self.has_any_season(crop.farm_growth_seasons) + seed_rule = self.has(crop.seed.name) + farm_rule = self.can_reach_region(Region.farm) & season_rule + tool_rule = self.has_tool(Tool.hoe) & self.has_tool(Tool.watering_can) + region_rule = farm_rule | self.can_reach_region(Region.greenhouse) | self.can_reach_region(Region.island_west) + self.cached_rules[key] = seed_rule & region_rule & tool_rule + return self.cached_rules[key] def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> StardewRule: if isinstance(seasons, str): @@ -1088,14 +1115,15 @@ def has_relationship(self, npc: str, hearts: int = 1) -> StardewRule: return self.can_earn_relationship(npc, hearts) is_capped_at_8 = villager.bachelor and friendsanity != Friendsanity.option_all_with_marriage if is_capped_at_8 and hearts > 8: - return self.received_hearts(villager, 8) & self.can_earn_relationship(npc, hearts) - return self.received_hearts(villager, hearts) + return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) + return self.received_hearts(villager.name, hearts) - def received_hearts(self, npc: Union[str, Villager], hearts: int) -> StardewRule: - if isinstance(npc, Villager): - return self.received_hearts(npc.name, hearts) - heart_size = self.options.friendsanity_heart_size.value - return self.received(self.heart(npc), math.ceil(hearts / heart_size)) + def received_hearts(self, npc: str, hearts: int) -> StardewRule: + key = f"received_hearts {npc}, {hearts}" + if key not in self.cached_rules: + heart_size = self.options.friendsanity_heart_size.value + self.cached_rules[key] = self.received(self.heart(npc), math.ceil(hearts / heart_size)) + return self.cached_rules[key] def can_meet(self, npc: str) -> StardewRule: if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): @@ -1301,14 +1329,17 @@ def can_donate_museum_minerals(self, number: int) -> StardewRule: return self.can_reach_region(Region.museum) & self.can_find_museum_minerals(number) def can_find_museum_item(self, item: MuseumItem) -> StardewRule: - region_rule = self.can_reach_all_regions_except_one(item.locations) - geodes_rule = And([self.can_open_geode(geode) for geode in item.geodes]) - # monster_rule = self.can_farm_monster(item.monsters) - # extra_rule = True_() - pan_rule = False_() - if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": - pan_rule = self.can_do_panning() - return pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule + key = f"can_find_museum_item {item.name}" + if key not in self.cached_rules: + region_rule = self.can_reach_any_region(item.locations) + geodes_rule = And([self.can_open_geode(geode) for geode in item.geodes]) + # monster_rule = self.can_farm_monster(item.monsters) + # extra_rule = True_() + pan_rule = False_() + if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": + pan_rule = self.can_do_panning() + self.cached_rules[key] = pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule + return self.cached_rules[key] def can_find_museum_artifacts(self, number: int) -> StardewRule: rules = [] @@ -1342,6 +1373,12 @@ def can_complete_museum(self) -> StardewRule: return And(rules) def has_season(self, season: str) -> StardewRule: + key = f"has_season {season}" + if key not in self.cached_rules: + self.cached_rules[key] = self._has_season(season) + return self.cached_rules[key] + + def _has_season(self, season: str) -> StardewRule: if season == Generic.any: return True_() seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] @@ -1367,8 +1404,11 @@ def has_all_seasons(self, seasons: Iterable[str]): return And([self.has_season(season) for season in seasons]) def has_lived_months(self, number: int) -> StardewRule: - number = max(0, min(number, MAX_MONTHS)) - return self.received("Month End", number) + key = f"has_lived_months {number}" + if key not in self.cached_rules: + number = max(0, min(number, MAX_MONTHS)) + self.cached_rules[key] = self.received("Month End", number) + return self.cached_rules[key] def has_rusty_key(self) -> StardewRule: return self.received(Wallet.rusty_key) @@ -1517,11 +1557,15 @@ def has_any_barn_animal(self) -> StardewRule: return barn_rule def can_open_geode(self, geode: str) -> StardewRule: - blacksmith_access = self.can_reach_region("Clint's Blacksmith") - geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] - if geode == Generic.any: - return blacksmith_access & Or([self.has(geode_type) for geode_type in geodes]) - return blacksmith_access & self.has(geode) + key = f"can_open_geode {geode}" + if key not in self.cached_rules: + blacksmith_access = self.can_reach_region("Clint's Blacksmith") + geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] + if geode == Generic.any: + self.cached_rules[key] = blacksmith_access & Or([self.has(geode_type) for geode_type in geodes]) + else: + self.cached_rules[key] = blacksmith_access & self.has(geode) + return self.cached_rules[key] def has_island_trader(self) -> StardewRule: if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index bf7dfada636a..f313c7533b89 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -12,6 +12,7 @@ def performance_test_multiworld(tester, options, acceptable_time_per_player): number_players = len(options) acceptable_average_time = acceptable_time_per_player * number_players total_time = 0 + all_times = {} for i in range(number_generations): seed = get_seed() with tester.subTest(f"Seed: {seed}"): @@ -19,12 +20,20 @@ def performance_test_multiworld(tester, options, acceptable_time_per_player): multiworld = setup_multiworld(options, seed) time_after = time.time() elapsed_time = time_after - time_before - print(f"Multiworld {i + 1}/{number_generations} [{seed}] generated in {elapsed_time} seconds") total_time += elapsed_time - tester.assertLessEqual(elapsed_time, acceptable_average_time * acceptable_deviation) + all_times[i] = elapsed_time + print(f"Multiworld {i + 1}/{number_generations} [{seed}] generated in {elapsed_time} seconds") + # tester.assertLessEqual(elapsed_time, acceptable_average_time * acceptable_deviation) size = size_name(number_players) - print(f"Generated {number_generations} {size} multiworlds in {total_time} seconds") average_time = total_time / number_generations + # Remove outliers + num_outliers = 0 + for world in all_times: + if all_times[world] > average_time * 4: + num_outliers += 1 + total_time -= all_times[world] + average_time = total_time / (number_generations - num_outliers) + print(f"Generated {(number_generations - num_outliers)} {size} multiworlds in {total_time} seconds") print(f"Average time per world: {average_time} seconds (Acceptable: {acceptable_average_time})") tester.assertLessEqual(average_time, acceptable_average_time) @@ -40,7 +49,7 @@ def size_name(number_players): class TestDefaultOptions(SVTestCase): - acceptable_time_per_player = 0.30 + acceptable_time_per_player = 0.12 options = default_options() def test_solo(self): @@ -49,6 +58,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players + # seed = 47965111899197590996 performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) def test_duo(self): @@ -77,7 +87,7 @@ def test_10_player(self): class TestMinLocationMaxItems(SVTestCase): - acceptable_time_per_player = 0.35 + acceptable_time_per_player = 0.25 options = minimal_locations_maximal_items() def test_solo(self): @@ -114,7 +124,7 @@ def test_10_player(self): class TestAllsanityWithoutMods(SVTestCase): - acceptable_time_per_player = 0.30 + acceptable_time_per_player = 0.18 options = allsanity_options_without_mods() def test_solo(self): From 50b283c4d5a76947cbbedde4b21f71fb1cff1ce7 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 16:54:46 +0200 Subject: [PATCH 005/482] - Improve friendsanity tests for performance --- worlds/stardew_valley/test/TestGeneration.py | 233 ++++++++----------- 1 file changed, 99 insertions(+), 134 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 46c6685ad536..b6bd68f7f008 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -238,11 +238,17 @@ def run_default_tests(self) -> bool: # None is default return False - def test_no_friendsanity_items(self): + def test_friendsanity_none(self): + with self.subTest("No Items"): + self.check_no_friendsanity_items() + with self.subTest("No Locations"): + self.check_no_friendsanity_locations() + + def check_no_friendsanity_items(self): for item in self.multiworld.itempool: self.assertFalse(item.name.endswith(" <3")) - def test_no_friendsanity_locations(self): + def check_no_friendsanity_locations(self): for location_name in get_real_location_names(self, self.multiworld): self.assertFalse(location_name.startswith("Friendsanity")) @@ -255,14 +261,20 @@ class TestFriendsanityBachelors(SVTestBase): bachelors = {"Harvey", "Elliott", "Sam", "Alex", "Shane", "Sebastian", "Emily", "Haley", "Leah", "Abigail", "Penny", "Maru"} - def test_friendsanity_only_bachelor_items(self): + def test_friendsanity_only_bachelors(self): + with self.subTest("Items are valid"): + self.check_only_bachelors_items() + with self.subTest("Locations are valid"): + self.check_only_bachelors_locations() + + def check_only_bachelors_items(self): suffix = " <3" for item in self.multiworld.itempool: if item.name.endswith(suffix): villager_name = item.name[:item.name.index(suffix)] self.assertIn(villager_name, self.bachelors) - def test_friendsanity_only_bachelor_locations(self): + def check_only_bachelors_locations(self): prefix = "Friendsanity: " suffix = " <3" for location_name in get_real_location_names(self, self.multiworld): @@ -283,14 +295,20 @@ class TestFriendsanityStartingNpcs(SVTestBase): } excluded_npcs = {"Leo", "Krobus", "Dwarf", "Sandy", "Kent"} - def test_friendsanity_only_starting_npcs_items(self): + def test_friendsanity_only_starting_npcs(self): + with self.subTest("Items are valid"): + self.check_only_starting_npcs_items() + with self.subTest("Locations are valid"): + self.check_only_starting_npcs_locations() + + def check_only_starting_npcs_items(self): suffix = " <3" for item in self.multiworld.itempool: if item.name.endswith(suffix): villager_name = item.name[:item.name.index(suffix)] self.assertNotIn(villager_name, self.excluded_npcs) - def test_friendsanity_only_starting_npcs_locations(self): + def check_only_starting_npcs_locations(self): prefix = "Friendsanity: " suffix = " <3" for location_name in get_real_location_names(self, self.multiworld): @@ -313,43 +331,70 @@ def test_friendsanity_only_starting_npcs_locations(self): class TestFriendsanityAllNpcs(SVTestBase): options = { options.Friendsanity.internal_name: options.Friendsanity.option_all, - options.FriendsanityHeartSize.internal_name: 1, + options.FriendsanityHeartSize.internal_name: 4, } - def test_friendsanity_all_items(self): + def test_friendsanity_all_npcs(self): + with self.subTest("Items are valid"): + self.check_items_are_valid() + with self.subTest("Correct number of items"): + self.check_correct_number_of_items() + with self.subTest("Locations are valid"): + self.check_locations_are_valid() + + def check_items_are_valid(self): suffix = " <3" for item in self.multiworld.itempool: if item.name.endswith(suffix): villager_name = item.name[:item.name.index(suffix)] self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet") - def test_friendsanity_all_locations(self): + def check_correct_number_of_items(self): + suffix = " <3" + item_names = [item.name for item in self.multiworld.itempool] + for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]: + heart_item_name = f"{villager_name}{suffix}" + number_heart_items = item_names.count(heart_item_name) + if all_villagers_by_name[villager_name].bachelor: + self.assertEqual(number_heart_items, 2) + else: + self.assertEqual(number_heart_items, 3) + self.assertEqual(item_names.count("Pet <3"), 2) + + def check_locations_are_valid(self): prefix = "Friendsanity: " suffix = " <3" for location_name in get_real_location_names(self, self.multiworld): - if location_name.startswith(prefix): - name_no_prefix = location_name[len(prefix):] - name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)] - parts = name_trimmed.split(" ") - name = parts[0] - hearts = parts[1] - self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet") - if name == "Pet": - self.assertLessEqual(int(hearts), 5) - elif all_villagers_by_name[name].bachelor: - self.assertLessEqual(int(hearts), 8) - else: - self.assertLessEqual(int(hearts), 10) + if not location_name.startswith(prefix): + continue + name_no_prefix = location_name[len(prefix):] + name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)] + parts = name_trimmed.split(" ") + name = parts[0] + hearts = int(parts[1]) + self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet") + if name == "Pet": + self.assertTrue(hearts == 4 or hearts == 5) + elif all_villagers_by_name[name].bachelor: + self.assertTrue(hearts == 4 or hearts == 8 or hearts == 12 or hearts == 14) + else: + self.assertTrue(hearts == 4 or hearts == 8 or hearts == 10) class TestFriendsanityAllNpcsExcludingGingerIsland(SVTestBase): options = { options.Friendsanity.internal_name: options.Friendsanity.option_all, - options.FriendsanityHeartSize.internal_name: 1, + options.FriendsanityHeartSize.internal_name: 4, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true } - def test_friendsanity_all_items(self): + def test_friendsanity_all_npcs_exclude_island(self): + with self.subTest("Items"): + self.check_items() + with self.subTest("Locations"): + self.check_locations() + + def check_items(self): suffix = " <3" for item in self.multiworld.itempool: if item.name.endswith(suffix): @@ -357,7 +402,7 @@ def test_friendsanity_all_items(self): self.assertNotEqual(villager_name, "Leo") self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet") - def test_friendsanity_all_locations(self): + def check_locations(self): prefix = "Friendsanity: " suffix = " <3" for location_name in get_real_location_names(self, self.multiworld): @@ -377,84 +422,28 @@ def test_friendsanity_all_locations(self): self.assertLessEqual(int(hearts), 10) -class TestFriendsanityAllNpcsWithMarriage(SVTestBase): +class TestFriendsanityHeartSize3(SVTestBase): options = { options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 1, + options.FriendsanityHeartSize.internal_name: 3, } - def test_friendsanity_all_with_marriage_items(self): + def test_friendsanity_all_npcs_with_marriage(self): + with self.subTest("Items are valid"): + self.check_items_are_valid() + with self.subTest("Correct number of items"): + self.check_correct_number_of_items() + with self.subTest("Locations are valid"): + self.check_locations_are_valid() + + def check_items_are_valid(self): suffix = " <3" for item in self.multiworld.itempool: if item.name.endswith(suffix): villager_name = item.name[:item.name.index(suffix)] self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet") - def test_friendsanity_all_with_marriage_locations(self): - prefix = "Friendsanity: " - suffix = " <3" - for location_name in get_real_location_names(self, self.multiworld): - if location_name.startswith(prefix): - name_no_prefix = location_name[len(prefix):] - name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)] - parts = name_trimmed.split(" ") - name = parts[0] - hearts = parts[1] - self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet") - if name == "Pet": - self.assertLessEqual(int(hearts), 5) - elif all_villagers_by_name[name].bachelor: - self.assertLessEqual(int(hearts), 14) - else: - self.assertLessEqual(int(hearts), 10) - - -""" # Assuming math is correct if we check 2 points -class TestFriendsanityAllNpcsWithMarriageHeartSize2(SVTestBase): - options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 2, - } - - def test_friendsanity_all_with_marriage_items(self): - suffix = " <3" - item_names = [item.name for item in self.multiworld.itempool] - for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]: - heart_item_name = f"{villager_name}{suffix}" - number_heart_items = item_names.count(heart_item_name) - if all_villagers_by_name[villager_name].bachelor: - self.assertEqual(number_heart_items, 7) - else: - self.assertEqual(number_heart_items, 5) - self.assertEqual(item_names.count("Pet <3"), 3) - - def test_friendsanity_all_with_marriage_locations(self): - prefix = "Friendsanity: " - suffix = " <3" - for location_name in get_real_location_names(self, self.multiworld): - if not location_name.startswith(prefix): - continue - name_no_prefix = location_name[len(prefix):] - name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)] - parts = name_trimmed.split(" ") - name = parts[0] - hearts = int(parts[1]) - self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet") - if name == "Pet": - self.assertTrue(hearts == 2 or hearts == 4 or hearts == 5) - elif all_villagers_by_name[name].bachelor: - self.assertTrue(hearts == 2 or hearts == 4 or hearts == 6 or hearts == 8 or hearts == 10 or hearts == 12 or hearts == 14) - else: - self.assertTrue(hearts == 2 or hearts == 4 or hearts == 6 or hearts == 8 or hearts == 10) - - -class TestFriendsanityAllNpcsWithMarriageHeartSize3(SVTestBase): - options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 3, - } - - def test_friendsanity_all_with_marriage_items(self): + def check_correct_number_of_items(self): suffix = " <3" item_names = [item.name for item in self.multiworld.itempool] for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]: @@ -466,7 +455,7 @@ def test_friendsanity_all_with_marriage_items(self): self.assertEqual(number_heart_items, 4) self.assertEqual(item_names.count("Pet <3"), 2) - def test_friendsanity_all_with_marriage_locations(self): + def check_locations_are_valid(self): prefix = "Friendsanity: " suffix = " <3" for location_name in get_real_location_names(self, self.multiworld): @@ -486,52 +475,28 @@ def test_friendsanity_all_with_marriage_locations(self): self.assertTrue(hearts == 3 or hearts == 6 or hearts == 9 or hearts == 10) -class TestFriendsanityAllNpcsWithMarriageHeartSize4(SVTestBase): +class TestFriendsanityHeartSize5(SVTestBase): options = { options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 4, + options.FriendsanityHeartSize.internal_name: 5, } - def test_friendsanity_all_with_marriage_items(self): - suffix = " <3" - item_names = [item.name for item in self.multiworld.itempool] - for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]: - heart_item_name = f"{villager_name}{suffix}" - number_heart_items = item_names.count(heart_item_name) - if all_villagers_by_name[villager_name].bachelor: - self.assertEqual(number_heart_items, 4) - else: - self.assertEqual(number_heart_items, 3) - self.assertEqual(item_names.count("Pet <3"), 2) + def test_friendsanity_all_npcs_with_marriage(self): + with self.subTest("Items are valid"): + self.check_items_are_valid() + with self.subTest("Correct number of items"): + self.check_correct_number_of_items() + with self.subTest("Locations are valid"): + self.check_locations_are_valid() - def test_friendsanity_all_with_marriage_locations(self): - prefix = "Friendsanity: " + def check_items_are_valid(self): suffix = " <3" - for location_name in get_real_location_names(self, self.multiworld): - if not location_name.startswith(prefix): - continue - name_no_prefix = location_name[len(prefix):] - name_trimmed = name_no_prefix[:name_no_prefix.index(suffix)] - parts = name_trimmed.split(" ") - name = parts[0] - hearts = int(parts[1]) - self.assertTrue(name in all_villagers_by_mod_by_name[ModNames.vanilla] or name == "Pet") - if name == "Pet": - self.assertTrue(hearts == 4 or hearts == 5) - elif all_villagers_by_name[name].bachelor: - self.assertTrue(hearts == 4 or hearts == 8 or hearts == 12 or hearts == 14) - else: - self.assertTrue(hearts == 4 or hearts == 8 or hearts == 10) -""" - - -class TestFriendsanityAllNpcsWithMarriageHeartSize5(SVTestBase): - options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 5, - } + for item in self.multiworld.itempool: + if item.name.endswith(suffix): + villager_name = item.name[:item.name.index(suffix)] + self.assertTrue(villager_name in all_villagers_by_mod_by_name[ModNames.vanilla] or villager_name == "Pet") - def test_friendsanity_all_with_marriage_items(self): + def check_correct_number_of_items(self): suffix = " <3" item_names = [item.name for item in self.multiworld.itempool] for villager_name in all_villagers_by_mod_by_name[ModNames.vanilla]: @@ -543,7 +508,7 @@ def test_friendsanity_all_with_marriage_items(self): self.assertEqual(number_heart_items, 2) self.assertEqual(item_names.count("Pet <3"), 1) - def test_friendsanity_all_with_marriage_locations(self): + def check_locations_are_valid(self): prefix = "Friendsanity: " suffix = " <3" for location_name in get_real_location_names(self, self.multiworld): From 2b70e7ff896fcb826f869fcd175dcdfee614d862 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 16:56:48 +0200 Subject: [PATCH 006/482] - Moved cached weapon rules to the generic cache system --- worlds/stardew_valley/logic.py | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index e11341d656a4..40851779ba26 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -100,11 +100,6 @@ class StardewLogic: festival_rules: Dict[str, StardewRule] = field(default_factory=dict) special_order_rules: Dict[str, StardewRule] = field(default_factory=dict) cached_rules: Dict[str, StardewRule] = field(default_factory=dict) - any_weapon_rule: StardewRule = None - decent_weapon_rule: StardewRule = None - good_weapon_rule: StardewRule = None - great_weapon_rule: StardewRule = None - galaxy_weapon_rule: StardewRule = None def __post_init__(self): self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) @@ -1283,29 +1278,34 @@ def has_island_transport(self) -> StardewRule: return self.received(Transportation.island_obelisk) | self.received(Transportation.boat_repair) def has_any_weapon(self) -> StardewRule: - if not self.any_weapon_rule: - self.any_weapon_rule = self.has_decent_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups) - return self.any_weapon_rule + key = "has_any_weapon" + if key not in self.cached_rules: + self.cached_rules[key] = self.has_decent_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups) + return self.cached_rules[key] def has_decent_weapon(self) -> StardewRule: - if not self.decent_weapon_rule: - self.decent_weapon_rule = self.has_good_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) - return self.decent_weapon_rule + key = "has_decent_weapon" + if key not in self.cached_rules: + self.cached_rules[key] = self.has_good_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) + return self.cached_rules[key] def has_good_weapon(self) -> StardewRule: - if not self.good_weapon_rule: - self.good_weapon_rule = self.has_great_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) - return self.good_weapon_rule + key = "has_good_weapon" + if key not in self.cached_rules: + self.cached_rules[key] = self.has_great_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) + return self.cached_rules[key] def has_great_weapon(self) -> StardewRule: - if not self.great_weapon_rule: - self.great_weapon_rule = self.has_galaxy_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) - return self.great_weapon_rule + key = "has_great_weapon" + if key not in self.cached_rules: + self.cached_rules[key] = self.has_galaxy_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) + return self.cached_rules[key] def has_galaxy_weapon(self) -> StardewRule: - if not self.galaxy_weapon_rule: - self.galaxy_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) - return self.galaxy_weapon_rule + key = "has_galaxy_weapon" + if key not in self.cached_rules: + self.cached_rules[key] = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) + return self.cached_rules[key] def has_year_two(self) -> StardewRule: return self.has_lived_months(4) From e84b65eb39f5aeba0cc00088e5c72cca24b5712f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 3 Nov 2023 17:19:27 +0200 Subject: [PATCH 007/482] - Add more caching --- worlds/stardew_valley/logic.py | 139 +++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 52 deletions(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index 40851779ba26..fc24c3cecae6 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -737,44 +737,61 @@ def can_complete_special_order(self, specialorder: str) -> StardewRule: return Has(specialorder, self.special_order_rules) def can_get_farming_xp(self) -> StardewRule: - crop_rules = [] - for crop in all_crops: - crop_rules.append(self.can_grow_crop(crop)) - return Or(crop_rules) + key = f"can_get_foraging_xp" + if key not in self.cached_rules: + crop_rules = [] + for crop in all_crops: + crop_rules.append(self.can_grow_crop(crop)) + self.cached_rules[key] = Or(crop_rules) + return self.cached_rules[key] def can_get_foraging_xp(self) -> StardewRule: - tool_rule = self.has_tool(Tool.axe) - tree_rule = self.can_reach_region(Region.forest) & self.has_any_season_not_winter() - stump_rule = self.can_reach_region(Region.secret_woods) & self.has_tool(Tool.axe, ToolMaterial.copper) - return tool_rule & (tree_rule | stump_rule) + key = f"can_get_foraging_xp" + if key not in self.cached_rules: + tool_rule = self.has_tool(Tool.axe) + tree_rule = self.can_reach_region(Region.forest) & self.has_any_season_not_winter() + self.cached_rules[key] = tool_rule & tree_rule + return self.cached_rules[key] def can_get_mining_xp(self) -> StardewRule: - tool_rule = self.has_tool(Tool.pickaxe) - stone_rule = self.can_reach_any_region([Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5]) - return tool_rule & stone_rule + key = f"can_get_mining_xp" + if key not in self.cached_rules: + tool_rule = self.has_tool(Tool.pickaxe) + stone_rule = self.can_reach_any_region([Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5]) + self.cached_rules[key] = tool_rule & stone_rule + return self.cached_rules[key] def can_get_combat_xp(self) -> StardewRule: - tool_rule = self.has_any_weapon() - enemy_rule = self.can_reach_any_region([Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5]) - return tool_rule & enemy_rule + key = f"can_get_combat_xp" + if key not in self.cached_rules: + tool_rule = self.has_any_weapon() + enemy_rule = self.can_reach_any_region([Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5]) + self.cached_rules[key] = tool_rule & enemy_rule + return self.cached_rules[key] def can_get_fishing_xp(self) -> StardewRule: - if self.options.skill_progression == SkillProgression.option_progressive: - return self.can_fish() | self.can_crab_pot() - - return self.can_fish() + key = f"can_get_fishing_xp" + if key not in self.cached_rules: + if self.options.skill_progression == SkillProgression.option_progressive: + self.cached_rules[key] = self.can_fish() | self.can_crab_pot() + else: + self.cached_rules[key] = self.can_fish() + return self.cached_rules[key] def can_fish(self, difficulty: int = 0) -> StardewRule: - skill_required = max(0, int((difficulty / 10) - 1)) - if difficulty <= 40: - skill_required = 0 - skill_rule = self.has_skill_level(Skill.fishing, skill_required) - region_rule = self.can_reach_any_region(fishing_regions) - number_fishing_rod_required = 1 if difficulty < 50 else 2 - if self.options.tool_progression == ToolProgression.option_progressive: - return self.received("Progressive Fishing Rod", number_fishing_rod_required) & skill_rule & region_rule - - return skill_rule & region_rule + key = f"can_fish {difficulty}" + if key not in self.cached_rules: + skill_required = max(0, int((difficulty / 10) - 1)) + if difficulty <= 40: + skill_required = 0 + skill_rule = self.has_skill_level(Skill.fishing, skill_required) + region_rule = self.can_reach_any_region(fishing_regions) + tool_rule = True_() + if self.options.tool_progression == ToolProgression.option_progressive: + number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) + tool_rule = self.received("Progressive Fishing Rod", number_fishing_rod_required) + self.cached_rules[key] = skill_rule & region_rule & tool_rule + return self.cached_rules[key] def can_fish_in_freshwater(self) -> StardewRule: return self.can_fish() & self.can_reach_any_region([Region.forest, Region.town, Region.mountain]) @@ -841,13 +858,16 @@ def has_island_farm(self) -> StardewRule: return self.can_reach_region(Region.island_south) def can_catch_fish(self, fish: FishItem) -> StardewRule: - region_rule = self.can_reach_any_region(fish.locations) - season_rule = self.has_any_season(fish.seasons) - if fish.difficulty == -1: - difficulty_rule = self.can_crab_pot() - else: - difficulty_rule = self.can_fish(fish.difficulty) - return region_rule & season_rule & difficulty_rule + key = f"can_catch_fish {fish.name}" + if key not in self.cached_rules: + region_rule = self.can_reach_any_region(fish.locations) + season_rule = self.has_any_season(fish.seasons) + if fish.difficulty == -1: + difficulty_rule = self.can_crab_pot() + else: + difficulty_rule = self.can_fish(fish.difficulty) + self.cached_rules[key] = region_rule & season_rule & difficulty_rule + return self.cached_rules[key] def can_catch_every_fish(self) -> StardewRule: rules = [self.has_skill_level(Skill.fishing, 10), self.has_max_fishing_rod()] @@ -1067,6 +1087,12 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule: return self.can_get_married() & self.has_house(2) & self.has_relationship(Generic.bachelor, 12) & self.has_children(number_children - 1) def has_relationship(self, npc: str, hearts: int = 1) -> StardewRule: + key = f"has_relationship {npc} {hearts}" + if key not in self.cached_rules: + self.cached_rules[key] = self._has_relationship(npc, hearts) + return self.cached_rules[key] + + def _has_relationship(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() friendsanity = self.options.friendsanity @@ -1121,31 +1147,38 @@ def received_hearts(self, npc: str, hearts: int) -> StardewRule: return self.cached_rules[key] def can_meet(self, npc: str) -> StardewRule: - if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): - return True_() - villager = all_villagers_by_name[npc] - rules = [self.can_reach_any_region(villager.locations)] - if npc == NPC.kent: - rules.append(self.has_year_two()) - elif npc == NPC.leo: - rules.append(self.received("Island West Turtle")) + key = f"can_meet {npc}" + if key not in self.cached_rules: + if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): + self.cached_rules[key] = True_() + return self.cached_rules[key] + villager = all_villagers_by_name[npc] + rules = [self.can_reach_any_region(villager.locations)] + if npc == NPC.kent: + rules.append(self.has_year_two()) + elif npc == NPC.leo: + rules.append(self.received("Island West Turtle")) - return And(rules) + self.cached_rules[key] = And(rules) + return self.cached_rules[key] def can_give_loved_gifts_to_everyone(self) -> StardewRule: rules = [] for npc in all_villagers_by_name: if not self.npc_is_in_current_slot(npc): continue - villager = all_villagers_by_name[npc] - gift_rule = self.has_any_universal_love() meet_rule = self.can_meet(npc) - rules.append(meet_rule & gift_rule) - loved_gifts_rules = And(rules) - simplified_rules = loved_gifts_rules.simplify() - return simplified_rules + rules.append(meet_rule) + loved_gifts_rules = And(rules) & self.has_any_universal_love() + return loved_gifts_rules def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: + key = f"can_meet {npc} {hearts}" + if key not in self.cached_rules: + self.cached_rules[key] = self._can_earn_relationship(npc, hearts) + return self.cached_rules[key] + + def _can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: if hearts <= 0: return True_() @@ -1458,8 +1491,10 @@ def can_win_fishing_competition(self) -> StardewRule: return self.can_fish(60) def has_any_universal_love(self) -> StardewRule: - return self.has(Gift.golden_pumpkin) | self.has("Magic Rock Candy") | self.has(Gift.pearl) | self.has( - "Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) + key = f"has_any_universal_love" + if key not in self.cached_rules: + self.cached_rules[key] = self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) + return self.cached_rules[key] def has_jelly(self) -> StardewRule: return self.can_preserves_jar(Fruit.any) From 2267893a991f40f5b8a093f389cce3db763cb685 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 4 Nov 2023 16:56:59 +0200 Subject: [PATCH 008/482] - Added caching to all rules with > 10 000 calls in the performance tests --- worlds/stardew_valley/data/recipe_data.py | 23 ++- worlds/stardew_valley/logic.py | 183 ++++++++++++++-------- 2 files changed, 140 insertions(+), 66 deletions(-) diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index dc1b490bf93c..029de15fdfda 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -15,11 +15,15 @@ class RecipeSource: - pass + + def __repr__(self): + return f"RecipeSource" class StarterSource(RecipeSource): - pass + + def __repr__(self): + return f"StarterSource" class QueenOfSauceSource(RecipeSource): @@ -32,6 +36,9 @@ def __init__(self, year: int, season: str, day: int): self.season = season self.day = day + def __repr__(self): + return f"QueenOfSauceSource at year {self.year} {self.season} {self.day}" + class FriendshipSource(RecipeSource): friend: str @@ -41,6 +48,9 @@ def __init__(self, friend: str, hearts: int): self.friend = friend self.hearts = hearts + def __repr__(self): + return f"FriendshipSource at {self.friend} {self.hearts} <3" + class SkillSource(RecipeSource): skill: str @@ -50,6 +60,9 @@ def __init__(self, skill: str, level: int): self.skill = skill self.level = level + def __repr__(self): + return f"SkillSource at level {self.level} {self.skill}" + class ShopSource(RecipeSource): region: str @@ -59,10 +72,16 @@ def __init__(self, region: str, price: int): self.region = region self.price = price + def __repr__(self): + return f"ShopSource at {self.region} costing {self.price}g" + class ShopTradeSource(ShopSource): currency: str + def __repr__(self): + return f"ShopTradeSource at {self.region} costing {self.price} {self.currency}" + class CookingRecipe: meal: str diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index fc24c3cecae6..7ffc31c72f23 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -586,8 +586,11 @@ def can_reach_any_region(self, spots: Iterable[str]) -> StardewRule: self.cached_rules[key] = Or(self.can_reach_region(spot) for spot in spots) return self.cached_rules[key] - def can_reach_all_regions(self, spots: Iterable[str]) -> StardewRule: - return And(self.can_reach_region(spot) for spot in spots) + def can_reach_all_regions(self, spots: List[str]) -> StardewRule: + key = f"can_reach_all_regions {spots}" + if key not in self.cached_rules: + self.cached_rules[key] = And(self.can_reach_region(spot) for spot in spots) + return self.cached_rules[key] def can_reach_location(self, spot: str) -> StardewRule: return Reach(spot, "Location", self.player) @@ -608,7 +611,10 @@ def can_spend_money(self, amount: int) -> StardewRule: return self.cached_rules[key] def can_spend_money_at(self, region: str, amount: int) -> StardewRule: - return self.can_reach_region(region) & self.can_spend_money(amount) + key = f"can_spend_money_at {region} {amount}" + if key not in self.cached_rules: + self.cached_rules[key] = self.can_reach_region(region) & self.can_spend_money(amount) + return self.cached_rules[key] def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: key = f"has_tool {tool} {material}" @@ -712,6 +718,12 @@ def has_building(self, building: str) -> StardewRule: return Has(building, self.building_rules) & carpenter_rule def has_house(self, upgrade_level: int) -> StardewRule: + key = f"has_house {upgrade_level}" + if key not in self.cached_rules: + self.cached_rules[key] = self._has_house(upgrade_level) + return self.cached_rules[key] + + def _has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level < 1: return True_() @@ -805,18 +817,21 @@ def can_fish_chests(self) -> StardewRule: return self.has_max_fishing_rod() & skill_rule def can_buy_seed(self, seed: SeedItem) -> StardewRule: - if self.options.cropsanity == Cropsanity.option_disabled: - item_rule = True_() - else: - item_rule = self.received(seed.name) - season_rule = self.has_any_season(seed.seasons) - region_rule = self.can_reach_all_regions(seed.regions) - currency_rule = self.can_spend_money(1000) - if seed.name == Seed.pineapple: - currency_rule = self.has(Forageable.magma_cap) - if seed.name == Seed.taro: - currency_rule = self.has(Fossil.bone_fragment) - return season_rule & region_rule & item_rule & currency_rule + key = f"can_buy_seed {seed.name}" + if key not in self.cached_rules: + if self.options.cropsanity == Cropsanity.option_disabled: + item_rule = True_() + else: + item_rule = self.received(seed.name) + season_rule = self.has_any_season(seed.seasons) + region_rule = self.can_reach_all_regions(seed.regions) + currency_rule = self.can_spend_money(1000) + if seed.name == Seed.pineapple: + currency_rule = self.has(Forageable.magma_cap) + if seed.name == Seed.taro: + currency_rule = self.has(Fossil.bone_fragment) + self.cached_rules[key] = season_rule & region_rule & item_rule & currency_rule + return self.cached_rules[key] def can_buy_sapling(self, fruit: str) -> StardewRule: sapling_prices = {Fruit.apple: 4000, Fruit.apricot: 2000, Fruit.cherry: 3400, Fruit.orange: 4000, @@ -884,17 +899,30 @@ def has_max_fishing_rod(self) -> StardewRule: return self.can_get_fishing_xp() def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: - cook_rule = self.has_house(1) | self.has_skill_level(Skill.foraging, 9) if recipe is None: - return cook_rule + key = f"can_cook" + else: + key = f"can_cook {recipe.meal} {type(recipe.source)}" + if key not in self.cached_rules: + cook_rule = self.has_house(1) | self.has_skill_level(Skill.foraging, 9) + if recipe is None: + self.cached_rules[key] = cook_rule + return self.cached_rules[key] - learn_rule = self.can_learn_recipe(recipe.source) - ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) - number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) - time_rule = self.has_lived_months(number_ingredients) - return cook_rule & learn_rule & ingredients_rule & time_rule + learn_rule = self.can_learn_recipe(recipe.source) + ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) + number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) + time_rule = self.has_lived_months(number_ingredients) + self.cached_rules[key] = cook_rule & learn_rule & ingredients_rule & time_rule + return self.cached_rules[key] def can_learn_recipe(self, source: RecipeSource) -> StardewRule: + key = f"can_learn_recipe {source}" + if key not in self.cached_rules: + self.cached_rules[key] = self._can_learn_recipe(source) + return self.cached_rules[key] + + def _can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() if isinstance(source, ShopSource): @@ -922,17 +950,20 @@ def can_do_panning(self, item: str = Generic.any) -> StardewRule: return self.received("Glittering Boulder Removed") def can_crab_pot(self, region: str = Generic.any) -> StardewRule: - crab_pot_rule = self.has(Craftable.bait) - if self.options.skill_progression == SkillProgression.option_progressive: - crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) - else: - crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp() - - if region != Generic.any: - return crab_pot_rule & self.can_reach_region(region) + key = f"can_crab_pot {region}" + if key not in self.cached_rules: + crab_pot_rule = self.has(Craftable.bait) + if self.options.skill_progression == SkillProgression.option_progressive: + crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) + else: + crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp() - water_region_rules = self.can_reach_any_region(fishing_regions) - return crab_pot_rule & water_region_rules + if region != Generic.any: + self.cached_rules[key] = crab_pot_rule & self.can_reach_region(region) + else: + water_region_rules = self.can_reach_any_region(fishing_regions) + self.cached_rules[key] = crab_pot_rule & water_region_rules + return self.cached_rules[key] # Regions def can_mine_in_the_mines_floor_1_40(self) -> StardewRule: @@ -988,16 +1019,19 @@ def get_weapon_rule_for_floor_tier(self, tier: int): return self.can_do_combat_at_level(Performance.basic) def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: - tier = int(floor / 40) - rules = [] - weapon_rule = self.get_weapon_rule_for_floor_tier(tier) - rules.append(weapon_rule) - if self.options.tool_progression == ToolProgression.option_progressive: - rules.append(self.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) - if self.options.skill_progression == SkillProgression.option_progressive: - combat_tier = min(10, max(0, tier * 2)) - rules.append(self.has_skill_level(Skill.combat, combat_tier)) - return And(rules) + key = f"can_progress_in_the_mines_from_floor {floor}" + if key not in self.cached_rules: + tier = int(floor / 40) + rules = [] + weapon_rule = self.get_weapon_rule_for_floor_tier(tier) + rules.append(weapon_rule) + if self.options.tool_progression == ToolProgression.option_progressive: + rules.append(self.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) + if self.options.skill_progression == SkillProgression.option_progressive: + combat_tier = min(10, max(0, tier * 2)) + rules.append(self.has_skill_level(Skill.combat, combat_tier)) + self.cached_rules[key] = And(rules) + return self.cached_rules[key] def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule: tier = int(floor / 40) + 1 @@ -1012,9 +1046,15 @@ def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule return And(rules) def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: - if self.options.elevator_progression != ElevatorProgression.option_vanilla: - return self.received("Progressive Mine Elevator", count=int(floor / 5)) - return True_() + key = f"has_mine_elevator_to_floor {floor}" + if key not in self.cached_rules: + if self.options.elevator_progression != ElevatorProgression.option_vanilla: + self.cached_rules[key] = self.received("Progressive Mine Elevator", count=int(floor / 5)) + else: + self.cached_rules[key] = True_() + return self.cached_rules[key] + + def can_mine_to_floor(self, floor: int) -> StardewRule: previous_elevator = max(floor - 5, 0) @@ -1350,7 +1390,10 @@ def can_speak_dwarf(self) -> StardewRule: return self.received("Dwarvish Translation Guide") def can_donate_museum_item(self, item: MuseumItem) -> StardewRule: - return self.can_reach_region(Region.museum) & self.can_find_museum_item(item) + key = f"can_donate_museum_item {item.name}" + if key not in self.cached_rules: + self.cached_rules[key] = self.can_reach_region(Region.museum) & self.can_find_museum_item(item) + return self.cached_rules[key] def can_donate_museum_items(self, number: int) -> StardewRule: return self.can_reach_region(Region.museum) & self.can_find_museum_items(number) @@ -1661,11 +1704,15 @@ def heart(self, npc: Union[str, Villager]) -> str: return self.heart(npc.name) def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: - season_rule = self.has_season(season) - region_rule = self.can_reach_region(region) - if need_hoe: - return season_rule & region_rule & self.has_tool(Tool.hoe) - return season_rule & region_rule + key = f"can_forage {season} {region} {need_hoe}" + if key not in self.cached_rules: + season_rule = self.has_season(season) + region_rule = self.can_reach_region(region) + if need_hoe: + self.cached_rules[key] = season_rule & region_rule & self.has_tool(Tool.hoe) + else: + self.cached_rules[key] = season_rule & region_rule + return self.cached_rules[key] def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] @@ -1673,21 +1720,29 @@ def npc_is_in_current_slot(self, name: str) -> bool: return mod is None or mod in self.options.mods def can_do_combat_at_level(self, level: str) -> StardewRule: - if level == Performance.basic: - return self.has_any_weapon() | magic.has_any_spell(self) - if level == Performance.decent: - return self.has_decent_weapon() | magic.has_decent_spells(self) - if level == Performance.good: - return self.has_good_weapon() | magic.has_good_spells(self) - if level == Performance.great: - return self.has_great_weapon() | magic.has_great_spells(self) - if level == Performance.galaxy: - return self.has_galaxy_weapon() | magic.has_amazing_spells(self) + key = f"can_do_combat_at_level {level}" + if key not in self.cached_rules: + if level == Performance.basic: + self.cached_rules[key] = self.has_any_weapon() | magic.has_any_spell(self) + elif level == Performance.decent: + self.cached_rules[key] = self.has_decent_weapon() | magic.has_decent_spells(self) + elif level == Performance.good: + self.cached_rules[key] = self.has_good_weapon() | magic.has_good_spells(self) + elif level == Performance.great: + self.cached_rules[key] = self.has_great_weapon() | magic.has_great_spells(self) + elif level == Performance.galaxy: + self.cached_rules[key] = self.has_galaxy_weapon() | magic.has_amazing_spells(self) + else: + self.cached_rules[key] = False_() + return self.cached_rules[key] def can_water(self, level: int) -> StardewRule: - tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) - spell_rule = (self.received(MagicSpell.water) & magic.can_use_altar(self) & self.has_skill_level(ModSkill.magic, level)) - return tool_rule | spell_rule + key = f"can_water {level}" + if key not in self.cached_rules: + tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) + spell_rule = (self.received(MagicSpell.water) & magic.can_use_altar(self) & self.has_skill_level(ModSkill.magic, level)) + self.cached_rules[key] = tool_rule | spell_rule + return self.cached_rules[key] def has_prismatic_jelly_reward_access(self) -> StardewRule: if self.options.special_order_locations == SpecialOrderLocations.option_disabled: From 4e48971f8cdfa5fee3fecfdd11a02f41dcb8f398 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 4 Nov 2023 18:26:32 +0200 Subject: [PATCH 009/482] - add cache to has and received --- worlds/stardew_valley/logic.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index 7ffc31c72f23..82105145cce9 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -544,6 +544,14 @@ def __post_init__(self): self.special_order_rules.update(get_modded_special_orders_rules(self, self.options.mods)) def has(self, items: Union[str, (Iterable[str], Sized)], count: Optional[int] = None) -> StardewRule: + if not isinstance(items, str): + items = list(items) + key = f"has {items} {count}" + if key not in self.cached_rules: + self.cached_rules[key] = self._has(items, count) + return self.cached_rules[key] + + def _has(self, items: Union[str, (Iterable[str], Sized)], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): return Has(items, self.item_rules) @@ -559,6 +567,14 @@ def has(self, items: Union[str, (Iterable[str], Sized)], count: Optional[int] = return Count(count, (self.has(item) for item in items)) def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: + if not isinstance(items, str): + items = list(items) + key = f"received {items} {count}" + if key not in self.cached_rules: + self.cached_rules[key] = self._received(items, count) + return self.cached_rules[key] + + def _received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: if count <= 0 or not items: return True_() @@ -593,13 +609,22 @@ def can_reach_all_regions(self, spots: List[str]) -> StardewRule: return self.cached_rules[key] def can_reach_location(self, spot: str) -> StardewRule: - return Reach(spot, "Location", self.player) + key = f"can_reach_location {spot}" + if key not in self.cached_rules: + self.cached_rules[key] = Reach(spot, "Location", self.player) + return self.cached_rules[key] def can_reach_entrance(self, spot: str) -> StardewRule: - return Reach(spot, "Entrance", self.player) + key = f"can_reach_entrance {spot}" + if key not in self.cached_rules: + self.cached_rules[key] = Reach(spot, "Entrance", self.player) + return self.cached_rules[key] def can_have_earned_total_money(self, amount: int) -> StardewRule: - return self.has_lived_months(min(8, amount // MONEY_PER_MONTH)) + key = f"can_have_earned_total_money {amount}" + if key not in self.cached_rules: + self.cached_rules[key] = self.has_lived_months(min(8, amount // MONEY_PER_MONTH)) + return self.cached_rules[key] def can_spend_money(self, amount: int) -> StardewRule: key = f"can_spend_money {amount}" From 14364c352cc5d4db0dd765875c6646ead776291d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 08:28:19 +0200 Subject: [PATCH 010/482] - Fix farming xp cache key --- worlds/stardew_valley/logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index 82105145cce9..34a17258dbb6 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -774,7 +774,7 @@ def can_complete_special_order(self, specialorder: str) -> StardewRule: return Has(specialorder, self.special_order_rules) def can_get_farming_xp(self) -> StardewRule: - key = f"can_get_foraging_xp" + key = f"can_get_farming_xp" if key not in self.cached_rules: crop_rules = [] for crop in all_crops: From 65206d024c9666c21bcc4435090dc172e9bd3777 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 7 Nov 2023 22:42:13 +0200 Subject: [PATCH 011/482] - Improve some location placement in regions --- worlds/stardew_valley/data/locations.csv | 140 +++++++++--------- worlds/stardew_valley/logic.py | 9 +- worlds/stardew_valley/regions.py | 96 ++++++------ worlds/stardew_valley/rules.py | 79 ++++++---- .../stardew_valley/strings/entrance_names.py | 6 + worlds/stardew_valley/strings/region_names.py | 6 + 6 files changed, 188 insertions(+), 148 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index ef56bf5a12ba..13991e84cdba 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -38,26 +38,26 @@ id,region,name,tags,mod_name 37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", 101,Pierre's General Store,Large Pack,BACKPACK, 102,Pierre's General Store,Deluxe Pack,BACKPACK, -103,Clint's Blacksmith,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -104,Clint's Blacksmith,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -105,Clint's Blacksmith,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -106,Clint's Blacksmith,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -107,Clint's Blacksmith,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -108,Clint's Blacksmith,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -109,Clint's Blacksmith,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -110,Clint's Blacksmith,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -111,Clint's Blacksmith,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -112,Clint's Blacksmith,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -113,Clint's Blacksmith,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -114,Clint's Blacksmith,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -115,Clint's Blacksmith,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -116,Clint's Blacksmith,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -117,Clint's Blacksmith,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -118,Clint's Blacksmith,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -119,Clint's Blacksmith,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -120,Clint's Blacksmith,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -121,Clint's Blacksmith,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -122,Clint's Blacksmith,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", 123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", 124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", 125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", @@ -100,56 +100,56 @@ id,region,name,tags,mod_name 236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, 237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, 251,Volcano - Floor 10,Volcano Caldera Treasure,"MANDATORY,GINGER_ISLAND", -301,Stardew Valley,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", -302,Stardew Valley,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", -303,Stardew Valley,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", -304,Stardew Valley,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", -305,Stardew Valley,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", -306,Stardew Valley,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", -307,Stardew Valley,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", -308,Stardew Valley,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", -309,Stardew Valley,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", -310,Stardew Valley,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", -311,Stardew Valley,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -312,Stardew Valley,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -313,Stardew Valley,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -314,Stardew Valley,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -315,Stardew Valley,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -316,Stardew Valley,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -317,Stardew Valley,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -318,Stardew Valley,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -319,Stardew Valley,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -320,Stardew Valley,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -321,Stardew Valley,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -322,Stardew Valley,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -323,Stardew Valley,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -324,Stardew Valley,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -325,Stardew Valley,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -326,Stardew Valley,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -327,Stardew Valley,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -328,Stardew Valley,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -329,Stardew Valley,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -330,Stardew Valley,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -331,Stardew Valley,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", -332,Stardew Valley,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", -333,Stardew Valley,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", -334,Stardew Valley,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", -335,Stardew Valley,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", -336,Stardew Valley,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", -337,Stardew Valley,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", -338,Stardew Valley,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", -339,Stardew Valley,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", -340,Stardew Valley,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", -341,Stardew Valley,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -342,Stardew Valley,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -343,Stardew Valley,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -344,Stardew Valley,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -345,Stardew Valley,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -346,Stardew Valley,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -347,Stardew Valley,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -348,Stardew Valley,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -349,Stardew Valley,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -350,Stardew Valley,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", +302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", +303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", +304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", +305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", +306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", +307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", +308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", +309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", +310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", +311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", +332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", +333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", +334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", +335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", +336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", +337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", +338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", +339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", +340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", +341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", 401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, 402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, 403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index 34a17258dbb6..af6017e55f06 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -1059,20 +1059,23 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: return self.cached_rules[key] def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule: - tier = int(floor / 40) + 1 + tier = (floor // 40) + 1 rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) if self.options.tool_progression == ToolProgression.option_progressive: rules.append(self.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) if self.options.skill_progression == SkillProgression.option_progressive: - combat_tier = min(10, max(0, tier * 2)) - rules.append(self.has_skill_level(Skill.combat, combat_tier)) + skill_tier = min(10, max(0, tier * 2)) + rules.append(self.has_skill_level(Skill.mining, skill_tier)) + rules.append(self.has_skill_level(Skill.combat, skill_tier)) return And(rules) def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: key = f"has_mine_elevator_to_floor {floor}" if key not in self.cached_rules: + if floor <= 0: + floor = 0 if self.options.elevator_progression != ElevatorProgression.option_vanilla: self.cached_rules[key] = self.received("Progressive Mine Elevator", count=int(floor / 5)) else: diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index d8e224841143..b8998fa1a157 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -22,7 +22,8 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.farm, [Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse, - Entrance.use_desert_obelisk, Entrance.use_island_obelisk]), + Entrance.use_desert_obelisk, Entrance.use_island_obelisk, Entrance.farming]), + RegionData(Region.farming), RegionData(Region.backwoods, [Entrance.backwoods_to_mountain]), RegionData(Region.bus_stop, [Entrance.bus_stop_to_town, Entrance.take_bus_to_desert, Entrance.bus_stop_to_tunnel_entrance]), @@ -53,7 +54,8 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: Entrance.town_to_museum, Entrance.town_to_jojamart]), RegionData(Region.beach, - [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools]), + [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, Entrance.fishing]), + RegionData(Region.fishing), RegionData(Region.railroad, [Entrance.enter_bathhouse_entrance, Entrance.enter_witch_warp_cave]), RegionData(Region.ranch), RegionData(Region.leah_house), @@ -84,7 +86,11 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.mayor_house), RegionData(Region.sam_house), RegionData(Region.haley_house), - RegionData(Region.blacksmith), + RegionData(Region.blacksmith, [Entrance.blacksmith_copper]), + RegionData(Region.blacksmith_copper, [Entrance.blacksmith_iron]), + RegionData(Region.blacksmith_iron, [Entrance.blacksmith_gold]), + RegionData(Region.blacksmith_gold, [Entrance.blacksmith_iridium]), + RegionData(Region.blacksmith_iridium), RegionData(Region.museum), RegionData(Region.jojamart), RegionData(Region.fish_shop, [Entrance.fish_shop_to_boat_tunnel]), @@ -105,17 +111,14 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.oasis, [Entrance.enter_casino]), RegionData(Region.casino), RegionData(Region.skull_cavern_entrance, [Entrance.enter_skull_cavern]), - RegionData(Region.skull_cavern, [Entrance.mine_to_skull_cavern_floor_25, Entrance.mine_to_skull_cavern_floor_50, - Entrance.mine_to_skull_cavern_floor_75, Entrance.mine_to_skull_cavern_floor_100, - Entrance.mine_to_skull_cavern_floor_125, Entrance.mine_to_skull_cavern_floor_150, - Entrance.mine_to_skull_cavern_floor_175, Entrance.mine_to_skull_cavern_floor_200]), - RegionData(Region.skull_cavern_25), - RegionData(Region.skull_cavern_50), - RegionData(Region.skull_cavern_75), - RegionData(Region.skull_cavern_100), - RegionData(Region.skull_cavern_125), - RegionData(Region.skull_cavern_150), - RegionData(Region.skull_cavern_175), + RegionData(Region.skull_cavern, [Entrance.mine_to_skull_cavern_floor_25]), + RegionData(Region.skull_cavern_25, [Entrance.mine_to_skull_cavern_floor_50]), + RegionData(Region.skull_cavern_50, [Entrance.mine_to_skull_cavern_floor_75]), + RegionData(Region.skull_cavern_75, [Entrance.mine_to_skull_cavern_floor_100]), + RegionData(Region.skull_cavern_100, [Entrance.mine_to_skull_cavern_floor_125]), + RegionData(Region.skull_cavern_125, [Entrance.mine_to_skull_cavern_floor_150]), + RegionData(Region.skull_cavern_150, [Entrance.mine_to_skull_cavern_floor_175]), + RegionData(Region.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200]), RegionData(Region.skull_cavern_200), RegionData(Region.island_south, [Entrance.island_south_to_west, Entrance.island_south_to_north, Entrance.island_south_to_east, Entrance.island_south_to_southeast, @@ -163,42 +166,31 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.junimo_kart_2, [Entrance.reach_junimo_kart_3]), RegionData(Region.junimo_kart_3), RegionData(Region.mines, [Entrance.talk_to_mines_dwarf, - Entrance.dig_to_mines_floor_5, Entrance.dig_to_mines_floor_10, - Entrance.dig_to_mines_floor_15, Entrance.dig_to_mines_floor_20, - Entrance.dig_to_mines_floor_25, Entrance.dig_to_mines_floor_30, - Entrance.dig_to_mines_floor_35, Entrance.dig_to_mines_floor_40, - Entrance.dig_to_mines_floor_45, Entrance.dig_to_mines_floor_50, - Entrance.dig_to_mines_floor_55, Entrance.dig_to_mines_floor_60, - Entrance.dig_to_mines_floor_65, Entrance.dig_to_mines_floor_70, - Entrance.dig_to_mines_floor_75, Entrance.dig_to_mines_floor_80, - Entrance.dig_to_mines_floor_85, Entrance.dig_to_mines_floor_90, - Entrance.dig_to_mines_floor_95, Entrance.dig_to_mines_floor_100, - Entrance.dig_to_mines_floor_105, Entrance.dig_to_mines_floor_110, - Entrance.dig_to_mines_floor_115, Entrance.dig_to_mines_floor_120]), + Entrance.dig_to_mines_floor_5]), RegionData(Region.mines_dwarf_shop), - RegionData(Region.mines_floor_5), - RegionData(Region.mines_floor_10), - RegionData(Region.mines_floor_15), - RegionData(Region.mines_floor_20), - RegionData(Region.mines_floor_25), - RegionData(Region.mines_floor_30), - RegionData(Region.mines_floor_35), - RegionData(Region.mines_floor_40), - RegionData(Region.mines_floor_45), - RegionData(Region.mines_floor_50), - RegionData(Region.mines_floor_55), - RegionData(Region.mines_floor_60), - RegionData(Region.mines_floor_65), - RegionData(Region.mines_floor_70), - RegionData(Region.mines_floor_75), - RegionData(Region.mines_floor_80), - RegionData(Region.mines_floor_85), - RegionData(Region.mines_floor_90), - RegionData(Region.mines_floor_95), - RegionData(Region.mines_floor_100), - RegionData(Region.mines_floor_105), - RegionData(Region.mines_floor_110), - RegionData(Region.mines_floor_115), + RegionData(Region.mines_floor_5, [Entrance.dig_to_mines_floor_10]), + RegionData(Region.mines_floor_10, [Entrance.dig_to_mines_floor_15]), + RegionData(Region.mines_floor_15, [Entrance.dig_to_mines_floor_20]), + RegionData(Region.mines_floor_20, [Entrance.dig_to_mines_floor_25]), + RegionData(Region.mines_floor_25, [Entrance.dig_to_mines_floor_30]), + RegionData(Region.mines_floor_30, [Entrance.dig_to_mines_floor_35]), + RegionData(Region.mines_floor_35, [Entrance.dig_to_mines_floor_40]), + RegionData(Region.mines_floor_40, [Entrance.dig_to_mines_floor_45]), + RegionData(Region.mines_floor_45, [Entrance.dig_to_mines_floor_50]), + RegionData(Region.mines_floor_50, [Entrance.dig_to_mines_floor_55]), + RegionData(Region.mines_floor_55, [Entrance.dig_to_mines_floor_60]), + RegionData(Region.mines_floor_60, [Entrance.dig_to_mines_floor_65]), + RegionData(Region.mines_floor_65, [Entrance.dig_to_mines_floor_70]), + RegionData(Region.mines_floor_70, [Entrance.dig_to_mines_floor_75]), + RegionData(Region.mines_floor_75, [Entrance.dig_to_mines_floor_80]), + RegionData(Region.mines_floor_80, [Entrance.dig_to_mines_floor_85]), + RegionData(Region.mines_floor_85, [Entrance.dig_to_mines_floor_90]), + RegionData(Region.mines_floor_90, [Entrance.dig_to_mines_floor_95]), + RegionData(Region.mines_floor_95, [Entrance.dig_to_mines_floor_100]), + RegionData(Region.mines_floor_100, [Entrance.dig_to_mines_floor_105]), + RegionData(Region.mines_floor_105, [Entrance.dig_to_mines_floor_110]), + RegionData(Region.mines_floor_110, [Entrance.dig_to_mines_floor_115]), + RegionData(Region.mines_floor_115, [Entrance.dig_to_mines_floor_120]), RegionData(Region.mines_floor_120), ] @@ -212,6 +204,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.farm_to_bus_stop, Region.bus_stop), ConnectionData(Entrance.farm_to_forest, Region.forest), ConnectionData(Entrance.farm_to_farmcave, Region.farm_cave, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(Entrance.farming, Region.farming), ConnectionData(Entrance.enter_greenhouse, Region.greenhouse), ConnectionData(Entrance.use_desert_obelisk, Region.desert), ConnectionData(Entrance.use_island_obelisk, Region.island_south), @@ -267,6 +260,10 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.enter_sunroom, Region.sunroom, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.town_to_clint_blacksmith, Region.blacksmith, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(Entrance.blacksmith_copper, Region.blacksmith_copper), + ConnectionData(Entrance.blacksmith_iron, Region.blacksmith_iron), + ConnectionData(Entrance.blacksmith_gold, Region.blacksmith_gold), + ConnectionData(Entrance.blacksmith_iridium, Region.blacksmith_iridium), ConnectionData(Entrance.town_to_saloon, Region.saloon, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.play_journey_of_the_prairie_king, Region.jotpk_world_1), @@ -298,6 +295,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.boat_to_ginger_island, Region.island_south), ConnectionData(Entrance.enter_tide_pools, Region.tide_pools), + ConnectionData(Entrance.fishing, Region.fishing), ConnectionData(Entrance.mountain_to_the_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.talk_to_mines_dwarf, Region.mines_dwarf_shop), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 88aa13f31471..97c49cde105a 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -40,24 +40,7 @@ def set_rules(world): set_ginger_island_rules(logic, multiworld, player, world_options) - # Those checks do not exist if ToolProgression is vanilla - if world_options.tool_progression != ToolProgression.option_vanilla: - MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), - (logic.has_skill_level(Skill.fishing, 2) & logic.can_spend_money(1800)).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Purchase Iridium Rod", player), - (logic.has_skill_level(Skill.fishing, 6) & logic.can_spend_money(7500)).simplify()) - - materials = [None, "Copper", "Iron", "Gold", "Iridium"] - tool = [Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.watering_can, Tool.trash_can] - for (previous, material), tool in itertools.product(zip(materials[:4], materials[1:]), tool): - if previous is None: - MultiWorldRules.add_rule(multiworld.get_location(f"{material} {tool} Upgrade", player), - (logic.has(f"{material} Ore") & - logic.can_spend_money(tool_upgrade_prices[material])).simplify()) - else: - MultiWorldRules.add_rule(multiworld.get_location(f"{material} {tool} Upgrade", player), - (logic.has(f"{material} Ore") & logic.has_tool(tool, previous) & - logic.can_spend_money(tool_upgrade_prices[material])).simplify()) + set_tools_rules(logic, multiworld, player, world_options) set_skills_rules(logic, multiworld, player, world_options) @@ -120,6 +103,25 @@ def set_rules(world): set_magic_spell_rules(logic, multiworld, player, world_options) +def set_tools_rules(logic, multiworld, player, world_options): + # Those checks do not exist if ToolProgression is vanilla + if world_options.tool_progression == ToolProgression.option_vanilla: + return + + MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), + (logic.has_skill_level(Skill.fishing, 2) & logic.can_spend_money(1800)).simplify()) + MultiWorldRules.add_rule(multiworld.get_location("Purchase Iridium Rod", player), + (logic.has_skill_level(Skill.fishing, 6) & logic.can_spend_money(7500)).simplify()) + + materials = [None, "Copper", "Iron", "Gold", "Iridium"] + tool = [Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.trash_can] + for (previous, material), tool in itertools.product(zip(materials[:4], materials[1:]), tool): + if previous is None: + continue + tool_upgrade_location = multiworld.get_location(f"{material} {tool} Upgrade", player) + MultiWorldRules.add_rule(tool_upgrade_location, logic.has_tool(tool, previous).simplify()) + + def set_skills_rules(logic, multiworld, player, world_options): # Skills if world_options.skill_progression != SkillProgression.option_vanilla: @@ -153,9 +155,10 @@ def set_skill_rule(logic, multiworld, player, skill: str, level: int): def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): - for floor in range(5, 120 + 5, 5): - MultiWorldRules.set_rule(multiworld.get_entrance(dig_to_mines_floor(floor), player), - logic.can_mine_to_floor(floor).simplify()) + set_mines_floor_entrance_rules(logic, multiworld, player) + set_skull_cavern_floor_entrance_rules(logic, multiworld, player) + set_blacksmith_entrance_rules(logic, multiworld, player) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), logic.received("Beach Bridge") | (magic.can_blink(logic)).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), @@ -170,11 +173,6 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp logic.received("Bus Repair").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_skull_cavern, player), logic.received(Wallet.skull_key).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), - logic.received("Club Card").simplify()) - for floor in range(25, 200 + 25, 25): - MultiWorldRules.set_rule(multiworld.get_entrance(dig_to_skull_floor(floor), player), - logic.can_mine_to_skull_cavern_floor(floor).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), logic.can_speak_dwarf() & logic.has_tool(Tool.pickaxe, ToolMaterial.iron)) @@ -221,6 +219,35 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp (logic.has_relationship(ModNPC.alec, 2) | magic.can_blink(logic)).simplify()) +def set_mines_floor_entrance_rules(logic, multiworld, player): + for floor in range(5, 120 + 5, 5): + rule = logic.has_mine_elevator_to_floor(floor - 10) + if floor == 5 or floor == 45 or floor == 85: + rule = rule & logic.can_progress_easily_in_the_mines_from_floor(floor) + entrance = multiworld.get_entrance(dig_to_mines_floor(floor), player) + MultiWorldRules.set_rule(entrance, rule.simplify()) + + + +def set_skull_cavern_floor_entrance_rules(logic, multiworld, player): + for floor in range(25, 200 + 25, 25): + MultiWorldRules.set_rule(multiworld.get_entrance(dig_to_skull_floor(floor), player), + logic.can_mine_to_skull_cavern_floor(floor).simplify()) + + +def set_blacksmith_entrance_rules(logic, multiworld, player): + set_blacksmith_upgrade_rule(logic, multiworld, player, Entrance.blacksmith_copper, MetalBar.copper, ToolMaterial.copper) + set_blacksmith_upgrade_rule(logic, multiworld, player, Entrance.blacksmith_iron, MetalBar.iron, ToolMaterial.iron) + set_blacksmith_upgrade_rule(logic, multiworld, player, Entrance.blacksmith_gold, MetalBar.gold, ToolMaterial.gold) + set_blacksmith_upgrade_rule(logic, multiworld, player, Entrance.blacksmith_iridium, MetalBar.iridium, ToolMaterial.iridium) + + +def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, item_name: str, tool_material: str): + material_entrance = multiworld.get_entrance(entrance_name, player) + upgrade_rule = logic.has(item_name) & logic.can_spend_money(tool_upgrade_prices[tool_material]) + MultiWorldRules.set_rule(material_entrance, upgrade_rule.simplify()) + + def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): set_island_entrances_rules(logic, multiworld, player) if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index e744400cfbd5..6e588512aa0c 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -161,6 +161,12 @@ class Entrance: parrot_express_jungle_to_docks = "Parrot Express Jungle to Docks" parrot_express_dig_site_to_docks = "Parrot Express Dig Site to Docks" parrot_express_volcano_to_docks = "Parrot Express Volcano to Docks" + blacksmith_copper = "Upgrade Copper Tools" + blacksmith_iron = "Upgrade Iron Tools" + blacksmith_gold = "Upgrade Gold Tools" + blacksmith_iridium = "Upgrade Iridium Tools" + farming = "Start Farming" + fishing = "Start Fishing" # Skull Cavern Elevator diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 9fa257114eb3..6403e1c34e57 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -130,6 +130,12 @@ class Region: mines_floor_110 = "The Mines - Floor 110" mines_floor_115 = "The Mines - Floor 115" mines_floor_120 = "The Mines - Floor 120" + blacksmith_copper = "Blacksmith Copper Upgrades" + blacksmith_iron = "Blacksmith Iron Upgrades" + blacksmith_gold = "Blacksmith Gold Upgrades" + blacksmith_iridium = "Blacksmith Iridium Upgrades" + farming = "Farming" + fishing = "Fishing" class DeepWoodsRegion: From ec49259bee4de8157bb37e0960805178121a6b97 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 08:27:48 +0200 Subject: [PATCH 012/482] - Simplify some mine rules --- worlds/stardew_valley/__init__.py | 7 +-- worlds/stardew_valley/data/locations.csv | 8 ++-- worlds/stardew_valley/logic.py | 43 ++----------------- .../mods/logic/skullcavernelevator.py | 8 ++-- worlds/stardew_valley/rules.py | 17 +++++--- 5 files changed, 28 insertions(+), 55 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index aa825af302eb..a56870e37619 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -186,8 +186,7 @@ def setup_victory(self): "Victory") elif self.options.goal == Goal.option_bottom_of_the_mines: self.create_event_location(location_table[GoalName.bottom_of_the_mines], - self.logic.can_mine_to_floor(120).simplify(), - "Victory") + item="Victory") elif self.options.goal == Goal.option_cryptic_note: self.create_event_location(location_table[GoalName.cryptic_note], self.logic.can_complete_quest("Cryptic Note").simplify(), @@ -223,7 +222,9 @@ def create_item(self, item: Union[str, ItemData]) -> StardewItem: self.all_progression_items.add(item.name) return StardewItem(item.name, item.classification, item.code, self.player) - def create_event_location(self, location_data: LocationData, rule: StardewRule, item: Optional[str] = None): + def create_event_location(self, location_data: LocationData, rule: StardewRule = None, item: Optional[str] = None): + if rule is None: + rule = True_() if item is None: item = location_data.name diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 13991e84cdba..861c5bf4b334 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -947,7 +947,7 @@ id,region,name,tags,mod_name 2030,Town,The Legend of the Winter Star,FESTIVAL, 2031,Farm,Collect All Rarecrows,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2102,Town,Cave Patrol,SPECIAL_ORDER_BOARD, +2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, 2103,Town,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, 2104,Town,Biome Balance,SPECIAL_ORDER_BOARD, 2105,Town,Rock Rejuvenation,SPECIAL_ORDER_BOARD, @@ -962,8 +962,8 @@ id,region,name,tags,mod_name 2114,Town,Robin's Resource Rush,SPECIAL_ORDER_BOARD, 2115,Town,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, 2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2117,Town,A Curious Substance,SPECIAL_ORDER_BOARD, -2118,Town,Prismatic Jelly,SPECIAL_ORDER_BOARD, +2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, +2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, 2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", 2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,SPECIAL_ORDER_QI,JUNIMO_KART", 2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", @@ -1107,7 +1107,7 @@ id,region,name,tags,mod_name 5508,Stardew Valley,Analyze All Life School Locations,MANDATORY,Magic 5509,Stardew Valley,Analyze: Descend,MANDATORY,Magic 5510,Stardew Valley,Analyze: Fireball,MANDATORY,Magic -5511,Stardew Valley,Analyze: Frostbite,MANDATORY,Magic +5511,The Mines - Floor 60,Analyze: Frostbite,MANDATORY,Magic 5512,Stardew Valley,Analyze All Elemental School Locations,MANDATORY,Magic 5513,Stardew Valley,Analyze: Lantern,MANDATORY,Magic 5514,Stardew Valley,Analyze: Tendrils,MANDATORY,Magic diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index af6017e55f06..d56b819fa091 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -496,7 +496,7 @@ def __post_init__(self): self.special_order_rules.update({ SpecialOrder.island_ingredients: self.can_meet(NPC.caroline) & self.has_island_transport() & self.can_farm_perfectly() & self.can_ship(Vegetable.taro_root) & self.can_ship(Fruit.pineapple) & self.can_ship(Forageable.ginger), - SpecialOrder.cave_patrol: self.can_meet(NPC.clint) & self.can_mine_perfectly() & self.can_mine_to_floor(120), + SpecialOrder.cave_patrol: self.can_meet(NPC.clint), SpecialOrder.aquatic_overpopulation: self.can_meet(NPC.demetrius) & self.can_fish_perfectly(), SpecialOrder.biome_balance: self.can_meet(NPC.demetrius) & self.can_fish_perfectly(), SpecialOrder.rock_rejuivenation: self.has_relationship(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & @@ -516,8 +516,8 @@ def __post_init__(self): SpecialOrder.juicy_bugs_wanted_yum: self.can_reach_region(Region.beach) & self.has(Loot.bug_meat), SpecialOrder.tropical_fish: self.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), - SpecialOrder.a_curious_substance: self.can_reach_region(Region.wizard_tower) & self.can_mine_perfectly() & self.can_mine_to_floor(80), - SpecialOrder.prismatic_jelly: self.can_reach_region(Region.wizard_tower) & self.can_mine_perfectly() & self.can_mine_to_floor(40), + SpecialOrder.a_curious_substance: self.can_reach_region(Region.wizard_tower), + SpecialOrder.prismatic_jelly: self.can_reach_region(Region.wizard_tower), SpecialOrder.qis_crop: self.can_farm_perfectly() & self.can_reach_region(Region.greenhouse) & self.can_reach_region(Region.island_west) & self.has_total_skill_level(50) & self.has(Machine.seed_maker) & self.has_building(Building.shipping_bin), @@ -1046,7 +1046,7 @@ def get_weapon_rule_for_floor_tier(self, tier: int): def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: key = f"can_progress_in_the_mines_from_floor {floor}" if key not in self.cached_rules: - tier = int(floor / 40) + tier = floor // 40 rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) @@ -1058,19 +1058,6 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: self.cached_rules[key] = And(rules) return self.cached_rules[key] - def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule: - tier = (floor // 40) + 1 - rules = [] - weapon_rule = self.get_weapon_rule_for_floor_tier(tier) - rules.append(weapon_rule) - if self.options.tool_progression == ToolProgression.option_progressive: - rules.append(self.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) - if self.options.skill_progression == SkillProgression.option_progressive: - skill_tier = min(10, max(0, tier * 2)) - rules.append(self.has_skill_level(Skill.mining, skill_tier)) - rules.append(self.has_skill_level(Skill.combat, skill_tier)) - return And(rules) - def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: key = f"has_mine_elevator_to_floor {floor}" if key not in self.cached_rules: @@ -1082,16 +1069,6 @@ def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: self.cached_rules[key] = True_() return self.cached_rules[key] - - - def can_mine_to_floor(self, floor: int) -> StardewRule: - previous_elevator = max(floor - 5, 0) - previous_previous_elevator = max(floor - 10, 0) - return ((self.has_mine_elevator_to_floor(previous_elevator) & - self.can_progress_in_the_mines_from_floor(previous_elevator)) | - (self.has_mine_elevator_to_floor(previous_previous_elevator) & - self.can_progress_easily_in_the_mines_from_floor(previous_previous_elevator))) - def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: tier = floor // 50 rules = [] @@ -1106,18 +1083,6 @@ def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule self.has_skill_level(Skill.mining, skill_tier)}) return And(rules) - def can_progress_easily_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: - return self.can_progress_in_the_skull_cavern_from_floor(floor + 50) - - def can_mine_to_skull_cavern_floor(self, floor: int) -> StardewRule: - previous_elevator = max(floor - 25, 0) - previous_previous_elevator = max(floor - 50, 0) - has_mine_elevator = self.has_mine_elevator_to_floor(5) # Skull Cavern Elevator menu needs a normal elevator... - return ((has_skull_cavern_elevator_to_floor(self, previous_elevator) & - self.can_progress_in_the_skull_cavern_from_floor(previous_elevator)) | - (has_skull_cavern_elevator_to_floor(self, previous_previous_elevator) & - self.can_progress_easily_in_the_skull_cavern_from_floor(previous_previous_elevator))) & has_mine_elevator - def has_jotpk_power_level(self, power_level: int) -> StardewRule: if self.options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: return True_() diff --git a/worlds/stardew_valley/mods/logic/skullcavernelevator.py b/worlds/stardew_valley/mods/logic/skullcavernelevator.py index 9a5140ae39c9..fd540e05abee 100644 --- a/worlds/stardew_valley/mods/logic/skullcavernelevator.py +++ b/worlds/stardew_valley/mods/logic/skullcavernelevator.py @@ -3,8 +3,8 @@ from ... import options -def has_skull_cavern_elevator_to_floor(self, floor: int) -> StardewRule: - if self.options.elevator_progression != options.ElevatorProgression.option_vanilla and \ - ModNames.skull_cavern_elevator in self.options.mods: - return self.received("Progressive Skull Cavern Elevator", floor // 25) +def has_skull_cavern_elevator_to_floor(logic, floor: int) -> StardewRule: + if logic.options.elevator_progression != options.ElevatorProgression.option_vanilla and \ + ModNames.skull_cavern_elevator in logic.options.mods: + return logic.received("Progressive Skull Cavern Elevator", floor // 25) return True_() diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 97c49cde105a..ec83dfa046a0 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -3,6 +3,7 @@ from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules +from .mods.logic.skullcavernelevator import has_skull_cavern_elevator_to_floor from .options import StardewValleyOptions, ToolProgression, BuildingProgression, SkillProgression, ExcludeGingerIsland, Cropsanity, SpecialOrderLocations, Museumsanity, \ BackpackProgression, ArcadeMachineLocations from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, \ @@ -159,6 +160,10 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp set_skull_cavern_floor_entrance_rules(logic, multiworld, player) set_blacksmith_entrance_rules(logic, multiworld, player) + + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), + logic.can_earn_farming_xp().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), logic.received("Beach Bridge") | (magic.can_blink(logic)).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), @@ -223,16 +228,18 @@ def set_mines_floor_entrance_rules(logic, multiworld, player): for floor in range(5, 120 + 5, 5): rule = logic.has_mine_elevator_to_floor(floor - 10) if floor == 5 or floor == 45 or floor == 85: - rule = rule & logic.can_progress_easily_in_the_mines_from_floor(floor) + rule = rule & logic.can_progress_in_the_mines_from_floor(floor) entrance = multiworld.get_entrance(dig_to_mines_floor(floor), player) MultiWorldRules.set_rule(entrance, rule.simplify()) - def set_skull_cavern_floor_entrance_rules(logic, multiworld, player): for floor in range(25, 200 + 25, 25): - MultiWorldRules.set_rule(multiworld.get_entrance(dig_to_skull_floor(floor), player), - logic.can_mine_to_skull_cavern_floor(floor).simplify()) + rule = has_skull_cavern_elevator_to_floor(logic, floor - 25) + if floor == 5 or floor == 45 or floor == 85: + rule = rule & logic.can_progress_in_the_skull_cavern_from_floor(floor) + entrance = multiworld.get_entrance(dig_to_skull_floor(floor), player) + MultiWorldRules.set_rule(entrance, rule.simplify()) def set_blacksmith_entrance_rules(logic, multiworld, player): @@ -623,7 +630,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), (logic.has("Fire Quartz") & magic.can_use_altar(logic)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.can_mine_to_floor(70) & logic.can_fish(85) & magic.can_use_altar(logic)).simplify()) + (logic.can_fish(85) & magic.can_use_altar(logic)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), (logic.can_reach_region(Region.mines) & logic.has("Fire Quartz") & logic.can_reach_region(Region.mines_floor_70) & logic.can_fish(85) & From 912533b26198889e3f482b8c1a7f5e47085670a0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 08:38:21 +0200 Subject: [PATCH 013/482] - Finished the skill rules simplification --- worlds/stardew_valley/logic.py | 36 +++---------------- worlds/stardew_valley/rules.py | 12 ++++--- .../test/performance/TestPerformance.py | 6 ++-- 3 files changed, 16 insertions(+), 38 deletions(-) diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index d56b819fa091..bad382152162 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -673,18 +673,16 @@ def _can_earn_skill_level(self, skill: str, level: int) -> StardewRule: previous_level_rule = self.has_skill_level(skill, level - 1) if skill == Skill.fishing: - xp_rule = self.can_get_fishing_xp() & self.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) + xp_rule = self.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) elif skill == Skill.farming: - xp_rule = self.can_get_farming_xp() & self.has_tool(Tool.hoe, tool_material) & self.can_water(tool_level) + xp_rule = self.has_tool(Tool.hoe, tool_material) & self.can_water(tool_level) elif skill == Skill.foraging: - xp_rule = self.can_get_foraging_xp() & \ - (self.has_tool(Tool.axe, tool_material) | magic.can_use_clear_debris_instead_of_tool_level(self, tool_level)) + xp_rule = self.has_tool(Tool.axe, tool_material) | magic.can_use_clear_debris_instead_of_tool_level(self, tool_level) elif skill == Skill.mining: - xp_rule = self.can_get_mining_xp() & \ - (self.has_tool(Tool.pickaxe, tool_material) | magic.can_use_clear_debris_instead_of_tool_level(self, tool_level)) + xp_rule = self.has_tool(Tool.pickaxe, tool_material) | magic.can_use_clear_debris_instead_of_tool_level(self, tool_level) elif skill == Skill.combat: combat_tier = Performance.tiers[tool_level] - xp_rule = self.can_get_combat_xp() & self.can_do_combat_at_level(combat_tier) + xp_rule = self.can_do_combat_at_level(combat_tier) else: xp_rule = skills.can_earn_mod_skill_level(self, skill, level) @@ -782,30 +780,6 @@ def can_get_farming_xp(self) -> StardewRule: self.cached_rules[key] = Or(crop_rules) return self.cached_rules[key] - def can_get_foraging_xp(self) -> StardewRule: - key = f"can_get_foraging_xp" - if key not in self.cached_rules: - tool_rule = self.has_tool(Tool.axe) - tree_rule = self.can_reach_region(Region.forest) & self.has_any_season_not_winter() - self.cached_rules[key] = tool_rule & tree_rule - return self.cached_rules[key] - - def can_get_mining_xp(self) -> StardewRule: - key = f"can_get_mining_xp" - if key not in self.cached_rules: - tool_rule = self.has_tool(Tool.pickaxe) - stone_rule = self.can_reach_any_region([Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5]) - self.cached_rules[key] = tool_rule & stone_rule - return self.cached_rules[key] - - def can_get_combat_xp(self) -> StardewRule: - key = f"can_get_combat_xp" - if key not in self.cached_rules: - tool_rule = self.has_any_weapon() - enemy_rule = self.can_reach_any_region([Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5]) - self.cached_rules[key] = tool_rule & enemy_rule - return self.cached_rules[key] - def can_get_fishing_xp(self) -> StardewRule: key = f"can_get_fishing_xp" if key not in self.cached_rules: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index ec83dfa046a0..61fb4074209d 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -159,10 +159,7 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp set_mines_floor_entrance_rules(logic, multiworld, player) set_skull_cavern_floor_entrance_rules(logic, multiworld, player) set_blacksmith_entrance_rules(logic, multiworld, player) - - - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), - logic.can_earn_farming_xp().simplify()) + set_skill_entrance_rules(logic, multiworld, player) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), logic.received("Beach Bridge") | (magic.can_blink(logic)).simplify()) @@ -249,6 +246,13 @@ def set_blacksmith_entrance_rules(logic, multiworld, player): set_blacksmith_upgrade_rule(logic, multiworld, player, Entrance.blacksmith_iridium, MetalBar.iridium, ToolMaterial.iridium) +def set_skill_entrance_rules(logic, multiworld, player): + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), + logic.can_get_farming_xp().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fishing, player), + logic.can_get_fishing_xp().simplify()) + + def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, item_name: str, tool_material: str): material_entrance = multiworld.get_entrance(entrance_name, player) upgrade_rule = logic.has(item_name) & logic.can_spend_money(tool_upgrade_prices[tool_material]) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index f313c7533b89..0053db9ec410 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -49,7 +49,7 @@ def size_name(number_players): class TestDefaultOptions(SVTestCase): - acceptable_time_per_player = 0.12 + acceptable_time_per_player = 0.04 options = default_options() def test_solo(self): @@ -87,7 +87,7 @@ def test_10_player(self): class TestMinLocationMaxItems(SVTestCase): - acceptable_time_per_player = 0.25 + acceptable_time_per_player = 0.6 options = minimal_locations_maximal_items() def test_solo(self): @@ -124,7 +124,7 @@ def test_10_player(self): class TestAllsanityWithoutMods(SVTestCase): - acceptable_time_per_player = 0.18 + acceptable_time_per_player = 0.1 options = allsanity_options_without_mods() def test_solo(self): From 53228efe76d184fcae6b857d4c0a895eddaa805e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 08:58:55 +0200 Subject: [PATCH 014/482] - Adapt the mines tests to the new rules --- worlds/stardew_valley/test/TestGeneration.py | 25 ++++---------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index b6bd68f7f008..ab1739e41587 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -155,34 +155,19 @@ class TestProgressiveElevator(SVTestBase): 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): + def test_given_elevator_to_floor_105_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.get_item_by_name("Progressive Mine Elevator")] * 21) 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")) + floor_120 = self.multiworld.get_region("The Mines - Floor 120", self.player) - self.assertFalse(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) + self.assertFalse(floor_120.can_reach(self.multiworld.state)) self.collect(self.get_item_by_name("Progressive Mine Elevator")) - self.assertTrue(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")) - - self.assertFalse(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")) - - self.assertTrue(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) + self.assertTrue(floor_120.can_reach(self.multiworld.state)) class TestLocationGeneration(SVTestBase): From 8c626050fcb1167d1c1dfc93f82083b358047fae Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 09:02:13 +0200 Subject: [PATCH 015/482] - Performance test speed was a bit too aggressive --- worlds/stardew_valley/test/performance/TestPerformance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 0053db9ec410..fa368b98ea6c 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -49,7 +49,7 @@ def size_name(number_players): class TestDefaultOptions(SVTestCase): - acceptable_time_per_player = 0.04 + acceptable_time_per_player = 0.05 options = default_options() def test_solo(self): From d1dad579a5d0b45ed48e50c2cf5d1c143be25c10 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 09:28:29 +0200 Subject: [PATCH 016/482] - Improve Regions for quest locations --- worlds/stardew_valley/data/locations.csv | 44 ++++++++++---------- worlds/stardew_valley/logic.py | 42 ++++++++++--------- worlds/stardew_valley/strings/quest_names.py | 1 + 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 861c5bf4b334..2db132930cbc 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -175,43 +175,43 @@ id,region,name,tags,mod_name 505,Farm,Advancement,"MANDATORY,QUEST", 506,Museum,Archaeology,"MANDATORY,QUEST", 507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", -508,Farm,Forging Ahead,"MANDATORY,QUEST", -509,Farm,Smelting,"MANDATORY,QUEST", -510,The Mines - Floor 5,Initiation,"MANDATORY,QUEST", +508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", +509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", +510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", 511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", 512,Sam's House,Jodi's Request,"MANDATORY,QUEST", 513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", 514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", 515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", -516,Town,Pam Is Thirsty,"MANDATORY,QUEST", +516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", 517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", 518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", 519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", -520,Town,Crop Research,"MANDATORY,QUEST", -521,Town,Knee Therapy,"MANDATORY,QUEST", -522,Town,Robin's Request,"MANDATORY,QUEST", -523,Skull Cavern,Qi's Challenge,"MANDATORY,QUEST", +520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", +521,Alex's House,Knee Therapy,"MANDATORY,QUEST", +522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", 524,Desert,The Mysterious Qi,"MANDATORY,QUEST", -525,Town,Carving Pumpkins,"MANDATORY,QUEST", +525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", 526,Town,A Winter Mystery,"MANDATORY,QUEST", 527,Secret Woods,Strange Note,"MANDATORY,QUEST", -528,Skull Cavern,Cryptic Note,"MANDATORY,QUEST", -529,Town,Fresh Fruit,"MANDATORY,QUEST", -530,Town,Aquatic Research,"MANDATORY,QUEST", -531,Town,A Soldier's Star,"MANDATORY,QUEST", -532,Town,Mayor's Need,"MANDATORY,QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", +529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", +530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", +531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", +532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", 533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", -534,Town,Pam Needs Juice,"MANDATORY,QUEST", +534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", 535,Sam's House,Fish Casserole,"MANDATORY,QUEST", -536,Beach,Catch A Squid,"MANDATORY,QUEST", +536,Fishing,Catch A Squid,"MANDATORY,QUEST", 537,Saloon,Fish Stew,"MANDATORY,QUEST", -538,Town,Pierre's Notice,"MANDATORY,QUEST", -539,Town,Clint's Attempt,"MANDATORY,QUEST", -540,Town,A Favor For Clint,"MANDATORY,QUEST", +538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", +539,Blacksmith,Clint's Attempt,"MANDATORY,QUEST", +540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", 541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", -542,Town,Granny's Gift,"MANDATORY,QUEST", -543,Saloon,Exotic Spirits,"MANDATORY,QUEST", -544,Town,Catch a Lingcod,"MANDATORY,QUEST", +542,Alex's House,Granny's Gift,"MANDATORY,QUEST", +543,Desert,Exotic Spirits,"MANDATORY,QUEST", +544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", 545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", 546,Railroad,Dark Talisman,"MANDATORY,QUEST", 547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index bad382152162..b430832cf68d 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -403,43 +403,45 @@ def __post_init__(self): self.building_rules.update(get_modded_building_rules(self, self.options.mods)) self.quest_rules.update({ - Quest.introductions: self.can_reach_region(Region.town), + Quest.introductions: True_(), Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), - Quest.getting_started: self.has(Vegetable.parsnip) & self.has_tool(Tool.hoe) & self.can_water(0), + Quest.getting_started: self.has(Vegetable.parsnip), Quest.to_the_beach: self.can_reach_region(Region.beach), Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.has_building(Building.coop), Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), - Quest.archaeology: (self.has_tool(Tool.hoe) | self.can_mine_in_the_mines_floor_1_40() | self.can_fish()) & self.can_reach_region(Region.museum), - Quest.meet_the_wizard: self.can_reach_region(Region.town) & self.can_reach_region(Region.community_center) & self.can_reach_region(Region.wizard_tower), + Quest.archaeology: self.has_tool(Tool.hoe) | self.can_mine_in_the_mines_floor_1_40() | self.can_fish(), + Quest.rat_problem: self.can_reach_region(Region.town) & self.can_reach_region(Region.community_center), + Quest.meet_the_wizard: self.can_complete_quest(Quest.rat_problem), Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), Quest.smelting: self.has(MetalBar.copper), Quest.initiation: self.can_mine_in_the_mines_floor_1_40(), - Quest.robins_lost_axe: self.has_season(Season.spring) & self.can_reach_region(Region.forest) & self.can_meet(NPC.robin), + Quest.robins_lost_axe: self.has_season(Season.spring) & self.can_meet(NPC.robin), Quest.jodis_request: self.has_season(Season.spring) & self.has(Vegetable.cauliflower) & self.can_meet(NPC.jodi), - Quest.mayors_shorts: self.has_season(Season.summer) & self.can_reach_region(Region.ranch) & - (self.has_relationship(NPC.marnie, 2) | (magic.can_blink(self))) & self.can_meet(NPC.lewis), + Quest.mayors_shorts: self.has_season(Season.summer) & + (self.has_relationship(NPC.marnie, 2) | (magic.can_blink(self))) & + self.can_meet(NPC.lewis), Quest.blackberry_basket: self.has_season(Season.fall) & self.can_meet(NPC.linus), - Quest.marnies_request: self.has_relationship(NPC.marnie, 3) & self.has(Forageable.cave_carrot) & self.can_reach_region(Region.ranch), + Quest.marnies_request: self.has_relationship(NPC.marnie, 3) & self.has(Forageable.cave_carrot), Quest.pam_is_thirsty: self.has_season(Season.summer) & self.has(ArtisanGood.pale_ale) & self.can_meet(NPC.pam), Quest.a_dark_reagent: self.has_season(Season.winter) & self.has(Loot.void_essence) & self.can_meet(NPC.wizard), Quest.cows_delight: self.has_season(Season.fall) & self.has(Vegetable.amaranth) & self.can_meet(NPC.marnie), - Quest.the_skull_key: self.received(Wallet.skull_key) & self.can_reach_region(Region.skull_cavern_entrance), + Quest.the_skull_key: self.received(Wallet.skull_key), Quest.crop_research: self.has_season(Season.summer) & self.has(Fruit.melon) & self.can_meet(NPC.demetrius), Quest.knee_therapy: self.has_season(Season.summer) & self.has(Fruit.hot_pepper) & self.can_meet(NPC.george), Quest.robins_request: self.has_season(Season.winter) & self.has(Material.hardwood) & self.can_meet(NPC.robin), - Quest.qis_challenge: self.can_mine_in_the_skull_cavern(), - Quest.the_mysterious_qi: self.can_reach_region(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.can_reach_region(Region.desert) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), + Quest.qis_challenge: True_(), # The skull cavern floor 25 already has rules + Quest.the_mysterious_qi: self.can_reach_region(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.can_reach_region(Region.mayor_house) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), Quest.carving_pumpkins: self.has_season(Season.fall) & self.has(Vegetable.pumpkin) & self.can_meet(NPC.caroline), - Quest.a_winter_mystery: self.has_season(Season.winter) & self.can_reach_region(Region.town), - Quest.strange_note: self.has(Forageable.secret_note) & self.can_reach_region(Region.secret_woods) & self.has(ArtisanGood.maple_syrup), - Quest.cryptic_note: self.has(Forageable.secret_note) & self.can_reach_region(Region.skull_cavern_100), + Quest.a_winter_mystery: self.has_season(Season.winter), + Quest.strange_note: self.has(Forageable.secret_note) & self.has(ArtisanGood.maple_syrup), + Quest.cryptic_note: self.has(Forageable.secret_note), Quest.fresh_fruit: self.has_season(Season.spring) & self.has(Fruit.apricot) & self.can_meet(NPC.emily), Quest.aquatic_research: self.has_season(Season.summer) & self.has(Fish.pufferfish) & self.can_meet(NPC.demetrius), Quest.a_soldiers_star: self.has_season(Season.summer) & self.has_year_two() & self.has(Fruit.starfruit) & self.can_meet(NPC.kent), Quest.mayors_need: self.has_season(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.can_meet(NPC.lewis), Quest.wanted_lobster: self.has_season(Season.fall) & self.has_season(Season.fall) & self.has(Fish.lobster) & self.can_meet(NPC.gus), Quest.pam_needs_juice: self.has_season(Season.fall) & self.has(ArtisanGood.battery_pack) & self.can_meet(NPC.pam), - Quest.fish_casserole: self.has_relationship(NPC.jodi, 4) & self.has(Fish.largemouth_bass) & self.can_reach_region(Region.sam_house), + Quest.fish_casserole: self.has_relationship(NPC.jodi, 4) & self.has(Fish.largemouth_bass), Quest.catch_a_squid: self.has_season(Season.winter) & self.has(Fish.squid) & self.can_meet(NPC.willy), Quest.fish_stew: self.has_season(Season.winter) & self.has(Fish.albacore) & self.can_meet(NPC.gus), Quest.pierres_notice: self.has_season(Season.spring) & self.has("Sashimi") & self.can_meet(NPC.pierre), @@ -449,11 +451,11 @@ def __post_init__(self): Quest.grannys_gift: self.has_season(Season.spring) & self.has(Forageable.leek) & self.can_meet(NPC.evelyn), Quest.exotic_spirits: self.has_season(Season.winter) & self.has(Forageable.coconut) & self.can_meet(NPC.gus), Quest.catch_a_lingcod: self.has_season(Season.winter) & self.has("Lingcod") & self.can_meet(NPC.willy), - Quest.dark_talisman: self.has_rusty_key() & self.can_reach_region(Region.railroad) & self.can_meet(NPC.krobus) & self.can_reach_region(Region.mutant_bug_lair), - Quest.goblin_problem: self.can_reach_region(Region.witch_swamp) & self.has(ArtisanGood.void_mayonnaise), - Quest.magic_ink: self.can_reach_region(Region.witch_hut) & self.can_meet(NPC.wizard), - Quest.the_pirates_wife: self.can_reach_region(Region.island_west) & self.can_meet(NPC.kent) & - self.can_meet(NPC.gus) & self.can_meet(NPC.sandy) & self.can_meet(NPC.george) & + Quest.dark_talisman: self.has_rusty_key() & self.can_meet(NPC.krobus) & self.can_reach_region(Region.mutant_bug_lair), + Quest.goblin_problem: self.has(ArtisanGood.void_mayonnaise), + Quest.magic_ink: self.can_meet(NPC.wizard), + Quest.the_pirates_wife: self.can_meet(NPC.kent) & self.can_meet(NPC.gus) & + self.can_meet(NPC.sandy) & self.can_meet(NPC.george) & self.can_meet(NPC.wizard) & self.can_meet(NPC.willy), }) diff --git a/worlds/stardew_valley/strings/quest_names.py b/worlds/stardew_valley/strings/quest_names.py index 112e40a5d84d..86fc406a0a6d 100644 --- a/worlds/stardew_valley/strings/quest_names.py +++ b/worlds/stardew_valley/strings/quest_names.py @@ -6,6 +6,7 @@ class Quest: raising_animals = "Raising Animals" advancement = "Advancement" archaeology = "Archaeology" + rat_problem = "Rat Problem" meet_the_wizard = "Meet The Wizard" forging_ahead = "Forging Ahead" smelting = "Smelting" From f97560397127c852bc7cad56dde70c0e09ad157e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 09:29:55 +0200 Subject: [PATCH 017/482] - Fix error in blacksmith region name --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 2db132930cbc..e6a210487ea4 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -206,7 +206,7 @@ id,region,name,tags,mod_name 536,Fishing,Catch A Squid,"MANDATORY,QUEST", 537,Saloon,Fish Stew,"MANDATORY,QUEST", 538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", -539,Blacksmith,Clint's Attempt,"MANDATORY,QUEST", +539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", 540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", 541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", 542,Alex's House,Granny's Gift,"MANDATORY,QUEST", From ceb71fad2a4c37fde8c12f49f417ef773545e5e8 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 09:46:07 +0200 Subject: [PATCH 018/482] - Added Traveling merchant regions for days --- worlds/stardew_valley/data/locations.csv | 90 +++++++++---------- worlds/stardew_valley/regions.py | 34 +++++-- worlds/stardew_valley/rules.py | 24 +++-- .../stardew_valley/strings/entrance_names.py | 7 ++ worlds/stardew_valley/strings/region_names.py | 7 ++ 5 files changed, 96 insertions(+), 66 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index e6a210487ea4..3db9f40c06fd 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -242,30 +242,30 @@ id,region,name,tags,mod_name 703,Desert,Galaxy Sword Shrine,MANDATORY, 704,Farmhouse,Have a Baby,MANDATORY, 705,Farmhouse,Have Another Baby,MANDATORY, -801,Town,Help Wanted: Gathering 1,HELP_WANTED, -802,Town,Help Wanted: Gathering 2,HELP_WANTED, -803,Town,Help Wanted: Gathering 3,HELP_WANTED, -804,Town,Help Wanted: Gathering 4,HELP_WANTED, -805,Town,Help Wanted: Gathering 5,HELP_WANTED, -806,Town,Help Wanted: Gathering 6,HELP_WANTED, -807,Town,Help Wanted: Gathering 7,HELP_WANTED, -808,Town,Help Wanted: Gathering 8,HELP_WANTED, -811,Town,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,Town,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,Town,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,Town,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,Town,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,Town,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,Town,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,Town,Help Wanted: Slay Monsters 8,HELP_WANTED, -821,Town,Help Wanted: Fishing 1,HELP_WANTED, -822,Town,Help Wanted: Fishing 2,HELP_WANTED, -823,Town,Help Wanted: Fishing 3,HELP_WANTED, -824,Town,Help Wanted: Fishing 4,HELP_WANTED, -825,Town,Help Wanted: Fishing 5,HELP_WANTED, -826,Town,Help Wanted: Fishing 6,HELP_WANTED, -827,Town,Help Wanted: Fishing 7,HELP_WANTED, -828,Town,Help Wanted: Fishing 8,HELP_WANTED, +801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, +802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, +803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, +804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, +805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, +806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, +807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, +808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, +811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, +812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, +821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, +822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, +823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, +824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, +825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, +826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, +827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, +828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, 841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, 842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, 843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, @@ -298,27 +298,27 @@ id,region,name,tags,mod_name 870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, 871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, 872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, -901,Forest,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", -902,Forest,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", -903,Forest,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", -911,Forest,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", -912,Forest,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", -913,Forest,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", -921,Forest,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -922,Forest,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -923,Forest,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -931,Forest,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -932,Forest,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -933,Forest,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -941,Forest,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", -942,Forest,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", -943,Forest,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", -951,Forest,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", -952,Forest,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", -953,Forest,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", -961,Forest,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", -962,Forest,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", -963,Forest,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", +901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", +902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", +903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", +911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", +912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", +913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", +921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", +942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", +943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", +951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", +952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", +953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", +961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", +962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", +963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", 1001,Mountain,Fishsanity: Carp,FISHSANITY, 1002,Beach,Fishsanity: Herring,FISHSANITY, 1003,Forest,Fishsanity: Smallmouth Bass,FISHSANITY, diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index b8998fa1a157..7bc13911afcb 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -32,7 +32,20 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: Entrance.forest_to_marnie_ranch, Entrance.forest_to_leah_cottage, Entrance.forest_to_sewer, Entrance.buy_from_traveling_merchant]), - RegionData(Region.traveling_cart), + RegionData(Region.traveling_cart, [Entrance.buy_from_traveling_merchant_sunday, + Entrance.buy_from_traveling_merchant_monday, + Entrance.buy_from_traveling_merchant_tuesday, + Entrance.buy_from_traveling_merchant_wednesday, + Entrance.buy_from_traveling_merchant_thursday, + Entrance.buy_from_traveling_merchant_friday, + Entrance.buy_from_traveling_merchant_saturday]), + RegionData(Region.traveling_cart_sunday), + RegionData(Region.traveling_cart_monday), + RegionData(Region.traveling_cart_tuesday), + RegionData(Region.traveling_cart_wednesday), + RegionData(Region.traveling_cart_thursday), + RegionData(Region.traveling_cart_friday), + RegionData(Region.traveling_cart_saturday), RegionData(Region.farm_cave), RegionData(Region.greenhouse), RegionData(Region.mountain, @@ -81,6 +94,12 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.pierre_store, [Entrance.enter_sunroom]), RegionData(Region.sunroom), RegionData(Region.saloon, [Entrance.play_journey_of_the_prairie_king, Entrance.play_junimo_kart]), + RegionData(Region.jotpk_world_1, [Entrance.reach_jotpk_world_2]), + RegionData(Region.jotpk_world_2, [Entrance.reach_jotpk_world_3]), + RegionData(Region.jotpk_world_3), + RegionData(Region.junimo_kart_1, [Entrance.reach_junimo_kart_2]), + RegionData(Region.junimo_kart_2, [Entrance.reach_junimo_kart_3]), + RegionData(Region.junimo_kart_3), RegionData(Region.alex_house), RegionData(Region.trailer), RegionData(Region.mayor_house), @@ -159,12 +178,6 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: [Entrance.dig_site_to_professor_snail_cave, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_dig_site_to_docks, Entrance.parrot_express_dig_site_to_jungle]), RegionData(Region.professor_snail_cave), - RegionData(Region.jotpk_world_1, [Entrance.reach_jotpk_world_2]), - RegionData(Region.jotpk_world_2, [Entrance.reach_jotpk_world_3]), - RegionData(Region.jotpk_world_3), - RegionData(Region.junimo_kart_1, [Entrance.reach_junimo_kart_2]), - RegionData(Region.junimo_kart_2, [Entrance.reach_junimo_kart_3]), - RegionData(Region.junimo_kart_3), RegionData(Region.mines, [Entrance.talk_to_mines_dwarf, Entrance.dig_to_mines_floor_5]), RegionData(Region.mines_dwarf_shop), @@ -225,6 +238,13 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.enter_secret_woods, Region.secret_woods), ConnectionData(Entrance.forest_to_sewer, Region.sewer, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.buy_from_traveling_merchant, Region.traveling_cart), + ConnectionData(Entrance.buy_from_traveling_merchant_sunday, Region.traveling_cart_sunday), + ConnectionData(Entrance.buy_from_traveling_merchant_monday, Region.traveling_cart_monday), + ConnectionData(Entrance.buy_from_traveling_merchant_tuesday, Region.traveling_cart_tuesday), + ConnectionData(Entrance.buy_from_traveling_merchant_wednesday, Region.traveling_cart_wednesday), + ConnectionData(Entrance.buy_from_traveling_merchant_thursday, Region.traveling_cart_thursday), + ConnectionData(Entrance.buy_from_traveling_merchant_friday, Region.traveling_cart_friday), + ConnectionData(Entrance.buy_from_traveling_merchant_saturday, Region.traveling_cart_saturday), ConnectionData(Entrance.town_to_sewer, Region.sewer, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.enter_mutant_bug_lair, Region.mutant_bug_lair, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.mountain_to_railroad, Region.railroad), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 61fb4074209d..5eae92addc0a 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -98,7 +98,6 @@ def set_rules(world): MultiWorldRules.add_rule(multiworld.get_location("Have Another Baby", player), logic.can_reproduce(2).simplify()) - set_traveling_merchant_rules(logic, multiworld, player) set_arcade_machine_rules(logic, multiworld, player, world_options) set_deepwoods_rules(logic, multiworld, player, world_options) set_magic_spell_rules(logic, multiworld, player, world_options) @@ -160,6 +159,7 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp set_skull_cavern_floor_entrance_rules(logic, multiworld, player) set_blacksmith_entrance_rules(logic, multiworld, player) set_skill_entrance_rules(logic, multiworld, player) + set_traveling_merchant_day_rules(logic, multiworld, player) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), logic.received("Beach Bridge") | (magic.can_blink(logic)).simplify()) @@ -417,9 +417,9 @@ def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_ quest_number = set_number * 4 + quest_number_in_set + 1 set_help_wanted_delivery_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 4: - set_help_wanted_fishing_rule(logic, multiworld, player, month_rule, quest_number) + set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 5: - set_help_wanted_slay_monsters_rule(logic, multiworld, player, month_rule, quest_number) + set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 6: set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number) @@ -434,16 +434,14 @@ def set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number) MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) -def set_help_wanted_fishing_rule(logic: StardewLogic, multiworld, player, month_rule, quest_number): +def set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {fishing} {quest_number}" - fishing_rule = month_rule & logic.can_fish() - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), fishing_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule.simplify()) -def set_help_wanted_slay_monsters_rule(logic: StardewLogic, multiworld, player, month_rule, quest_number): +def set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {slay_monsters} {quest_number}" - slay_rule = month_rule & logic.can_do_combat_at_level("Basic") - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), slay_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule.simplify()) def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): @@ -540,13 +538,11 @@ def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multi logic.festival_rules[festival.name].simplify()) -def set_traveling_merchant_rules(logic: StardewLogic, multiworld: MultiWorld, player: int): +def set_traveling_merchant_day_rules(logic: StardewLogic, multiworld: MultiWorld, player: int): for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" - for i in range(1, 4): - location_name = f"Traveling Merchant {day} Item {i}" - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), - logic.received(item_for_day)) + entrance_name = f"Buy from Traveling Merchant {day}" + MultiWorldRules.set_rule(multiworld.get_entrance(entrance_name, player), logic.received(item_for_day)) def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 6e588512aa0c..b421aa703676 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -35,6 +35,13 @@ class Entrance: forest_to_leah_cottage = "Forest to Leah's Cottage" forest_to_sewer = "Forest to Sewer" buy_from_traveling_merchant = "Buy from Traveling Merchant" + buy_from_traveling_merchant_sunday = "Buy from Traveling Merchant Sunday" + buy_from_traveling_merchant_monday = "Buy from Traveling Merchant Monday" + buy_from_traveling_merchant_tuesday = "Buy from Traveling Merchant Tuesday" + buy_from_traveling_merchant_wednesday = "Buy from Traveling Merchant Wednesday" + buy_from_traveling_merchant_thursday = "Buy from Traveling Merchant Thursday" + buy_from_traveling_merchant_friday = "Buy from Traveling Merchant Friday" + buy_from_traveling_merchant_saturday = "Buy from Traveling Merchant Saturday" mountain_to_railroad = "Mountain to Railroad" mountain_to_tent = "Mountain to Tent" mountain_to_carpenter_shop = "Mountain to Carpenter Shop" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 6403e1c34e57..90aca5577c91 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -69,6 +69,13 @@ class Region: elliott_house = "Elliott's House" ranch = "Marnie's Ranch" traveling_cart = "Traveling Cart" + traveling_cart_sunday = "Traveling Cart Sunday" + traveling_cart_monday = "Traveling Cart Monday" + traveling_cart_tuesday = "Traveling Cart Tuesday" + traveling_cart_wednesday = "Traveling Cart Wednesday" + traveling_cart_thursday = "Traveling Cart Thursday" + traveling_cart_friday = "Traveling Cart Friday" + traveling_cart_saturday = "Traveling Cart Saturday" farm_cave = "Farmcave" greenhouse = "Greenhouse" tunnel_entrance = "Tunnel Entrance" From 15288546c22a09a01065214d750e0f442a0d7137 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 10:05:31 +0200 Subject: [PATCH 019/482] - Improve Museum location regions - Improve friendsanity location regions --- worlds/stardew_valley/data/locations.csv | 936 +++++++++++------------ worlds/stardew_valley/logic.py | 20 +- worlds/stardew_valley/rules.py | 18 +- 3 files changed, 479 insertions(+), 495 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3db9f40c06fd..23c91c191a38 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -319,61 +319,61 @@ id,region,name,tags,mod_name 961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", 962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", 963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", -1001,Mountain,Fishsanity: Carp,FISHSANITY, -1002,Beach,Fishsanity: Herring,FISHSANITY, -1003,Forest,Fishsanity: Smallmouth Bass,FISHSANITY, -1004,Beach,Fishsanity: Anchovy,FISHSANITY, -1005,Beach,Fishsanity: Sardine,FISHSANITY, -1006,Forest,Fishsanity: Sunfish,FISHSANITY, -1007,Forest,Fishsanity: Perch,FISHSANITY, -1008,Forest,Fishsanity: Chub,FISHSANITY, -1009,Forest,Fishsanity: Bream,FISHSANITY, -1010,Beach,Fishsanity: Red Snapper,FISHSANITY, -1011,Beach,Fishsanity: Sea Cucumber,FISHSANITY, -1012,Forest,Fishsanity: Rainbow Trout,FISHSANITY, -1013,Forest,Fishsanity: Walleye,FISHSANITY, -1014,Forest,Fishsanity: Shad,FISHSANITY, -1015,Mountain,Fishsanity: Bullhead,FISHSANITY, -1016,Mountain,Fishsanity: Largemouth Bass,FISHSANITY, -1017,Forest,Fishsanity: Salmon,FISHSANITY, -1018,The Mines - Floor 20,Fishsanity: Ghostfish,FISHSANITY, -1019,Beach,Fishsanity: Tilapia,FISHSANITY, -1020,Secret Woods,Fishsanity: Woodskip,FISHSANITY, -1021,Beach,Fishsanity: Flounder,FISHSANITY, -1022,Beach,Fishsanity: Halibut,FISHSANITY, -1023,Island West,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", -1024,Mutant Bug Lair,Fishsanity: Slimejack,FISHSANITY, -1025,Forest,Fishsanity: Midnight Carp,FISHSANITY, -1026,Beach,Fishsanity: Red Mullet,FISHSANITY, -1027,Forest,Fishsanity: Pike,FISHSANITY, -1028,Forest,Fishsanity: Tiger Trout,FISHSANITY, -1029,Island West,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", -1030,Beach,Fishsanity: Albacore,FISHSANITY, -1031,Desert,Fishsanity: Sandfish,FISHSANITY, -1032,The Mines - Floor 20,Fishsanity: Stonefish,FISHSANITY, -1033,Beach,Fishsanity: Tuna,FISHSANITY, -1034,Beach,Fishsanity: Eel,FISHSANITY, -1035,Forest,Fishsanity: Catfish,FISHSANITY, -1036,Beach,Fishsanity: Squid,FISHSANITY, -1037,Mountain,Fishsanity: Sturgeon,FISHSANITY, -1038,Forest,Fishsanity: Dorado,FISHSANITY, -1039,Beach,Fishsanity: Pufferfish,FISHSANITY, -1040,Witch's Swamp,Fishsanity: Void Salmon,FISHSANITY, -1041,Beach,Fishsanity: Super Cucumber,FISHSANITY, -1042,Pirate Cove,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", -1043,The Mines - Floor 60,Fishsanity: Ice Pip,FISHSANITY, -1044,Forest,Fishsanity: Lingcod,FISHSANITY, +1001,Fishing,Fishsanity: Carp,FISHSANITY, +1002,Fishing,Fishsanity: Herring,FISHSANITY, +1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, +1004,Fishing,Fishsanity: Anchovy,FISHSANITY, +1005,Fishing,Fishsanity: Sardine,FISHSANITY, +1006,Fishing,Fishsanity: Sunfish,FISHSANITY, +1007,Fishing,Fishsanity: Perch,FISHSANITY, +1008,Fishing,Fishsanity: Chub,FISHSANITY, +1009,Fishing,Fishsanity: Bream,FISHSANITY, +1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, +1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, +1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, +1013,Fishing,Fishsanity: Walleye,FISHSANITY, +1014,Fishing,Fishsanity: Shad,FISHSANITY, +1015,Fishing,Fishsanity: Bullhead,FISHSANITY, +1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, +1017,Fishing,Fishsanity: Salmon,FISHSANITY, +1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, +1019,Fishing,Fishsanity: Tilapia,FISHSANITY, +1020,Fishing,Fishsanity: Woodskip,FISHSANITY, +1021,Fishing,Fishsanity: Flounder,FISHSANITY, +1022,Fishing,Fishsanity: Halibut,FISHSANITY, +1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", +1024,Fishing,Fishsanity: Slimejack,FISHSANITY, +1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, +1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, +1027,Fishing,Fishsanity: Pike,FISHSANITY, +1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, +1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", +1030,Fishing,Fishsanity: Albacore,FISHSANITY, +1031,Fishing,Fishsanity: Sandfish,FISHSANITY, +1032,Fishing,Fishsanity: Stonefish,FISHSANITY, +1033,Fishing,Fishsanity: Tuna,FISHSANITY, +1034,Fishing,Fishsanity: Eel,FISHSANITY, +1035,Fishing,Fishsanity: Catfish,FISHSANITY, +1036,Fishing,Fishsanity: Squid,FISHSANITY, +1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, +1038,Fishing,Fishsanity: Dorado,FISHSANITY, +1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, +1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, +1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, +1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", +1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, +1044,Fishing,Fishsanity: Lingcod,FISHSANITY, 1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, -1046,The Mines - Floor 100,Fishsanity: Lava Eel,FISHSANITY, -1047,Beach,Fishsanity: Octopus,FISHSANITY, -1048,Beach,Fishsanity: Midnight Squid,FISHSANITY, -1049,Beach,Fishsanity: Spook Fish,FISHSANITY, -1050,Beach,Fishsanity: Blobfish,FISHSANITY, -1051,Beach,Fishsanity: Crimsonfish,FISHSANITY, -1052,Town,Fishsanity: Angler,FISHSANITY, -1053,Mountain,Fishsanity: Legend,FISHSANITY, -1054,Forest,Fishsanity: Glacierfish,FISHSANITY, -1055,Sewer,Fishsanity: Mutant Carp,FISHSANITY, +1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, +1047,Fishing,Fishsanity: Octopus,FISHSANITY, +1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, +1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, +1050,Fishing,Fishsanity: Blobfish,FISHSANITY, +1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, +1052,Fishing,Fishsanity: Angler,FISHSANITY, +1053,Fishing,Fishsanity: Legend,FISHSANITY, +1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, +1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, 1056,Town,Fishsanity: Crayfish,FISHSANITY, 1057,Town,Fishsanity: Snail,FISHSANITY, 1058,Town,Fishsanity: Periwinkle,FISHSANITY, @@ -384,186 +384,186 @@ id,region,name,tags,mod_name 1063,Beach,Fishsanity: Mussel,FISHSANITY, 1064,Beach,Fishsanity: Shrimp,FISHSANITY, 1065,Beach,Fishsanity: Oyster,FISHSANITY, -1100,Stardew Valley,Museumsanity: 5 Donations,MUSEUM_MILESTONES, -1101,Stardew Valley,Museumsanity: 10 Donations,MUSEUM_MILESTONES, -1102,Stardew Valley,Museumsanity: 15 Donations,MUSEUM_MILESTONES, -1103,Stardew Valley,Museumsanity: 20 Donations,MUSEUM_MILESTONES, -1104,Stardew Valley,Museumsanity: 25 Donations,MUSEUM_MILESTONES, -1105,Stardew Valley,Museumsanity: 30 Donations,MUSEUM_MILESTONES, -1106,Stardew Valley,Museumsanity: 35 Donations,MUSEUM_MILESTONES, -1107,Stardew Valley,Museumsanity: 40 Donations,MUSEUM_MILESTONES, -1108,Stardew Valley,Museumsanity: 50 Donations,MUSEUM_MILESTONES, -1109,Stardew Valley,Museumsanity: 60 Donations,MUSEUM_MILESTONES, -1110,Stardew Valley,Museumsanity: 70 Donations,MUSEUM_MILESTONES, -1111,Stardew Valley,Museumsanity: 80 Donations,MUSEUM_MILESTONES, -1112,Stardew Valley,Museumsanity: 90 Donations,MUSEUM_MILESTONES, -1113,Stardew Valley,Museumsanity: 95 Donations,MUSEUM_MILESTONES, -1114,Stardew Valley,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, -1115,Stardew Valley,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, -1116,Stardew Valley,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, -1117,Stardew Valley,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, -1118,Stardew Valley,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, -1119,Stardew Valley,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, -1120,Stardew Valley,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, -1121,Stardew Valley,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, -1122,Stardew Valley,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, -1123,Stardew Valley,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, -1124,Stardew Valley,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, -1125,Stardew Valley,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, -1126,Stardew Valley,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, -1127,Stardew Valley,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, -1128,Stardew Valley,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, -1201,The Mines - Floor 20,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, -1202,The Mines - Floor 20,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, -1203,The Mines - Floor 60,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, -1204,The Mines - Floor 100,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, -1205,Town,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, -1206,Forest,Museumsanity: Arrowhead,MUSEUM_DONATIONS, -1207,Forest,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, -1208,Forest,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, -1209,Forest,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, -1210,Forest,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, -1211,Mountain,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, -1212,Stardew Valley,Museumsanity: Rare Disc,MUSEUM_DONATIONS, -1213,Forest,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, -1214,Town,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, -1215,Farm,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, -1216,Mountain,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, -1217,Farm,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, -1218,Forest,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", -1219,Forest,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, -1220,Beach,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, -1221,Beach,Museumsanity: Anchor,MUSEUM_DONATIONS, -1222,Beach,Museumsanity: Glass Shards,MUSEUM_DONATIONS, -1223,Forest,Museumsanity: Bone Flute,MUSEUM_DONATIONS, -1224,Forest,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, -1225,The Mines - Floor 20,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, -1226,The Mines - Floor 60,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, -1227,Forest,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, -1228,Desert,Museumsanity: Golden Mask,MUSEUM_DONATIONS, -1229,Desert,Museumsanity: Golden Relic,MUSEUM_DONATIONS, -1230,Town,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, -1231,Desert,Museumsanity: Strange Doll,MUSEUM_DONATIONS, -1232,Forest,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, -1233,Forest,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, -1234,Dig Site,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, -1235,Dig Site,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, -1236,Dig Site,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, -1237,Dig Site,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, -1238,Dig Site,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, -1239,Dig Site,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, -1240,Forest,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, -1241,Forest,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, -1242,Forest,Museumsanity: Trilobite,MUSEUM_DONATIONS, -1243,The Mines - Floor 20,Museumsanity: Quartz,MUSEUM_DONATIONS, -1244,The Mines - Floor 100,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, -1245,The Mines - Floor 60,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, -1246,The Mines - Floor 20,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, -1247,The Mines - Floor 100,Museumsanity: Emerald,MUSEUM_DONATIONS, -1248,The Mines - Floor 60,Museumsanity: Aquamarine,MUSEUM_DONATIONS, -1249,The Mines - Floor 100,Museumsanity: Ruby,MUSEUM_DONATIONS, -1250,The Mines - Floor 20,Museumsanity: Amethyst,MUSEUM_DONATIONS, -1251,The Mines - Floor 20,Museumsanity: Topaz,MUSEUM_DONATIONS, -1252,The Mines - Floor 60,Museumsanity: Jade,MUSEUM_DONATIONS, -1253,The Mines - Floor 60,Museumsanity: Diamond,MUSEUM_DONATIONS, -1254,Skull Cavern Floor 100,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, -1255,Town,Museumsanity: Alamite,MUSEUM_DONATIONS, -1256,Town,Museumsanity: Bixite,MUSEUM_DONATIONS, -1257,Town,Museumsanity: Baryte,MUSEUM_DONATIONS, -1258,Town,Museumsanity: Aerinite,MUSEUM_DONATIONS, -1259,Town,Museumsanity: Calcite,MUSEUM_DONATIONS, -1260,Town,Museumsanity: Dolomite,MUSEUM_DONATIONS, -1261,Town,Museumsanity: Esperite,MUSEUM_DONATIONS, -1262,Town,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, -1263,Town,Museumsanity: Geminite,MUSEUM_DONATIONS, -1264,Town,Museumsanity: Helvite,MUSEUM_DONATIONS, -1265,Town,Museumsanity: Jamborite,MUSEUM_DONATIONS, -1266,Town,Museumsanity: Jagoite,MUSEUM_DONATIONS, -1267,Town,Museumsanity: Kyanite,MUSEUM_DONATIONS, -1268,Town,Museumsanity: Lunarite,MUSEUM_DONATIONS, -1269,Town,Museumsanity: Malachite,MUSEUM_DONATIONS, -1270,Town,Museumsanity: Neptunite,MUSEUM_DONATIONS, -1271,Town,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, -1272,Town,Museumsanity: Nekoite,MUSEUM_DONATIONS, -1273,Town,Museumsanity: Orpiment,MUSEUM_DONATIONS, -1274,Town,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, -1275,Town,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, -1276,Town,Museumsanity: Pyrite,MUSEUM_DONATIONS, -1277,Town,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, -1278,Town,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, -1279,Town,Museumsanity: Tigerseye,MUSEUM_DONATIONS, -1280,Town,Museumsanity: Jasper,MUSEUM_DONATIONS, -1281,Town,Museumsanity: Opal,MUSEUM_DONATIONS, -1282,Town,Museumsanity: Fire Opal,MUSEUM_DONATIONS, -1283,Town,Museumsanity: Celestine,MUSEUM_DONATIONS, -1284,Town,Museumsanity: Marble,MUSEUM_DONATIONS, -1285,Town,Museumsanity: Sandstone,MUSEUM_DONATIONS, -1286,Town,Museumsanity: Granite,MUSEUM_DONATIONS, -1287,Town,Museumsanity: Basalt,MUSEUM_DONATIONS, -1288,Town,Museumsanity: Limestone,MUSEUM_DONATIONS, -1289,Town,Museumsanity: Soapstone,MUSEUM_DONATIONS, -1290,Town,Museumsanity: Hematite,MUSEUM_DONATIONS, -1291,Town,Museumsanity: Mudstone,MUSEUM_DONATIONS, -1292,Town,Museumsanity: Obsidian,MUSEUM_DONATIONS, -1293,Town,Museumsanity: Slate,MUSEUM_DONATIONS, -1294,Town,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, -1295,Town,Museumsanity: Star Shards,MUSEUM_DONATIONS, -1301,Town,Friendsanity: Alex 1 <3,FRIENDSANITY, -1302,Town,Friendsanity: Alex 2 <3,FRIENDSANITY, -1303,Town,Friendsanity: Alex 3 <3,FRIENDSANITY, -1304,Town,Friendsanity: Alex 4 <3,FRIENDSANITY, -1305,Town,Friendsanity: Alex 5 <3,FRIENDSANITY, -1306,Town,Friendsanity: Alex 6 <3,FRIENDSANITY, -1307,Town,Friendsanity: Alex 7 <3,FRIENDSANITY, -1308,Town,Friendsanity: Alex 8 <3,FRIENDSANITY, -1309,Town,Friendsanity: Alex 9 <3,FRIENDSANITY, -1310,Town,Friendsanity: Alex 10 <3,FRIENDSANITY, -1311,Town,Friendsanity: Alex 11 <3,FRIENDSANITY, -1312,Town,Friendsanity: Alex 12 <3,FRIENDSANITY, -1313,Town,Friendsanity: Alex 13 <3,FRIENDSANITY, -1314,Town,Friendsanity: Alex 14 <3,FRIENDSANITY, -1315,Beach,Friendsanity: Elliott 1 <3,FRIENDSANITY, -1316,Beach,Friendsanity: Elliott 2 <3,FRIENDSANITY, -1317,Beach,Friendsanity: Elliott 3 <3,FRIENDSANITY, -1318,Beach,Friendsanity: Elliott 4 <3,FRIENDSANITY, -1319,Beach,Friendsanity: Elliott 5 <3,FRIENDSANITY, -1320,Beach,Friendsanity: Elliott 6 <3,FRIENDSANITY, -1321,Beach,Friendsanity: Elliott 7 <3,FRIENDSANITY, -1322,Beach,Friendsanity: Elliott 8 <3,FRIENDSANITY, -1323,Beach,Friendsanity: Elliott 9 <3,FRIENDSANITY, -1324,Beach,Friendsanity: Elliott 10 <3,FRIENDSANITY, -1325,Beach,Friendsanity: Elliott 11 <3,FRIENDSANITY, -1326,Beach,Friendsanity: Elliott 12 <3,FRIENDSANITY, -1327,Beach,Friendsanity: Elliott 13 <3,FRIENDSANITY, -1328,Beach,Friendsanity: Elliott 14 <3,FRIENDSANITY, -1329,Town,Friendsanity: Harvey 1 <3,FRIENDSANITY, -1330,Town,Friendsanity: Harvey 2 <3,FRIENDSANITY, -1331,Town,Friendsanity: Harvey 3 <3,FRIENDSANITY, -1332,Town,Friendsanity: Harvey 4 <3,FRIENDSANITY, -1333,Town,Friendsanity: Harvey 5 <3,FRIENDSANITY, -1334,Town,Friendsanity: Harvey 6 <3,FRIENDSANITY, -1335,Town,Friendsanity: Harvey 7 <3,FRIENDSANITY, -1336,Town,Friendsanity: Harvey 8 <3,FRIENDSANITY, -1337,Town,Friendsanity: Harvey 9 <3,FRIENDSANITY, -1338,Town,Friendsanity: Harvey 10 <3,FRIENDSANITY, -1339,Town,Friendsanity: Harvey 11 <3,FRIENDSANITY, -1340,Town,Friendsanity: Harvey 12 <3,FRIENDSANITY, -1341,Town,Friendsanity: Harvey 13 <3,FRIENDSANITY, -1342,Town,Friendsanity: Harvey 14 <3,FRIENDSANITY, -1343,Town,Friendsanity: Sam 1 <3,FRIENDSANITY, -1344,Town,Friendsanity: Sam 2 <3,FRIENDSANITY, -1345,Town,Friendsanity: Sam 3 <3,FRIENDSANITY, -1346,Town,Friendsanity: Sam 4 <3,FRIENDSANITY, -1347,Town,Friendsanity: Sam 5 <3,FRIENDSANITY, -1348,Town,Friendsanity: Sam 6 <3,FRIENDSANITY, -1349,Town,Friendsanity: Sam 7 <3,FRIENDSANITY, -1350,Town,Friendsanity: Sam 8 <3,FRIENDSANITY, -1351,Town,Friendsanity: Sam 9 <3,FRIENDSANITY, -1352,Town,Friendsanity: Sam 10 <3,FRIENDSANITY, -1353,Town,Friendsanity: Sam 11 <3,FRIENDSANITY, -1354,Town,Friendsanity: Sam 12 <3,FRIENDSANITY, -1355,Town,Friendsanity: Sam 13 <3,FRIENDSANITY, -1356,Town,Friendsanity: Sam 14 <3,FRIENDSANITY, +1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, +1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, +1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, +1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, +1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, +1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, +1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, +1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, +1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, +1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, +1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, +1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, +1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, +1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, +1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, +1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, +1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, +1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, +1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, +1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, +1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, +1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, +1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, +1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, +1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, +1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, +1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, +1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, +1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, +1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, +1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, +1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, +1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, +1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, +1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, +1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, +1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, +1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, +1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, +1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, +1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, +1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, +1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, +1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, +1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, +1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, +1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", +1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, +1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, +1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, +1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, +1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, +1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, +1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, +1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, +1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, +1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, +1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, +1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, +1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, +1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, +1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, +1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, +1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, +1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, +1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, +1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, +1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, +1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, +1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, +1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, +1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, +1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, +1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, +1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, +1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, +1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, +1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, +1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, +1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, +1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, +1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, +1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, +1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, +1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, +1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, +1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, +1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, +1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, +1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, +1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, +1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, +1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, +1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, +1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, +1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, +1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, +1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, +1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, +1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, +1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, +1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, +1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, +1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, +1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, +1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, +1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, +1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, +1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, +1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, +1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, +1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, +1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, +1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, +1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, +1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, +1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, +1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, +1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, +1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, +1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, +1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, +1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, +1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, +1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, +1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, +1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, +1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, +1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, +1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, +1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, +1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, +1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, +1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, +1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, +1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, +1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, +1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, +1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, +1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, +1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, +1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, +1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, +1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, +1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, +1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, +1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, +1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, +1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, +1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, +1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, +1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, +1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, +1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, +1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, +1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, +1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, +1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, +1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, +1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, +1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, +1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, +1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, +1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, +1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, +1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, +1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, +1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, +1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, +1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, +1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, +1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, +1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, +1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, +1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, +1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, +1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, +1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, +1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, +1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, 1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, 1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, 1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, @@ -592,62 +592,62 @@ id,region,name,tags,mod_name 1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, 1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, 1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, -1385,Town,Friendsanity: Abigail 1 <3,FRIENDSANITY, -1386,Town,Friendsanity: Abigail 2 <3,FRIENDSANITY, -1387,Town,Friendsanity: Abigail 3 <3,FRIENDSANITY, -1388,Town,Friendsanity: Abigail 4 <3,FRIENDSANITY, -1389,Town,Friendsanity: Abigail 5 <3,FRIENDSANITY, -1390,Town,Friendsanity: Abigail 6 <3,FRIENDSANITY, -1391,Town,Friendsanity: Abigail 7 <3,FRIENDSANITY, -1392,Town,Friendsanity: Abigail 8 <3,FRIENDSANITY, -1393,Town,Friendsanity: Abigail 9 <3,FRIENDSANITY, -1394,Town,Friendsanity: Abigail 10 <3,FRIENDSANITY, -1395,Town,Friendsanity: Abigail 11 <3,FRIENDSANITY, -1396,Town,Friendsanity: Abigail 12 <3,FRIENDSANITY, -1397,Town,Friendsanity: Abigail 13 <3,FRIENDSANITY, -1398,Town,Friendsanity: Abigail 14 <3,FRIENDSANITY, -1399,Town,Friendsanity: Emily 1 <3,FRIENDSANITY, -1400,Town,Friendsanity: Emily 2 <3,FRIENDSANITY, -1401,Town,Friendsanity: Emily 3 <3,FRIENDSANITY, -1402,Town,Friendsanity: Emily 4 <3,FRIENDSANITY, -1403,Town,Friendsanity: Emily 5 <3,FRIENDSANITY, -1404,Town,Friendsanity: Emily 6 <3,FRIENDSANITY, -1405,Town,Friendsanity: Emily 7 <3,FRIENDSANITY, -1406,Town,Friendsanity: Emily 8 <3,FRIENDSANITY, -1407,Town,Friendsanity: Emily 9 <3,FRIENDSANITY, -1408,Town,Friendsanity: Emily 10 <3,FRIENDSANITY, -1409,Town,Friendsanity: Emily 11 <3,FRIENDSANITY, -1410,Town,Friendsanity: Emily 12 <3,FRIENDSANITY, -1411,Town,Friendsanity: Emily 13 <3,FRIENDSANITY, -1412,Town,Friendsanity: Emily 14 <3,FRIENDSANITY, -1413,Town,Friendsanity: Haley 1 <3,FRIENDSANITY, -1414,Town,Friendsanity: Haley 2 <3,FRIENDSANITY, -1415,Town,Friendsanity: Haley 3 <3,FRIENDSANITY, -1416,Town,Friendsanity: Haley 4 <3,FRIENDSANITY, -1417,Town,Friendsanity: Haley 5 <3,FRIENDSANITY, -1418,Town,Friendsanity: Haley 6 <3,FRIENDSANITY, -1419,Town,Friendsanity: Haley 7 <3,FRIENDSANITY, -1420,Town,Friendsanity: Haley 8 <3,FRIENDSANITY, -1421,Town,Friendsanity: Haley 9 <3,FRIENDSANITY, -1422,Town,Friendsanity: Haley 10 <3,FRIENDSANITY, -1423,Town,Friendsanity: Haley 11 <3,FRIENDSANITY, -1424,Town,Friendsanity: Haley 12 <3,FRIENDSANITY, -1425,Town,Friendsanity: Haley 13 <3,FRIENDSANITY, -1426,Town,Friendsanity: Haley 14 <3,FRIENDSANITY, -1427,Forest,Friendsanity: Leah 1 <3,FRIENDSANITY, -1428,Forest,Friendsanity: Leah 2 <3,FRIENDSANITY, -1429,Forest,Friendsanity: Leah 3 <3,FRIENDSANITY, -1430,Forest,Friendsanity: Leah 4 <3,FRIENDSANITY, -1431,Forest,Friendsanity: Leah 5 <3,FRIENDSANITY, -1432,Forest,Friendsanity: Leah 6 <3,FRIENDSANITY, -1433,Forest,Friendsanity: Leah 7 <3,FRIENDSANITY, -1434,Forest,Friendsanity: Leah 8 <3,FRIENDSANITY, -1435,Forest,Friendsanity: Leah 9 <3,FRIENDSANITY, -1436,Forest,Friendsanity: Leah 10 <3,FRIENDSANITY, -1437,Forest,Friendsanity: Leah 11 <3,FRIENDSANITY, -1438,Forest,Friendsanity: Leah 12 <3,FRIENDSANITY, -1439,Forest,Friendsanity: Leah 13 <3,FRIENDSANITY, -1440,Forest,Friendsanity: Leah 14 <3,FRIENDSANITY, +1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, +1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, +1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, +1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, +1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, +1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, +1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, +1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, +1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, +1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, +1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, +1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, +1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, +1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, +1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, +1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, +1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, +1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, +1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, +1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, +1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, +1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, +1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, +1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, +1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, +1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, +1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, +1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, +1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, +1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, +1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, +1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, +1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, +1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, +1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, +1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, +1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, +1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, +1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, +1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, +1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, +1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, +1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, +1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, +1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, +1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, +1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, +1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, +1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, +1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, +1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, +1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, +1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, +1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, +1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, +1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, 1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, 1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, 1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, @@ -662,40 +662,40 @@ id,region,name,tags,mod_name 1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, 1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, 1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, -1455,Town,Friendsanity: Penny 1 <3,FRIENDSANITY, -1456,Town,Friendsanity: Penny 2 <3,FRIENDSANITY, -1457,Town,Friendsanity: Penny 3 <3,FRIENDSANITY, -1458,Town,Friendsanity: Penny 4 <3,FRIENDSANITY, -1459,Town,Friendsanity: Penny 5 <3,FRIENDSANITY, -1460,Town,Friendsanity: Penny 6 <3,FRIENDSANITY, -1461,Town,Friendsanity: Penny 7 <3,FRIENDSANITY, -1462,Town,Friendsanity: Penny 8 <3,FRIENDSANITY, -1463,Town,Friendsanity: Penny 9 <3,FRIENDSANITY, -1464,Town,Friendsanity: Penny 10 <3,FRIENDSANITY, -1465,Town,Friendsanity: Penny 11 <3,FRIENDSANITY, -1466,Town,Friendsanity: Penny 12 <3,FRIENDSANITY, -1467,Town,Friendsanity: Penny 13 <3,FRIENDSANITY, -1468,Town,Friendsanity: Penny 14 <3,FRIENDSANITY, -1469,Town,Friendsanity: Caroline 1 <3,FRIENDSANITY, -1470,Town,Friendsanity: Caroline 2 <3,FRIENDSANITY, -1471,Town,Friendsanity: Caroline 3 <3,FRIENDSANITY, -1472,Town,Friendsanity: Caroline 4 <3,FRIENDSANITY, -1473,Town,Friendsanity: Caroline 5 <3,FRIENDSANITY, -1474,Town,Friendsanity: Caroline 6 <3,FRIENDSANITY, -1475,Town,Friendsanity: Caroline 7 <3,FRIENDSANITY, -1476,Town,Friendsanity: Caroline 8 <3,FRIENDSANITY, -1477,Town,Friendsanity: Caroline 9 <3,FRIENDSANITY, -1478,Town,Friendsanity: Caroline 10 <3,FRIENDSANITY, -1480,Town,Friendsanity: Clint 1 <3,FRIENDSANITY, -1481,Town,Friendsanity: Clint 2 <3,FRIENDSANITY, -1482,Town,Friendsanity: Clint 3 <3,FRIENDSANITY, -1483,Town,Friendsanity: Clint 4 <3,FRIENDSANITY, -1484,Town,Friendsanity: Clint 5 <3,FRIENDSANITY, -1485,Town,Friendsanity: Clint 6 <3,FRIENDSANITY, -1486,Town,Friendsanity: Clint 7 <3,FRIENDSANITY, -1487,Town,Friendsanity: Clint 8 <3,FRIENDSANITY, -1488,Town,Friendsanity: Clint 9 <3,FRIENDSANITY, -1489,Town,Friendsanity: Clint 10 <3,FRIENDSANITY, +1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, +1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, +1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, +1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, +1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, +1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, +1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, +1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, +1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, +1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, +1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, +1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, +1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, +1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, +1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, +1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, +1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, +1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, +1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, +1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, +1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, +1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, +1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, +1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, +1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, +1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, +1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, +1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, +1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, +1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, +1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, +1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, +1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, +1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, 1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, 1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, 1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, @@ -706,46 +706,46 @@ id,region,name,tags,mod_name 1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, 1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, 1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, -1502,The Mines,Friendsanity: Dwarf 1 <3,FRIENDSANITY, -1503,The Mines,Friendsanity: Dwarf 2 <3,FRIENDSANITY, -1504,The Mines,Friendsanity: Dwarf 3 <3,FRIENDSANITY, -1505,The Mines,Friendsanity: Dwarf 4 <3,FRIENDSANITY, -1506,The Mines,Friendsanity: Dwarf 5 <3,FRIENDSANITY, -1507,The Mines,Friendsanity: Dwarf 6 <3,FRIENDSANITY, -1508,The Mines,Friendsanity: Dwarf 7 <3,FRIENDSANITY, -1509,The Mines,Friendsanity: Dwarf 8 <3,FRIENDSANITY, -1510,The Mines,Friendsanity: Dwarf 9 <3,FRIENDSANITY, -1511,The Mines,Friendsanity: Dwarf 10 <3,FRIENDSANITY, -1513,Town,Friendsanity: Evelyn 1 <3,FRIENDSANITY, -1514,Town,Friendsanity: Evelyn 2 <3,FRIENDSANITY, -1515,Town,Friendsanity: Evelyn 3 <3,FRIENDSANITY, -1516,Town,Friendsanity: Evelyn 4 <3,FRIENDSANITY, -1517,Town,Friendsanity: Evelyn 5 <3,FRIENDSANITY, -1518,Town,Friendsanity: Evelyn 6 <3,FRIENDSANITY, -1519,Town,Friendsanity: Evelyn 7 <3,FRIENDSANITY, -1520,Town,Friendsanity: Evelyn 8 <3,FRIENDSANITY, -1521,Town,Friendsanity: Evelyn 9 <3,FRIENDSANITY, -1522,Town,Friendsanity: Evelyn 10 <3,FRIENDSANITY, -1524,Town,Friendsanity: George 1 <3,FRIENDSANITY, -1525,Town,Friendsanity: George 2 <3,FRIENDSANITY, -1526,Town,Friendsanity: George 3 <3,FRIENDSANITY, -1527,Town,Friendsanity: George 4 <3,FRIENDSANITY, -1528,Town,Friendsanity: George 5 <3,FRIENDSANITY, -1529,Town,Friendsanity: George 6 <3,FRIENDSANITY, -1530,Town,Friendsanity: George 7 <3,FRIENDSANITY, -1531,Town,Friendsanity: George 8 <3,FRIENDSANITY, -1532,Town,Friendsanity: George 9 <3,FRIENDSANITY, -1533,Town,Friendsanity: George 10 <3,FRIENDSANITY, -1535,Town,Friendsanity: Gus 1 <3,FRIENDSANITY, -1536,Town,Friendsanity: Gus 2 <3,FRIENDSANITY, -1537,Town,Friendsanity: Gus 3 <3,FRIENDSANITY, -1538,Town,Friendsanity: Gus 4 <3,FRIENDSANITY, -1539,Town,Friendsanity: Gus 5 <3,FRIENDSANITY, -1540,Town,Friendsanity: Gus 6 <3,FRIENDSANITY, -1541,Town,Friendsanity: Gus 7 <3,FRIENDSANITY, -1542,Town,Friendsanity: Gus 8 <3,FRIENDSANITY, -1543,Town,Friendsanity: Gus 9 <3,FRIENDSANITY, -1544,Town,Friendsanity: Gus 10 <3,FRIENDSANITY, +1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, +1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, +1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, +1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, +1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, +1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, +1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, +1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, +1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, +1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, +1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, +1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, +1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, +1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, +1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, +1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, +1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, +1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, +1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, +1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, +1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, +1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, +1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, +1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, +1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, +1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, +1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, +1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, +1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, +1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, +1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, +1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, +1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, +1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, +1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, +1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, +1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, +1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, +1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, +1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, 1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, 1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, 1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, @@ -756,26 +756,26 @@ id,region,name,tags,mod_name 1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, 1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, 1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, -1557,Town,Friendsanity: Jodi 1 <3,FRIENDSANITY, -1558,Town,Friendsanity: Jodi 2 <3,FRIENDSANITY, -1559,Town,Friendsanity: Jodi 3 <3,FRIENDSANITY, -1560,Town,Friendsanity: Jodi 4 <3,FRIENDSANITY, -1561,Town,Friendsanity: Jodi 5 <3,FRIENDSANITY, -1562,Town,Friendsanity: Jodi 6 <3,FRIENDSANITY, -1563,Town,Friendsanity: Jodi 7 <3,FRIENDSANITY, -1564,Town,Friendsanity: Jodi 8 <3,FRIENDSANITY, -1565,Town,Friendsanity: Jodi 9 <3,FRIENDSANITY, -1566,Town,Friendsanity: Jodi 10 <3,FRIENDSANITY, -1568,Town,Friendsanity: Kent 1 <3,FRIENDSANITY, -1569,Town,Friendsanity: Kent 2 <3,FRIENDSANITY, -1570,Town,Friendsanity: Kent 3 <3,FRIENDSANITY, -1571,Town,Friendsanity: Kent 4 <3,FRIENDSANITY, -1572,Town,Friendsanity: Kent 5 <3,FRIENDSANITY, -1573,Town,Friendsanity: Kent 6 <3,FRIENDSANITY, -1574,Town,Friendsanity: Kent 7 <3,FRIENDSANITY, -1575,Town,Friendsanity: Kent 8 <3,FRIENDSANITY, -1576,Town,Friendsanity: Kent 9 <3,FRIENDSANITY, -1577,Town,Friendsanity: Kent 10 <3,FRIENDSANITY, +1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, +1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, +1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, +1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, +1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, +1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, +1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, +1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, +1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, +1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, +1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, +1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, +1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, +1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, +1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, +1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, +1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, +1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, +1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, +1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, 1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, 1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, 1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, @@ -796,26 +796,26 @@ id,region,name,tags,mod_name 1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", 1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", 1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", -1601,Town,Friendsanity: Lewis 1 <3,FRIENDSANITY, -1602,Town,Friendsanity: Lewis 2 <3,FRIENDSANITY, -1603,Town,Friendsanity: Lewis 3 <3,FRIENDSANITY, -1604,Town,Friendsanity: Lewis 4 <3,FRIENDSANITY, -1605,Town,Friendsanity: Lewis 5 <3,FRIENDSANITY, -1606,Town,Friendsanity: Lewis 6 <3,FRIENDSANITY, -1607,Town,Friendsanity: Lewis 7 <3,FRIENDSANITY, -1608,Town,Friendsanity: Lewis 8 <3,FRIENDSANITY, -1609,Town,Friendsanity: Lewis 9 <3,FRIENDSANITY, -1610,Town,Friendsanity: Lewis 10 <3,FRIENDSANITY, -1612,Mountain,Friendsanity: Linus 1 <3,FRIENDSANITY, -1613,Mountain,Friendsanity: Linus 2 <3,FRIENDSANITY, -1614,Mountain,Friendsanity: Linus 3 <3,FRIENDSANITY, -1615,Mountain,Friendsanity: Linus 4 <3,FRIENDSANITY, -1616,Mountain,Friendsanity: Linus 5 <3,FRIENDSANITY, -1617,Mountain,Friendsanity: Linus 6 <3,FRIENDSANITY, -1618,Mountain,Friendsanity: Linus 7 <3,FRIENDSANITY, -1619,Mountain,Friendsanity: Linus 8 <3,FRIENDSANITY, -1620,Mountain,Friendsanity: Linus 9 <3,FRIENDSANITY, -1621,Mountain,Friendsanity: Linus 10 <3,FRIENDSANITY, +1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, +1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, +1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, +1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, +1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, +1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, +1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, +1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, +1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, +1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, +1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, +1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, +1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, +1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, +1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, +1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, +1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, +1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, +1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, +1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, 1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, 1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, 1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, @@ -826,26 +826,26 @@ id,region,name,tags,mod_name 1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, 1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, 1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, -1634,Town,Friendsanity: Pam 1 <3,FRIENDSANITY, -1635,Town,Friendsanity: Pam 2 <3,FRIENDSANITY, -1636,Town,Friendsanity: Pam 3 <3,FRIENDSANITY, -1637,Town,Friendsanity: Pam 4 <3,FRIENDSANITY, -1638,Town,Friendsanity: Pam 5 <3,FRIENDSANITY, -1639,Town,Friendsanity: Pam 6 <3,FRIENDSANITY, -1640,Town,Friendsanity: Pam 7 <3,FRIENDSANITY, -1641,Town,Friendsanity: Pam 8 <3,FRIENDSANITY, -1642,Town,Friendsanity: Pam 9 <3,FRIENDSANITY, -1643,Town,Friendsanity: Pam 10 <3,FRIENDSANITY, -1645,Town,Friendsanity: Pierre 1 <3,FRIENDSANITY, -1646,Town,Friendsanity: Pierre 2 <3,FRIENDSANITY, -1647,Town,Friendsanity: Pierre 3 <3,FRIENDSANITY, -1648,Town,Friendsanity: Pierre 4 <3,FRIENDSANITY, -1649,Town,Friendsanity: Pierre 5 <3,FRIENDSANITY, -1650,Town,Friendsanity: Pierre 6 <3,FRIENDSANITY, -1651,Town,Friendsanity: Pierre 7 <3,FRIENDSANITY, -1652,Town,Friendsanity: Pierre 8 <3,FRIENDSANITY, -1653,Town,Friendsanity: Pierre 9 <3,FRIENDSANITY, -1654,Town,Friendsanity: Pierre 10 <3,FRIENDSANITY, +1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, +1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, +1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, +1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, +1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, +1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, +1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, +1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, +1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, +1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, +1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, +1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, +1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, +1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, +1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, +1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, +1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, +1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, +1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, +1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, 1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, 1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, 1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, @@ -866,55 +866,55 @@ id,region,name,tags,mod_name 1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, 1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, 1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, -1678,Town,Friendsanity: Vincent 1 <3,FRIENDSANITY, -1679,Town,Friendsanity: Vincent 2 <3,FRIENDSANITY, -1680,Town,Friendsanity: Vincent 3 <3,FRIENDSANITY, -1681,Town,Friendsanity: Vincent 4 <3,FRIENDSANITY, -1682,Town,Friendsanity: Vincent 5 <3,FRIENDSANITY, -1683,Town,Friendsanity: Vincent 6 <3,FRIENDSANITY, -1684,Town,Friendsanity: Vincent 7 <3,FRIENDSANITY, -1685,Town,Friendsanity: Vincent 8 <3,FRIENDSANITY, -1686,Town,Friendsanity: Vincent 9 <3,FRIENDSANITY, -1687,Town,Friendsanity: Vincent 10 <3,FRIENDSANITY, -1689,Beach,Friendsanity: Willy 1 <3,FRIENDSANITY, -1690,Beach,Friendsanity: Willy 2 <3,FRIENDSANITY, -1691,Beach,Friendsanity: Willy 3 <3,FRIENDSANITY, -1692,Beach,Friendsanity: Willy 4 <3,FRIENDSANITY, -1693,Beach,Friendsanity: Willy 5 <3,FRIENDSANITY, -1694,Beach,Friendsanity: Willy 6 <3,FRIENDSANITY, -1695,Beach,Friendsanity: Willy 7 <3,FRIENDSANITY, -1696,Beach,Friendsanity: Willy 8 <3,FRIENDSANITY, -1697,Beach,Friendsanity: Willy 9 <3,FRIENDSANITY, -1698,Beach,Friendsanity: Willy 10 <3,FRIENDSANITY, -1700,Forest,Friendsanity: Wizard 1 <3,FRIENDSANITY, -1701,Forest,Friendsanity: Wizard 2 <3,FRIENDSANITY, -1702,Forest,Friendsanity: Wizard 3 <3,FRIENDSANITY, -1703,Forest,Friendsanity: Wizard 4 <3,FRIENDSANITY, -1704,Forest,Friendsanity: Wizard 5 <3,FRIENDSANITY, -1705,Forest,Friendsanity: Wizard 6 <3,FRIENDSANITY, -1706,Forest,Friendsanity: Wizard 7 <3,FRIENDSANITY, -1707,Forest,Friendsanity: Wizard 8 <3,FRIENDSANITY, -1708,Forest,Friendsanity: Wizard 9 <3,FRIENDSANITY, -1709,Forest,Friendsanity: Wizard 10 <3,FRIENDSANITY, +1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, +1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, +1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, +1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, +1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, +1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, +1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, +1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, +1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, +1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, +1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, +1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, +1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, +1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, +1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, +1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, +1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, +1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, +1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, +1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, +1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, +1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, +1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, +1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, +1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, +1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, +1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, +1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, +1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, +1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, 1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, 1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, 1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, 1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, 1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, -1715,Farm,Friendsanity: Friend 1 <3,FRIENDSANITY, -1716,Farm,Friendsanity: Friend 2 <3,FRIENDSANITY, -1717,Farm,Friendsanity: Friend 3 <3,FRIENDSANITY, -1718,Farm,Friendsanity: Friend 4 <3,FRIENDSANITY, -1719,Farm,Friendsanity: Friend 5 <3,FRIENDSANITY, -1720,Farm,Friendsanity: Friend 6 <3,FRIENDSANITY, -1721,Farm,Friendsanity: Friend 7 <3,FRIENDSANITY, -1722,Farm,Friendsanity: Friend 8 <3,FRIENDSANITY, -1723,Farm,Friendsanity: Suitor 9 <3,FRIENDSANITY, -1724,Farm,Friendsanity: Suitor 10 <3,FRIENDSANITY, -1725,Farm,Friendsanity: Spouse 11 <3,FRIENDSANITY, -1726,Farm,Friendsanity: Spouse 12 <3,FRIENDSANITY, -1727,Farm,Friendsanity: Spouse 13 <3,FRIENDSANITY, -1728,Farm,Friendsanity: Spouse 14 <3,FRIENDSANITY, +1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, +1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, +1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, +1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, +1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, +1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, +1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, +1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, +1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, +1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, +1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, +1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, +1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, +1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, 2001,Town,Egg Hunt Victory,FESTIVAL, 2002,Town,Egg Festival: Strawberry Seeds,FESTIVAL, 2003,Forest,Dance with someone,FESTIVAL, diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index b430832cf68d..8e8f9cf537bd 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -16,7 +16,6 @@ from .mods.logic.buildings import get_modded_building_rules from .mods.logic.quests import get_modded_quest_rules from .mods.logic.special_orders import get_modded_special_orders_rules -from .mods.logic.skullcavernelevator import has_skull_cavern_elevator_to_floor from .mods.mod_data import ModNames from .mods.logic import magic, skills from .options import Museumsanity, SeasonRandomization, StardewValleyOptions, BuildingProgression, SkillProgression, ToolProgression, Friendsanity, Cropsanity, \ @@ -479,8 +478,8 @@ def __post_init__(self): FestivalCheck.mermaid_pearl: self.has_season(Season.winter) & self.can_reach_region(Region.beach), FestivalCheck.cone_hat: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(2500), FestivalCheck.iridium_fireplace: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(15000), - FestivalCheck.rarecrow_7: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_donate_museum_artifacts(20), - FestivalCheck.rarecrow_8: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_donate_museum_items(40), + FestivalCheck.rarecrow_7: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_find_museum_artifacts(20), + FestivalCheck.rarecrow_8: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_find_museum_items(40), FestivalCheck.lupini_red_eagle: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200), FestivalCheck.lupini_portrait_mermaid: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200), FestivalCheck.lupini_solar_kingdom: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200), @@ -1358,21 +1357,6 @@ def has_year_three(self) -> StardewRule: def can_speak_dwarf(self) -> StardewRule: return self.received("Dwarvish Translation Guide") - def can_donate_museum_item(self, item: MuseumItem) -> StardewRule: - key = f"can_donate_museum_item {item.name}" - if key not in self.cached_rules: - self.cached_rules[key] = self.can_reach_region(Region.museum) & self.can_find_museum_item(item) - return self.cached_rules[key] - - def can_donate_museum_items(self, number: int) -> StardewRule: - return self.can_reach_region(Region.museum) & self.can_find_museum_items(number) - - def can_donate_museum_artifacts(self, number: int) -> StardewRule: - return self.can_reach_region(Region.museum) & self.can_find_museum_artifacts(number) - - def can_donate_museum_minerals(self, number: int) -> StardewRule: - return self.can_reach_region(Region.museum) & self.can_find_museum_minerals(number) - def can_find_museum_item(self, item: MuseumItem) -> StardewRule: key = f"can_find_museum_item {item.name}" if key not in self.cached_rules: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 5eae92addc0a..7edeff1a8e25 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -472,7 +472,7 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi if museum_location.name in all_location_names: donation_name = museum_location.name[len(museum_prefix):] required_detectors = counter * 5 // number_donations - rule = logic.can_donate_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", + rule = logic.can_find_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", required_detectors) MultiWorldRules.set_rule(multiworld.get_location(museum_location.name, player), rule.simplify()) @@ -488,21 +488,21 @@ def set_museum_milestone_rule(logic: StardewLogic, multiworld: MultiWorld, museu metal_detector = "Traveling Merchant Metal Detector" rule = None if milestone_name.endswith(donations_suffix): - rule = get_museum_item_count_rule(logic, donations_suffix, milestone_name, all_museum_items, logic.can_donate_museum_items) + rule = get_museum_item_count_rule(logic, donations_suffix, milestone_name, all_museum_items, logic.can_find_museum_items) elif milestone_name.endswith(minerals_suffix): - rule = get_museum_item_count_rule(logic, minerals_suffix, milestone_name, all_museum_minerals, logic.can_donate_museum_minerals) + rule = get_museum_item_count_rule(logic, minerals_suffix, milestone_name, all_museum_minerals, logic.can_find_museum_minerals) elif milestone_name.endswith(artifacts_suffix): - rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_museum_artifacts, logic.can_donate_museum_artifacts) + rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_museum_artifacts, logic.can_find_museum_artifacts) elif milestone_name == "Dwarf Scrolls": - rule = And([logic.can_donate_museum_item(item) for item in dwarf_scrolls]) & logic.received(metal_detector, 4) + rule = And([logic.can_find_museum_item(item) for item in dwarf_scrolls]) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Front": - rule = And([logic.can_donate_museum_item(item) for item in skeleton_front]) & logic.received(metal_detector, 4) + rule = And([logic.can_find_museum_item(item) for item in skeleton_front]) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Middle": - rule = And([logic.can_donate_museum_item(item) for item in skeleton_middle]) & logic.received(metal_detector, 4) + rule = And([logic.can_find_museum_item(item) for item in skeleton_middle]) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Back": - rule = And([logic.can_donate_museum_item(item) for item in skeleton_back]) & logic.received(metal_detector, 4) + rule = And([logic.can_find_museum_item(item) for item in skeleton_back]) & logic.received(metal_detector, 4) elif milestone_name == "Ancient Seed": - rule = logic.can_donate_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) + rule = logic.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) if rule is None: return MultiWorldRules.set_rule(multiworld.get_location(museum_milestone.name, player), rule.simplify()) From 91b6aff0fdd20a44044f1c816153f0ed458afa2e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 10:37:31 +0200 Subject: [PATCH 020/482] - Add regions for festivals --- worlds/stardew_valley/data/locations.csv | 58 ++++++++-------- worlds/stardew_valley/logic.py | 68 ++++++++++--------- worlds/stardew_valley/regions.py | 30 ++++++-- worlds/stardew_valley/rules.py | 20 ++++++ .../stardew_valley/strings/entrance_names.py | 9 +++ worlds/stardew_valley/strings/region_names.py | 9 +++ 6 files changed, 131 insertions(+), 63 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 23c91c191a38..f5328264bd7a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -917,34 +917,36 @@ id,region,name,tags,mod_name 1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, 2001,Town,Egg Hunt Victory,FESTIVAL, 2002,Town,Egg Festival: Strawberry Seeds,FESTIVAL, -2003,Forest,Dance with someone,FESTIVAL, -2004,Forest,Rarecrow #5 (Woman),FESTIVAL, -2005,Beach,Luau Soup,FESTIVAL, -2006,Beach,Dance of the Moonlight Jellies,FESTIVAL, -2007,Town,Smashing Stone,FESTIVAL, -2008,Town,Grange Display,FESTIVAL, -2009,Town,Rarecrow #1 (Turnip Head),FESTIVAL, -2010,Town,Fair Stardrop,FESTIVAL, -2011,Town,Spirit's Eve Maze,FESTIVAL, -2012,Town,Rarecrow #2 (Witch),FESTIVAL, -2013,Forest,Win Fishing Competition,FESTIVAL, -2014,Forest,Rarecrow #4 (Snowman),FESTIVAL, -2015,Beach,Mermaid Pearl,FESTIVAL, -2016,Beach,Cone Hat,FESTIVAL_HARD, -2017,Beach,Iridium Fireplace,FESTIVAL_HARD, -2018,Beach,Rarecrow #7 (Tanuki),FESTIVAL, -2019,Beach,Rarecrow #8 (Tribal Mask),FESTIVAL, -2020,Beach,Lupini: Red Eagle,FESTIVAL, -2021,Beach,Lupini: Portrait Of A Mermaid,FESTIVAL, -2022,Beach,Lupini: Solar Kingdom,FESTIVAL, -2023,Beach,Lupini: Clouds,FESTIVAL_HARD, -2024,Beach,Lupini: 1000 Years From Now,FESTIVAL_HARD, -2025,Beach,Lupini: Three Trees,FESTIVAL_HARD, -2026,Beach,Lupini: The Serpent,FESTIVAL_HARD, -2027,Beach,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, -2028,Beach,Lupini: Land Of Clay,FESTIVAL_HARD, -2029,Town,Secret Santa,FESTIVAL, -2030,Town,The Legend of the Winter Star,FESTIVAL, +2001,Egg Festival,Egg Hunt Victory,FESTIVAL, +2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, +2003,Flower Dance,Dance with someone,FESTIVAL, +2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, +2005,Luau,Luau Soup,FESTIVAL, +2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, +2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, +2008,Stardew Valley Fair,Grange Display,FESTIVAL, +2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, +2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, +2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, +2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, +2013,Festival of Ice,Win Fishing Competition,FESTIVAL, +2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, +2015,Night Market,Mermaid Pearl,FESTIVAL, +2016,Night Market,Cone Hat,FESTIVAL_HARD, +2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, +2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, +2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, +2020,Night Market,Lupini: Red Eagle,FESTIVAL, +2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, +2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, +2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, +2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, +2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, +2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, +2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, +2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, +2029,Feast of the Winter Star,Secret Santa,FESTIVAL, +2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, 2031,Farm,Collect All Rarecrows,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index 8e8f9cf537bd..47cdafdcb1d2 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -461,36 +461,36 @@ def __post_init__(self): self.quest_rules.update(get_modded_quest_rules(self, self.options.mods)) self.festival_rules.update({ - FestivalCheck.egg_hunt: self.has_season(Season.spring) & self.can_reach_region(Region.town) & self.can_win_egg_hunt(), - FestivalCheck.strawberry_seeds: self.has_season(Season.spring) & self.can_reach_region(Region.town) & self.can_spend_money(1000), - FestivalCheck.dance: self.has_season(Season.spring) & self.can_reach_region(Region.forest) & self.has_relationship(Generic.bachelor, 4), - FestivalCheck.rarecrow_5: self.has_season(Season.spring) & self.can_reach_region(Region.forest) & self.can_spend_money(2500), - FestivalCheck.luau_soup: self.has_season(Season.summer) & self.can_reach_region(Region.beach) & self.can_succeed_luau_soup(), - FestivalCheck.moonlight_jellies: self.has_season(Season.summer) & self.can_reach_region(Region.beach), - FestivalCheck.smashing_stone: self.has_season(Season.fall) & self.can_reach_region(Region.town), - FestivalCheck.grange_display: self.has_season(Season.fall) & self.can_reach_region(Region.town) & self.can_succeed_grange_display(), - FestivalCheck.rarecrow_1: self.has_season(Season.fall) & self.can_reach_region(Region.town), # only cost star tokens - FestivalCheck.fair_stardrop: self.has_season(Season.fall) & self.can_reach_region(Region.town), # only cost star tokens - FestivalCheck.spirit_eve_maze: self.has_season(Season.fall) & self.can_reach_region(Region.town), - FestivalCheck.rarecrow_2: self.has_season(Season.fall) & self.can_reach_region(Region.town) & self.can_spend_money(5000), - FestivalCheck.fishing_competition: self.has_season(Season.winter) & self.can_reach_region(Region.forest) & self.can_win_fishing_competition(), - FestivalCheck.rarecrow_4: self.has_season(Season.winter) & self.can_reach_region(Region.forest) & self.can_spend_money(5000), - FestivalCheck.mermaid_pearl: self.has_season(Season.winter) & self.can_reach_region(Region.beach), - FestivalCheck.cone_hat: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(2500), - FestivalCheck.iridium_fireplace: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(15000), - FestivalCheck.rarecrow_7: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_find_museum_artifacts(20), - FestivalCheck.rarecrow_8: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_find_museum_items(40), - FestivalCheck.lupini_red_eagle: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200), - FestivalCheck.lupini_portrait_mermaid: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200), - FestivalCheck.lupini_solar_kingdom: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200), - FestivalCheck.lupini_clouds: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.has_year_two() & self.can_spend_money(1200), - FestivalCheck.lupini_1000_years: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.has_year_two() & self.can_spend_money(1200), - FestivalCheck.lupini_three_trees: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.has_year_two() & self.can_spend_money(1200), - FestivalCheck.lupini_the_serpent: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.has_year_three() & self.can_spend_money(1200), - FestivalCheck.lupini_tropical_fish: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.has_year_three() & self.can_spend_money(1200), - FestivalCheck.lupini_land_of_clay: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.has_year_three() & self.can_spend_money(1200), - FestivalCheck.secret_santa: self.has_season(Season.winter) & self.can_reach_region(Region.town) & self.has_any_universal_love(), - FestivalCheck.legend_of_the_winter_star: self.has_season(Season.winter) & self.can_reach_region(Region.town), + FestivalCheck.egg_hunt: self.can_win_egg_hunt(), + FestivalCheck.strawberry_seeds: self.can_spend_money(1000), + FestivalCheck.dance: self.has_relationship(Generic.bachelor, 4), + FestivalCheck.rarecrow_5: self.can_spend_money(2500), + FestivalCheck.luau_soup: self.can_succeed_luau_soup(), + FestivalCheck.moonlight_jellies: True_(), + FestivalCheck.smashing_stone: True_(), + FestivalCheck.grange_display: self.can_succeed_grange_display(), + FestivalCheck.rarecrow_1: True_(), # only cost star tokens + FestivalCheck.fair_stardrop: True_(), # only cost star tokens + FestivalCheck.spirit_eve_maze: True_(), + FestivalCheck.rarecrow_2: self.can_spend_money(5000), + FestivalCheck.fishing_competition: self.can_win_fishing_competition(), + FestivalCheck.rarecrow_4: self.can_spend_money(5000), + FestivalCheck.mermaid_pearl: self.has(Forageable.secret_note), + FestivalCheck.cone_hat: self.can_spend_money(2500), + FestivalCheck.iridium_fireplace: self.can_spend_money(15000), + FestivalCheck.rarecrow_7: self.can_spend_money(5000) & self.can_donate_museum_artifacts(20), + FestivalCheck.rarecrow_8: self.can_spend_money(5000) & self.can_donate_museum_items(40), + FestivalCheck.lupini_red_eagle: self.can_spend_money(1200), + FestivalCheck.lupini_portrait_mermaid: self.can_spend_money(1200), + FestivalCheck.lupini_solar_kingdom: self.can_spend_money(1200), + FestivalCheck.lupini_clouds: self.has_year_two() & self.can_spend_money(1200), + FestivalCheck.lupini_1000_years: self.has_year_two() & self.can_spend_money(1200), + FestivalCheck.lupini_three_trees: self.has_year_two() & self.can_spend_money(1200), + FestivalCheck.lupini_the_serpent: self.has_year_three() & self.can_spend_money(1200), + FestivalCheck.lupini_tropical_fish: self.has_year_three() & self.can_spend_money(1200), + FestivalCheck.lupini_land_of_clay: self.has_year_three() & self.can_spend_money(1200), + FestivalCheck.secret_santa: self.has_any_universal_love(), + FestivalCheck.legend_of_the_winter_star: True_(), FestivalCheck.all_rarecrows: self.can_reach_region(Region.farm) & self.has_all_rarecrows(), }) @@ -813,7 +813,7 @@ def has_max_fishing(self) -> StardewRule: return self.has_max_fishing_rod() & skill_rule def can_fish_chests(self) -> StardewRule: - skill_rule = self.has_skill_level(Skill.fishing, 4) + skill_rule = self.has_skill_level(Skill.fishing, 6) return self.has_max_fishing_rod() & skill_rule def can_buy_seed(self, seed: SeedItem) -> StardewRule: @@ -1370,6 +1370,9 @@ def can_find_museum_item(self, item: MuseumItem) -> StardewRule: self.cached_rules[key] = pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule return self.cached_rules[key] + def can_donate_museum_artifacts(self, number: int) -> StardewRule: + return self.can_reach_region(Region.museum) & self.can_find_museum_artifacts(number) + def can_find_museum_artifacts(self, number: int) -> StardewRule: rules = [] for artifact in all_museum_artifacts: @@ -1384,6 +1387,9 @@ def can_find_museum_minerals(self, number: int) -> StardewRule: return Count(number, rules) + def can_donate_museum_items(self, number: int) -> StardewRule: + return self.can_reach_region(Region.museum) & self.can_find_museum_items(number) + def can_find_museum_items(self, number: int) -> StardewRule: rules = [] for donation in all_museum_items: diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 7bc13911afcb..4768abca874a 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -31,7 +31,8 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: [Entrance.forest_to_town, Entrance.enter_secret_woods, Entrance.forest_to_wizard_tower, Entrance.forest_to_marnie_ranch, Entrance.forest_to_leah_cottage, Entrance.forest_to_sewer, - Entrance.buy_from_traveling_merchant]), + Entrance.buy_from_traveling_merchant, + Entrance.attend_flower_dance, Entrance.attend_festival_of_ice]), RegionData(Region.traveling_cart, [Entrance.buy_from_traveling_merchant_sunday, Entrance.buy_from_traveling_merchant_monday, Entrance.buy_from_traveling_merchant_tuesday, @@ -65,9 +66,12 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: Entrance.town_to_sam_house, Entrance.town_to_haley_house, Entrance.town_to_sewer, Entrance.town_to_clint_blacksmith, Entrance.town_to_museum, - Entrance.town_to_jojamart]), - RegionData(Region.beach, - [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, Entrance.fishing]), + Entrance.town_to_jojamart, + Entrance.attend_egg_festival, Entrance.attend_fair, + Entrance.attend_spirit_eve, Entrance.attend_winter_star]), + RegionData(Region.beach, [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, + Entrance.fishing, + Entrance.attend_luau, Entrance.attend_moonlight_jellies, Entrance.attend_night_market]), RegionData(Region.fishing), RegionData(Region.railroad, [Entrance.enter_bathhouse_entrance, Entrance.enter_witch_warp_cave]), RegionData(Region.ranch), @@ -205,6 +209,15 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.mines_floor_110, [Entrance.dig_to_mines_floor_115]), RegionData(Region.mines_floor_115, [Entrance.dig_to_mines_floor_120]), RegionData(Region.mines_floor_120), + RegionData(Region.egg_festival), + RegionData(Region.flower_dance), + RegionData(Region.luau), + RegionData(Region.moonlight_jellies), + RegionData(Region.fair), + RegionData(Region.spirit_eve), + RegionData(Region.festival_of_ice), + RegionData(Region.night_market), + RegionData(Region.winter_star), ] # Exists and where they lead @@ -411,6 +424,15 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.parrot_express_dig_site_to_volcano, Region.island_north), ConnectionData(Entrance.parrot_express_docks_to_volcano, Region.island_north), ConnectionData(Entrance.parrot_express_jungle_to_volcano, Region.island_north), + ConnectionData(Entrance.attend_egg_festival, Region.egg_festival), + ConnectionData(Entrance.attend_flower_dance, Region.flower_dance), + ConnectionData(Entrance.attend_luau, Region.luau), + ConnectionData(Entrance.attend_moonlight_jellies, Region.moonlight_jellies), + ConnectionData(Entrance.attend_fair, Region.fair), + ConnectionData(Entrance.attend_spirit_eve, Region.spirit_eve), + ConnectionData(Entrance.attend_festival_of_ice, Region.festival_of_ice), + ConnectionData(Entrance.attend_night_market, Region.night_market), + ConnectionData(Entrance.attend_winter_star, Region.winter_star), ] diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 7edeff1a8e25..91d5a3a8d469 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -22,6 +22,7 @@ from .strings.craftable_names import Craftable from .strings.material_names import Material from .strings.metal_names import MetalBar +from .strings.season_names import Season from .strings.skill_names import ModSkill, Skill from .strings.tool_names import Tool, ToolMaterial from .strings.villager_names import NPC, ModNPC @@ -199,6 +200,10 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), ((logic.has_rusty_key() & logic.can_reach_region(Region.railroad) & logic.can_meet(NPC.krobus) | magic.can_blink(logic)).simplify())) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), + logic.received("Club Card")) + + set_festival_entrance_rules(logic, multiworld, player) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), logic.has_relationship(NPC.harvey, 2)) @@ -259,6 +264,21 @@ def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, i MultiWorldRules.set_rule(material_entrance, upgrade_rule.simplify()) +def set_festival_entrance_rules(logic, multiworld, player): + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_egg_festival, player), logic.has_season(Season.spring)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_flower_dance, player), logic.has_season(Season.spring)) + + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_luau, player), logic.has_season(Season.summer)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_moonlight_jellies, player), logic.has_season(Season.summer)) + + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_fair, player), logic.has_season(Season.fall)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_spirit_eve, player), logic.has_season(Season.fall)) + + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_festival_of_ice, player), logic.has_season(Season.winter)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_night_market, player), logic.has_season(Season.winter)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_winter_star, player), logic.has_season(Season.winter)) + + def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): set_island_entrances_rules(logic, multiworld, player) if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index b421aa703676..1c1f0bc9ea2c 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -174,6 +174,15 @@ class Entrance: blacksmith_iridium = "Upgrade Iridium Tools" farming = "Start Farming" fishing = "Start Fishing" + attend_egg_festival = "Attend Egg Festival" + attend_flower_dance = "Attend Flower Dance" + attend_luau = "Attend Luau" + attend_moonlight_jellies = "Attend Dance of the Moonlight Jellies" + attend_fair = "Attend Stardew Valley Fair" + attend_spirit_eve = "Attend Spirit's Eve" + attend_festival_of_ice = "Attend Festival of Ice" + attend_night_market = "Attend Night Market" + attend_winter_star = "Attend Feast of the Winter Star" # Skull Cavern Elevator diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 90aca5577c91..2059609901ab 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -143,6 +143,15 @@ class Region: blacksmith_iridium = "Blacksmith Iridium Upgrades" farming = "Farming" fishing = "Fishing" + egg_festival = "Egg Festival" + flower_dance = "Flower Dance" + luau = "Luau" + moonlight_jellies = "Dance of the Moonlight Jellies" + fair = "Stardew Valley Fair" + spirit_eve = "Spirit's Eve" + festival_of_ice = "Festival of Ice" + night_market = "Night Market" + winter_star = "Feast of the Winter Star" class DeepWoodsRegion: From d783957b0def401b400af2619cf248861f1bf441 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 15:41:15 +0200 Subject: [PATCH 021/482] - Improvement to mod regions --- worlds/stardew_valley/data/locations.csv | 416 +++++++++--------- worlds/stardew_valley/logic.py | 20 +- worlds/stardew_valley/mods/logic/quests.py | 5 +- worlds/stardew_valley/mods/logic/skills.py | 10 +- worlds/stardew_valley/rules.py | 52 +-- .../test/performance/TestPerformance.py | 6 +- 6 files changed, 247 insertions(+), 262 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f5328264bd7a..56b9337b4571 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -915,8 +915,6 @@ id,region,name,tags,mod_name 1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, 1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, 1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, -2001,Town,Egg Hunt Victory,FESTIVAL, -2002,Town,Egg Festival: Strawberry Seeds,FESTIVAL, 2001,Egg Festival,Egg Hunt Victory,FESTIVAL, 2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, 2003,Flower Dance,Dance with someone,FESTIVAL, @@ -950,19 +948,19 @@ id,region,name,tags,mod_name 2031,Farm,Collect All Rarecrows,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, -2103,Town,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, -2104,Town,Biome Balance,SPECIAL_ORDER_BOARD, -2105,Town,Rock Rejuvenation,SPECIAL_ORDER_BOARD, -2106,Town,Gifts for George,SPECIAL_ORDER_BOARD, -2107,Town,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2108,Town,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, -2109,Town,Crop Order,SPECIAL_ORDER_BOARD, -2110,Town,Community Cleanup,SPECIAL_ORDER_BOARD, -2111,Town,The Strong Stuff,SPECIAL_ORDER_BOARD, -2112,Town,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, -2113,Town,Robin's Project,SPECIAL_ORDER_BOARD, -2114,Town,Robin's Resource Rush,SPECIAL_ORDER_BOARD, -2115,Town,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, +2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, +2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, +2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, +2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, +2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, +2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, +2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, +2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, +2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, +2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, +2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, +2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, 2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, 2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, @@ -992,53 +990,53 @@ id,region,name,tags,mod_name 2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", 2215,Dig Site,Open Professor Snail Cave,"GINGER_ISLAND", 2216,Field Office,Complete Island Field Office,"GINGER_ISLAND", -2301,Farm,Harvest Amaranth,"CROPSANITY", -2302,Farm,Harvest Artichoke,"CROPSANITY", -2303,Farm,Harvest Beet,"CROPSANITY", -2304,Farm,Harvest Blue Jazz,"CROPSANITY", -2305,Farm,Harvest Blueberry,"CROPSANITY", -2306,Farm,Harvest Bok Choy,"CROPSANITY", -2307,Farm,Harvest Cauliflower,"CROPSANITY", -2308,Farm,Harvest Corn,"CROPSANITY", -2309,Farm,Harvest Cranberries,"CROPSANITY", -2310,Farm,Harvest Eggplant,"CROPSANITY", -2311,Farm,Harvest Fairy Rose,"CROPSANITY", -2312,Farm,Harvest Garlic,"CROPSANITY", -2313,Farm,Harvest Grape,"CROPSANITY", -2314,Farm,Harvest Green Bean,"CROPSANITY", -2315,Farm,Harvest Hops,"CROPSANITY", -2316,Farm,Harvest Hot Pepper,"CROPSANITY", -2317,Farm,Harvest Kale,"CROPSANITY", -2318,Farm,Harvest Melon,"CROPSANITY", -2319,Farm,Harvest Parsnip,"CROPSANITY", -2320,Farm,Harvest Poppy,"CROPSANITY", -2321,Farm,Harvest Potato,"CROPSANITY", -2322,Farm,Harvest Pumpkin,"CROPSANITY", -2323,Farm,Harvest Radish,"CROPSANITY", -2324,Farm,Harvest Red Cabbage,"CROPSANITY", -2325,Farm,Harvest Rhubarb,"CROPSANITY", -2326,Farm,Harvest Starfruit,"CROPSANITY", -2327,Farm,Harvest Strawberry,"CROPSANITY", -2328,Farm,Harvest Summer Spangle,"CROPSANITY", -2329,Farm,Harvest Sunflower,"CROPSANITY", -2330,Farm,Harvest Tomato,"CROPSANITY", -2331,Farm,Harvest Tulip,"CROPSANITY", -2332,Farm,Harvest Unmilled Rice,"CROPSANITY", -2333,Farm,Harvest Wheat,"CROPSANITY", -2334,Farm,Harvest Yam,"CROPSANITY", -2335,Farm,Harvest Cactus Fruit,"CROPSANITY", -2336,Farm,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", -2337,Farm,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farm,Harvest Sweet Gem Berry,"CROPSANITY", -2339,Farm,Harvest Apple,"CROPSANITY", -2340,Farm,Harvest Apricot,"CROPSANITY", -2341,Farm,Harvest Cherry,"CROPSANITY", -2342,Farm,Harvest Orange,"CROPSANITY", -2343,Farm,Harvest Pomegranate,"CROPSANITY", -2344,Farm,Harvest Peach,"CROPSANITY", -2345,Farm,Harvest Banana,"CROPSANITY,GINGER_ISLAND", -2346,Farm,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farm,Harvest Coffee Bean,"CROPSANITY", +2301,Farming,Harvest Amaranth,"CROPSANITY", +2302,Farming,Harvest Artichoke,"CROPSANITY", +2303,Farming,Harvest Beet,"CROPSANITY", +2304,Farming,Harvest Blue Jazz,"CROPSANITY", +2305,Farming,Harvest Blueberry,"CROPSANITY", +2306,Farming,Harvest Bok Choy,"CROPSANITY", +2307,Farming,Harvest Cauliflower,"CROPSANITY", +2308,Farming,Harvest Corn,"CROPSANITY", +2309,Farming,Harvest Cranberries,"CROPSANITY", +2310,Farming,Harvest Eggplant,"CROPSANITY", +2311,Farming,Harvest Fairy Rose,"CROPSANITY", +2312,Farming,Harvest Garlic,"CROPSANITY", +2313,Farming,Harvest Grape,"CROPSANITY", +2314,Farming,Harvest Green Bean,"CROPSANITY", +2315,Farming,Harvest Hops,"CROPSANITY", +2316,Farming,Harvest Hot Pepper,"CROPSANITY", +2317,Farming,Harvest Kale,"CROPSANITY", +2318,Farming,Harvest Melon,"CROPSANITY", +2319,Farming,Harvest Parsnip,"CROPSANITY", +2320,Farming,Harvest Poppy,"CROPSANITY", +2321,Farming,Harvest Potato,"CROPSANITY", +2322,Farming,Harvest Pumpkin,"CROPSANITY", +2323,Farming,Harvest Radish,"CROPSANITY", +2324,Farming,Harvest Red Cabbage,"CROPSANITY", +2325,Farming,Harvest Rhubarb,"CROPSANITY", +2326,Farming,Harvest Starfruit,"CROPSANITY", +2327,Farming,Harvest Strawberry,"CROPSANITY", +2328,Farming,Harvest Summer Spangle,"CROPSANITY", +2329,Farming,Harvest Sunflower,"CROPSANITY", +2330,Farming,Harvest Tomato,"CROPSANITY", +2331,Farming,Harvest Tulip,"CROPSANITY", +2332,Farming,Harvest Unmilled Rice,"CROPSANITY", +2333,Farming,Harvest Wheat,"CROPSANITY", +2334,Farming,Harvest Yam,"CROPSANITY", +2335,Farming,Harvest Cactus Fruit,"CROPSANITY", +2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", +2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", +2338,Farming,Harvest Sweet Gem Berry,"CROPSANITY", +2339,Farming,Harvest Apple,"CROPSANITY", +2340,Farming,Harvest Apricot,"CROPSANITY", +2341,Farming,Harvest Cherry,"CROPSANITY", +2342,Farming,Harvest Orange,"CROPSANITY", +2343,Farming,Harvest Pomegranate,"CROPSANITY", +2344,Farming,Harvest Peach,"CROPSANITY", +2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", +2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", +2347,Farming,Harvest Coffee Bean,"CROPSANITY", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill @@ -1059,26 +1057,26 @@ id,region,name,tags,mod_name 5018,Stardew Valley,Level 8 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill 5019,Stardew Valley,Level 9 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill 5020,Stardew Valley,Level 10 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5021,Stardew Valley,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5022,Stardew Valley,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5023,Stardew Valley,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5024,Stardew Valley,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5025,Stardew Valley,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5026,Stardew Valley,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5027,Stardew Valley,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5028,Stardew Valley,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5029,Stardew Valley,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5030,Stardew Valley,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5031,Stardew Valley,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5032,Stardew Valley,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5033,Stardew Valley,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5034,Stardew Valley,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5035,Stardew Valley,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5036,Stardew Valley,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5037,Stardew Valley,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5038,Stardew Valley,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5039,Stardew Valley,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5040,Stardew Valley,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill 5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology 5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology 5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology @@ -1099,61 +1097,61 @@ id,region,name,tags,mod_name 5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill 5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill 5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5501,Stardew Valley,Analyze: Clear Debris,MANDATORY,Magic -5502,Stardew Valley,Analyze: Till,MANDATORY,Magic -5503,Stardew Valley,Analyze: Water,MANDATORY,Magic -5504,Stardew Valley,Analyze All Toil School Locations,MANDATORY,Magic -5505,Stardew Valley,Analyze: Evac,MANDATORY,Magic -5506,Stardew Valley,Analyze: Haste,MANDATORY,Magic -5507,Stardew Valley,Analyze: Heal,MANDATORY,Magic -5508,Stardew Valley,Analyze All Life School Locations,MANDATORY,Magic -5509,Stardew Valley,Analyze: Descend,MANDATORY,Magic -5510,Stardew Valley,Analyze: Fireball,MANDATORY,Magic -5511,The Mines - Floor 60,Analyze: Frostbite,MANDATORY,Magic -5512,Stardew Valley,Analyze All Elemental School Locations,MANDATORY,Magic -5513,Stardew Valley,Analyze: Lantern,MANDATORY,Magic -5514,Stardew Valley,Analyze: Tendrils,MANDATORY,Magic -5515,Stardew Valley,Analyze: Shockwave,MANDATORY,Magic -5516,Stardew Valley,Analyze All Nature School Locations,MANDATORY,Magic -5517,Stardew Valley,Analyze: Meteor,MANDATORY,Magic -5518,Stardew Valley,Analyze: Lucksteal,MANDATORY,Magic -5519,Stardew Valley,Analyze: Bloodmana,MANDATORY,Magic -5520,Stardew Valley,Analyze All Eldritch School Locations,MANDATORY,Magic -5521,Stardew Valley,Analyze Every Magic School Location,MANDATORY,Magic -6001,Town,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas -6002,Town,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas -6003,Town,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas -6004,Town,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas -6005,Town,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas -6006,Town,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas -6007,Town,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas -6008,Town,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas -6009,Town,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas -6010,Town,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas -6011,Town,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas -6012,Town,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas -6013,Town,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas -6014,Town,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas -6015,Secret Woods,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba -6016,Secret Woods,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba -6017,Secret Woods,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba -6018,Secret Woods,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba -6019,Secret Woods,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba -6020,Secret Woods,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba -6021,Secret Woods,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba -6022,Secret Woods,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba -6023,Secret Woods,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba -6024,Secret Woods,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba -6025,Forest,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) -6026,Forest,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) -6027,Forest,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) -6028,Forest,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) -6029,Forest,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) -6030,Forest,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) -6031,Forest,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) -6032,Forest,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) -6033,Forest,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) -6034,Forest,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) +5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic +5502,Magic Altar,Analyze: Till,MANDATORY,Magic +5503,Magic Altar,Analyze: Water,MANDATORY,Magic +5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic +5505,Magic Altar,Analyze: Evac,MANDATORY,Magic +5506,Magic Altar,Analyze: Haste,MANDATORY,Magic +5507,Magic Altar,Analyze: Heal,MANDATORY,Magic +5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic +5509,Magic Altar,Analyze: Descend,MANDATORY,Magic +5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbite,MANDATORY,Magic +5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic +5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic +5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic +5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic +5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic +5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic +5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic +5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic +5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic +5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic +6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas +6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas +6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas +6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas +6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas +6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas +6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas +6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas +6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas +6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas +6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas +6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas +6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas +6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas +6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba +6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba +6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba +6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba +6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba +6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba +6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba +6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba +6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba +6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba +6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) +6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) +6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) +6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) +6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) +6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) +6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) +6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) +6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) +6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) 6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) @@ -1164,34 +1162,34 @@ id,region,name,tags,mod_name 6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6045,Town,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC -6046,Town,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC -6047,Town,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC -6048,Town,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC -6049,Town,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC -6050,Town,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC -6051,Town,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC -6052,Town,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC -6053,Town,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC -6054,Town,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC -6055,Town,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC -6056,Town,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC -6057,Town,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC -6058,Town,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC -6059,Forest,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick -6060,Forest,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick -6061,Forest,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick -6062,Forest,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick -6063,Forest,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick -6064,Forest,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick -6065,Forest,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick -6066,Forest,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick -6067,Forest,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick -6068,Forest,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick -6069,Forest,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick -6070,Forest,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick -6071,Forest,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick -6072,Forest,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick +6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC +6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC +6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC +6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC +6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC +6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC +6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC +6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC +6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC +6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC +6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC +6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC +6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC +6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC +6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick +6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick +6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick +6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick +6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick +6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick +6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick +6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick +6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick +6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick +6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick +6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick +6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick +6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick 6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC 6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC 6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC @@ -1206,34 +1204,34 @@ id,region,name,tags,mod_name 6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC 6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC 6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC -6087,Forest,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited -6088,Forest,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited -6089,Forest,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited -6090,Forest,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited -6091,Forest,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited -6092,Forest,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited -6093,Forest,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited -6094,Forest,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited -6095,Forest,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited -6096,Forest,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited -6097,Forest,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited -6098,Forest,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited -6099,Forest,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited -6100,Forest,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited -6101,Forest,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene -6102,Forest,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene -6103,Forest,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene -6104,Forest,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene -6105,Forest,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene -6106,Forest,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene -6107,Forest,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene -6108,Forest,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene -6109,Forest,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene -6110,Forest,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene -6111,Forest,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene -6112,Forest,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene -6113,Forest,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene -6114,Forest,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene +6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited +6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited +6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited +6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited +6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited +6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited +6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited +6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited +6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited +6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited +6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited +6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited +6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited +6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited +6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene +6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene +6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene +6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene +6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene +6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene +6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene +6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene +6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene +6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene +6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene +6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene +6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene +6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene 6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC 6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC 6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC @@ -1244,20 +1242,20 @@ id,region,name,tags,mod_name 6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC 6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC 6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC -6125,Town,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley -6126,Town,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley -6127,Town,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley -6128,Town,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley -6129,Town,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley -6130,Town,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley -6131,Town,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley -6132,Town,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley -6133,Town,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley -6134,Town,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley -6135,Town,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley -6136,Town,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley -6137,Town,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley -6138,Town,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley +6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley +6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley +6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley +6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley +6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley +6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley +6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley +6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley +6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley +6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley +6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley +6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley +6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley 7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack 7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod 7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods @@ -1285,8 +1283,8 @@ id,region,name,tags,mod_name 7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator 7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator 7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7501,Town,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Town,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) 7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC 7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py index 47cdafdcb1d2..0c2fb1cab573 100644 --- a/worlds/stardew_valley/logic.py +++ b/worlds/stardew_valley/logic.py @@ -502,19 +502,19 @@ def __post_init__(self): SpecialOrder.biome_balance: self.can_meet(NPC.demetrius) & self.can_fish_perfectly(), SpecialOrder.rock_rejuivenation: self.has_relationship(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & - self.has(ArtisanGood.cloth) & self.can_reach_region(Region.haley_house), - SpecialOrder.gifts_for_george: self.can_reach_region(Region.alex_house) & self.has_season(Season.spring) & self.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.can_reach_region(Region.museum) & self.can_reach_region(Region.dig_site) & self.has_tool(Tool.pickaxe), - SpecialOrder.gus_famous_omelet: self.can_reach_region(Region.saloon) & self.has(AnimalProduct.any_egg), + self.has(ArtisanGood.cloth), + SpecialOrder.gifts_for_george: self.has_season(Season.spring) & self.has(Forageable.leek), + SpecialOrder.fragments_of_the_past: self.can_reach_region(Region.dig_site) & self.has_tool(Tool.pickaxe), + SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), SpecialOrder.crop_order: self.can_farm_perfectly() & self.can_ship(), - SpecialOrder.community_cleanup: self.can_reach_region(Region.railroad) & self.can_crab_pot(), - SpecialOrder.the_strong_stuff: self.can_reach_region(Region.trailer) & self.can_keg(Vegetable.potato), - SpecialOrder.pierres_prime_produce: self.can_reach_region(Region.pierre_store) & self.can_farm_perfectly(), - SpecialOrder.robins_project: self.can_meet(NPC.robin) & self.can_reach_region(Region.carpenter) & self.can_chop_perfectly() & + SpecialOrder.community_cleanup: self.can_crab_pot(), + SpecialOrder.the_strong_stuff: self.can_keg(Vegetable.potato), + SpecialOrder.pierres_prime_produce: self.can_farm_perfectly(), + SpecialOrder.robins_project: self.can_meet(NPC.robin) & self.can_chop_perfectly() & self.has(Material.hardwood), - SpecialOrder.robins_resource_rush: self.can_meet(NPC.robin) & self.can_reach_region(Region.carpenter) & self.can_chop_perfectly() & + SpecialOrder.robins_resource_rush: self.can_meet(NPC.robin) & self.can_chop_perfectly() & self.has(Fertilizer.tree) & self.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted_yum: self.can_reach_region(Region.beach) & self.has(Loot.bug_meat), + SpecialOrder.juicy_bugs_wanted_yum: self.has(Loot.bug_meat), SpecialOrder.tropical_fish: self.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), SpecialOrder.a_curious_substance: self.can_reach_region(Region.wizard_tower), diff --git a/worlds/stardew_valley/mods/logic/quests.py b/worlds/stardew_valley/mods/logic/quests.py index bf185754b2be..f543d4262e44 100644 --- a/worlds/stardew_valley/mods/logic/quests.py +++ b/worlds/stardew_valley/mods/logic/quests.py @@ -23,9 +23,8 @@ def get_modded_quest_rules(vanilla_logic, active_mods): if ModNames.ayeisha in active_mods: quests.update({ - ModQuest.AyeishaEnvelope: (vanilla_logic.has_season(Season.spring) | vanilla_logic.has_season(Season.fall)) & - vanilla_logic.can_reach_region(Region.mountain), - ModQuest.AyeishaRing: vanilla_logic.has_season(Season.winter) & vanilla_logic.can_reach_region(Region.forest) + ModQuest.AyeishaEnvelope: vanilla_logic.has_season(Season.spring) | vanilla_logic.has_season(Season.fall), + ModQuest.AyeishaRing: vanilla_logic.has_season(Season.winter) }) return quests diff --git a/worlds/stardew_valley/mods/logic/skills.py b/worlds/stardew_valley/mods/logic/skills.py index 24402a088b16..fd8f2f2ad41c 100644 --- a/worlds/stardew_valley/mods/logic/skills.py +++ b/worlds/stardew_valley/mods/logic/skills.py @@ -9,7 +9,7 @@ from ...strings.tool_names import Tool, ToolMaterial from ...mods.mod_data import ModNames from ...data.villagers_data import all_villagers -from ...stardew_rule import Count, StardewRule, False_ +from ...stardew_rule import Count, StardewRule, False_, True_ from ... import options @@ -59,7 +59,7 @@ def can_earn_magic_skill_level(vanilla_logic, level: int) -> StardewRule: vanilla_logic.received(MagicSpell.shockwave), vanilla_logic.received(MagicSpell.meteor), vanilla_logic.received(MagicSpell.spirit)] - return magic.can_use_altar(vanilla_logic) & Count(level, spell_count) + return Count(level, spell_count) def can_earn_socializing_skill_level(vanilla_logic, level: int) -> StardewRule: @@ -87,8 +87,6 @@ def can_earn_cooking_skill_level(vanilla_logic, level: int) -> StardewRule: def can_earn_binning_skill_level(vanilla_logic, level: int) -> StardewRule: if level >= 6: - return vanilla_logic.can_reach_region(Region.town) & vanilla_logic.has(Machine.recycling_machine) & \ - (vanilla_logic.can_fish() | vanilla_logic.can_crab_pot()) + return vanilla_logic.has(Machine.recycling_machine) & (vanilla_logic.can_fish() | vanilla_logic.can_crab_pot()) else: - return vanilla_logic.can_reach_region(Region.town) | (vanilla_logic.has(Machine.recycling_machine) & - (vanilla_logic.can_fish() | vanilla_logic.can_crab_pot())) + return True_() # You can always earn levels 1-5 with trash cans diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 91d5a3a8d469..96fd2b473df1 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -625,65 +625,55 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i (logic.has_relationship(NPC.wizard, 3) & logic.can_reach_region(Region.wizard_tower)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Clear Debris", player), - ((logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic")) - & magic.can_use_altar(logic)).simplify()) + (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic")).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Till", player), - (logic.has_tool("Hoe", "Basic") & magic.can_use_altar(logic)).simplify()) + logic.has_tool("Hoe", "Basic").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Water", player), - (logic.has_tool("Watering Can", "Basic") & magic.can_use_altar(logic)).simplify()) + logic.has_tool("Watering Can", "Basic").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Toil School Locations", player), (logic.has_tool("Watering Can", "Basic") & logic.has_tool("Hoe", "Basic") - & (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic")) - & magic.can_use_altar(logic)).simplify()) + & (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic"))).simplify()) # Do I *want* to add boots into logic when you get them even in vanilla without effort? idk MultiWorldRules.add_rule(multiworld.get_location("Analyze: Evac", player), - (logic.can_mine_perfectly() & magic.can_use_altar(logic)).simplify()) + logic.can_mine_perfectly().simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Haste", player), - (logic.has("Coffee") & magic.can_use_altar(logic)).simplify()) + logic.has("Coffee").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Heal", player), - (logic.has("Life Elixir") & magic.can_use_altar(logic)).simplify()) + logic.has("Life Elixir").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Life School Locations", player), (logic.has("Coffee") & logic.has("Life Elixir") - & logic.can_mine_perfectly() & magic.can_use_altar(logic)).simplify()) + & logic.can_mine_perfectly()).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Descend", player), - (logic.can_reach_region(Region.mines) & magic.can_use_altar(logic)).simplify()) + logic.can_reach_region(Region.mines).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), - (logic.has("Fire Quartz") & magic.can_use_altar(logic)).simplify()) + logic.has("Fire Quartz").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.can_fish(85) & magic.can_use_altar(logic)).simplify()) + (logic.can_reach_region(Region.mines_floor_60) & logic.can_fish(85)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), - (logic.can_reach_region(Region.mines) & logic.has("Fire Quartz") - & logic.can_reach_region(Region.mines_floor_70) & logic.can_fish(85) & - magic.can_use_altar(logic)).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player), - magic.can_use_altar(logic).simplify()) + (logic.has("Fire Quartz") & logic.can_reach_region(Region.mines_floor_60) & logic.can_fish(85)).simplify()) + # MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player),) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Tendrils", player), - (logic.can_reach_region(Region.farm) & magic.can_use_altar(logic)).simplify()) + logic.can_reach_region(Region.farm).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Shockwave", player), - (logic.has("Earth Crystal") & magic.can_use_altar(logic)).simplify()) + logic.has("Earth Crystal").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Nature School Locations", player), - (logic.has("Earth Crystal") & logic.can_reach_region("Farm") & - magic.can_use_altar(logic)).simplify()), + (logic.has("Earth Crystal") & logic.can_reach_region("Farm")).simplify()), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Meteor", player), - (logic.can_reach_region(Region.farm) & logic.has_lived_months(12) - & magic.can_use_altar(logic)).simplify()), + (logic.can_reach_region(Region.farm) & logic.has_lived_months(12)).simplify()), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lucksteal", player), - (logic.can_reach_region(Region.witch_hut) & magic.can_use_altar(logic)).simplify()) + logic.can_reach_region(Region.witch_hut).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Bloodmana", player), - (logic.can_reach_region(Region.mines_floor_100) & magic.can_use_altar(logic)).simplify()) + logic.can_reach_region(Region.mines_floor_100).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Eldritch School Locations", player), (logic.can_reach_region(Region.witch_hut) & logic.can_reach_region(Region.mines_floor_100) & - logic.can_reach_region(Region.farm) & logic.has_lived_months(12) & - magic.can_use_altar(logic)).simplify()) + logic.can_reach_region(Region.farm) & logic.has_lived_months(12)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze Every Magic School Location", player), (logic.has_tool("Watering Can", "Basic") & logic.has_tool("Hoe", "Basic") & (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic")) & logic.has("Coffee") & logic.has("Life Elixir") & logic.can_mine_perfectly() & logic.has("Earth Crystal") & - logic.can_reach_region(Region.mines) & logic.has("Fire Quartz") & logic.can_fish(85) & logic.can_reach_region(Region.witch_hut) & logic.can_reach_region(Region.mines_floor_100) & - logic.can_reach_region(Region.farm) & logic.has_lived_months(12) & - magic.can_use_altar(logic)).simplify()) + logic.can_reach_region(Region.farm) & logic.has_lived_months(12)).simplify()) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index fa368b98ea6c..ff7595c5db60 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -49,7 +49,7 @@ def size_name(number_players): class TestDefaultOptions(SVTestCase): - acceptable_time_per_player = 0.05 + acceptable_time_per_player = 0.04 options = default_options() def test_solo(self): @@ -87,7 +87,7 @@ def test_10_player(self): class TestMinLocationMaxItems(SVTestCase): - acceptable_time_per_player = 0.6 + acceptable_time_per_player = 0.08 options = minimal_locations_maximal_items() def test_solo(self): @@ -124,7 +124,7 @@ def test_10_player(self): class TestAllsanityWithoutMods(SVTestCase): - acceptable_time_per_player = 0.1 + acceptable_time_per_player = 0.07 options = allsanity_options_without_mods() def test_solo(self): From 1ec7d61dcf554c227abf8116dcfee5a41c9b262b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 11 Nov 2023 21:50:42 -0500 Subject: [PATCH 022/482] - Add missing rule for Parrot Express to Dig Site --- worlds/stardew_valley/rules.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 96fd2b473df1..3766be51bebb 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -315,8 +315,8 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): logic.received("Island Farmhouse").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_gourmand_cave, player), logic.received("Island Farmhouse").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_dig_site, player), - logic.received("Dig Site Bridge").simplify()) + dig_site_rule = logic.received("Dig Site Bridge").simplify() + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_dig_site, player), dig_site_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), logic.received("Open Professor Snail Cave").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_island_trader, player), @@ -344,8 +344,13 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): Entrance.parrot_express_docks_to_jungle, Entrance.parrot_express_dig_site_to_jungle, Entrance.parrot_express_volcano_to_jungle, Entrance.parrot_express_jungle_to_docks, Entrance.parrot_express_dig_site_to_docks, Entrance.parrot_express_volcano_to_docks] + parrot_express_rule = logic.received(Transportation.parrot_express).simplify() + parrot_express_to_dig_site_rule = dig_site_rule & parrot_express_rule for parrot in parrots: - MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), logic.received(Transportation.parrot_express).simplify()) + if "Dig Site" in parrot: + MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), parrot_express_to_dig_site_rule) + else: + MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), parrot_express_rule) def set_island_parrot_rules(logic: StardewLogic, multiworld, player): From 6917c422c7c77633ce213e14c089606bee0b3a2c Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 4 Aug 2023 00:00:34 -0400 Subject: [PATCH 023/482] - Code from Mati --- worlds/stardew_valley/test/regions_mati.py | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 worlds/stardew_valley/test/regions_mati.py diff --git a/worlds/stardew_valley/test/regions_mati.py b/worlds/stardew_valley/test/regions_mati.py new file mode 100644 index 000000000000..48a8fcc827c5 --- /dev/null +++ b/worlds/stardew_valley/test/regions_mati.py @@ -0,0 +1,39 @@ +def shuffle_archipelago_entrances(archipelago_data): + # archipelago_data is a representation of the current layout with entrance information + + # Extract all the entrances from the archipelago_data + entrances = extract_entrances(archipelago_data) + + # Shuffle the entrances randomly + random.shuffle(entrances) + + # Assign the shuffled entrances back to the archipelago_data + assign_shuffled_entrances(archipelago_data, entrances) + + +def extract_entrances(archipelago_data): + # Extract all the entrance information from the archipelago_data + # For example, you might have a data structure that represents entrances as tuples or objects. + entrances = [] + # Code to extract the entrances from the archipelago_data and add them to the entrances list + return entrances + + +def assign_shuffled_entrances(archipelago_data, shuffled_entrances): + # Assign the shuffled entrances back to the archipelago_data + # Modify the archipelago_data to have the shuffled entrances in their new positions + pass # Replace this with the actual code to update the archipelago_data + + +def main(): + # Example usage + archipelago_data = { + # Your representation of the current layout with entrance information + } + + shuffle_archipelago_entrances(archipelago_data) + # Now archipelago_data should contain the layout with shuffled entrances + + +if __name__ == "__main__": + main() \ No newline at end of file From 1b49a66ed3ee9869a1b9efba809cb8ed972386a8 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 4 Aug 2023 00:01:39 -0400 Subject: [PATCH 024/482] Moved mati regions --- worlds/stardew_valley/{test => }/regions_mati.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename worlds/stardew_valley/{test => }/regions_mati.py (100%) diff --git a/worlds/stardew_valley/test/regions_mati.py b/worlds/stardew_valley/regions_mati.py similarity index 100% rename from worlds/stardew_valley/test/regions_mati.py rename to worlds/stardew_valley/regions_mati.py From bfa61fac0be5086e1b0bcc5c74ba72b8460630f1 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 4 Aug 2023 19:21:59 -0400 Subject: [PATCH 025/482] - Added Monstersanity locations --- worlds/stardew_valley/data/locations.csv | 133 ++++++++++++++++-- worlds/stardew_valley/data/monster_data.py | 117 ++++++++++++++- worlds/stardew_valley/data/museum_data.py | 2 +- .../data/shipsanity_unimplemented_items.csv | 0 worlds/stardew_valley/locations.py | 39 ++++- worlds/stardew_valley/options.py | 54 +++++++ worlds/stardew_valley/regions_mati.py | 39 ----- .../stardew_valley/strings/monster_names.py | 67 +++++++++ worlds/stardew_valley/strings/region_names.py | 5 + 9 files changed, 396 insertions(+), 60 deletions(-) create mode 100644 worlds/stardew_valley/data/shipsanity_unimplemented_items.csv delete mode 100644 worlds/stardew_valley/regions_mati.py create mode 100644 worlds/stardew_valley/strings/monster_names.py diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 56b9337b4571..24ed689902db 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -213,7 +213,7 @@ id,region,name,tags,mod_name 543,Desert,Exotic Spirits,"MANDATORY,QUEST", 544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", 545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Railroad,Dark Talisman,"MANDATORY,QUEST", +546,Railroad,Dark Talisman,"MANDATORY,QUEST,REQUIRES_MUSEUM", 547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", 548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", 601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", @@ -776,16 +776,16 @@ id,region,name,tags,mod_name 1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, 1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, 1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, -1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, -1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, -1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, -1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, -1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, -1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, -1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, -1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, -1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, +1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY,REQUIRES_MUSEUM", 1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", 1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", 1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", @@ -1037,6 +1037,117 @@ id,region,name,tags,mod_name 2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", 2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", 2347,Farming,Harvest Coffee Bean,"CROPSANITY", +2500,Farm,PLACEHOLDER Shipsanity start,"SHIPSANITY" +3000,Farm,PLACEHOLDER Shipsanity end,"SHIPSANITY" +3001,Adventurer's Guild,Monster Eradication: Slime,"MONSTERSANITY,MONSTERSANITY_GOALS", +3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", +3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", +3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", +3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", +3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", +3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", +3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", +3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", +3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS,GINGER_ISLAND", +3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", +3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", +3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", +3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", +3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Blue Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Red Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Purple Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Yellow Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Black Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Copper Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Iron Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Tiger Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3110,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Dangerous Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3112,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Dangerous Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3114,Adventurer's Guild,Monster Eradication: Shadow Sniper,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3115,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Dangerous Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3117,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Dangerous Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3119,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Dangerous Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3123,Adventurer's Guild,Monster Eradication: Skeleton Mage,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3124,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Dangerous Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3126,Adventurer's Guild,Monster Eradication: Cave Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Dangerous Cave Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3128,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3129,Adventurer's Guild,Monster Eradication: Dangerous Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3130,Adventurer's Guild,Monster Eradication: Mutant Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", +3131,Adventurer's Guild,Monster Eradication: Mutant Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", +3132,Adventurer's Guild,Monster Eradication: Armored Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3133,Adventurer's Guild,Monster Eradication: Dangerous Armored Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3134,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3135,Adventurer's Guild,Monster Eradication: Dangerous Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3136,Adventurer's Guild,Monster Eradication: Magma Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3137,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3138,Adventurer's Guild,Monster Eradication: Dangerous Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3139,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3140,Adventurer's Guild,Monster Eradication: Dangerous Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3141,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3142,Adventurer's Guild,Monster Eradication: Dangerous Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3143,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3144,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3145,Adventurer's Guild,Monster Eradication: Dangerous Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3146,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3147,Adventurer's Guild,Monster Eradication: Royal Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3148,Adventurer's Guild,Monster Eradication: Magma Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", +3149,Adventurer's Guild,Monster Eradication: Magma Sparker,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 6030571f89fe..49898902babe 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -1,8 +1,113 @@ -class Monster: - duggy = "Duggy" - blue_slime = "Blue Slime" - pepper_rex = "Pepper Rex" - stone_golem = "Stone Golem" +from dataclasses import dataclass +from typing import List, Tuple, Union, Optional +from . import season_data as season +from .game_item import GameItem +from ..strings.monster_names import Monster, MonsterCategory +from ..strings.region_names import Region -frozen_monsters = (Monster.blue_slime,) + +@dataclass(frozen=True) +class StardewMonster: + name: str + category: str + locations: Tuple[str] + difficulty: int + + def __repr__(self): + return f"{self.name} [{self.category}] (Locations: {self.locations} |" \ + f" Difficulty: {self.difficulty}) |" + +slime_hutch = (Region.slime_hutch,) +mines_floor_20 = (Region.mines_floor_20,) +mines_floor_60 = (Region.mines_floor_60,) +mines_floor_100 = (Region.mines_floor_100,) +dangerous_mines_20 = (Region.dangerous_mines_20,) +dangerous_mines_60 = (Region.dangerous_mines_60,) +dangerous_mines_100 = (Region.dangerous_mines_100,) +quarry_mine = (Region.quarry_mine,) +mutant_bug_lair = (Region.mutant_bug_lair,) +skull_cavern = (Region.skull_cavern_25,) +skull_cavern_high = (Region.skull_cavern_75,) +skull_cavern_dangerous = (Region.dangerous_skull_cavern,) +tiger_slime_grove = (Region.island_west,) +volcano = (Region.volcano_floor_5,) +volcano_high = (Region.volcano_floor_10,) + +all_monsters: List[StardewMonster] = [] + + +def create_monster(name: str, category: str, locations: Tuple[str, ...], difficulty: int) -> StardewMonster: + monster = StardewMonster(name, category, locations, difficulty) + all_monsters.append(monster) + return monster + + +green_slime = create_monster(Monster.green_slime, MonsterCategory.slime, mines_floor_20, 0) +blue_slime = create_monster(Monster.blue_slime, MonsterCategory.slime, mines_floor_60, 1) +red_slime = create_monster(Monster.red_slime, MonsterCategory.slime, mines_floor_100, 2) +purple_slime = create_monster(Monster.purple_slime, MonsterCategory.slime, skull_cavern, 3) +yellow_slime = create_monster(Monster.yellow_slime, MonsterCategory.slime, skull_cavern_high, 4) +black_slime = create_monster(Monster.black_slime, MonsterCategory.slime, slime_hutch, 1) +copper_slime = create_monster(Monster.copper_slime, MonsterCategory.slime, quarry_mine, 1) +iron_slime = create_monster(Monster.iron_slime, MonsterCategory.slime, quarry_mine, 2) +tiger_slime = create_monster(Monster.tiger_slime, MonsterCategory.slime, tiger_slime_grove, 4) + +shadow_shaman = create_monster(Monster.shadow_shaman, MonsterCategory.void_spirits, mines_floor_100, 2) +shadow_shaman_dangerous = create_monster(Monster.shadow_shaman_dangerous, MonsterCategory.void_spirits, dangerous_mines_100, 4) +shadow_brute = create_monster(Monster.shadow_brute, MonsterCategory.void_spirits, mines_floor_100, 2) +shadow_brute_dangerous = create_monster(Monster.shadow_brute_dangerous, MonsterCategory.void_spirits, dangerous_mines_100, 4) +shadow_sniper = create_monster(Monster.shadow_sniper, MonsterCategory.void_spirits, dangerous_mines_100, 4) + +bat = create_monster(Monster.bat, MonsterCategory.bats, mines_floor_20, 0) +bat_dangerous = create_monster(Monster.bat_dangerous, MonsterCategory.bats, dangerous_mines_20, 4) +frost_bat = create_monster(Monster.frost_bat, MonsterCategory.bats, mines_floor_60, 1) +frost_bat_dangerous = create_monster(Monster.frost_bat_dangerous, MonsterCategory.bats, dangerous_mines_60, 4) +lava_bat = create_monster(Monster.lava_bat, MonsterCategory.bats,mines_floor_100, 2) +iridium_bat = create_monster(Monster.iridium_bat, MonsterCategory.bats, skull_cavern_high, 3) + +skeleton = create_monster(Monster.skeleton, MonsterCategory.skeletons, mines_floor_100, 2) +skeleton_dangerous = create_monster(Monster.skeleton_dangerous, MonsterCategory.skeletons, dangerous_mines_100, 4) +skeleton_mage = create_monster(Monster.skeleton_mage, MonsterCategory.skeletons, dangerous_mines_100, 4) + +bug = create_monster(Monster.bug, MonsterCategory.cave_insects, mines_floor_20, 0) +bug_dangerous = create_monster(Monster.bug_dangerous, MonsterCategory.cave_insects, dangerous_mines_20, 4) +cave_fly = create_monster(Monster.cave_fly, MonsterCategory.cave_insects, mines_floor_20, 0) +cave_fly_dangerous = create_monster(Monster.cave_fly_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, 4) +grub = create_monster(Monster.grub, MonsterCategory.cave_insects, mines_floor_20, 0) +grub_dangerous = create_monster(Monster.grub_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, 4) +mutant_fly = create_monster(Monster.mutant_fly, MonsterCategory.cave_insects, mutant_bug_lair, 2) +mutant_grub = create_monster(Monster.mutant_grub, MonsterCategory.cave_insects, mutant_bug_lair, 2) +armored_bug = create_monster(Monster.armored_bug, MonsterCategory.cave_insects, skull_cavern, 0) # Requires 'Bug Killer' enchantment +armored_bug_dangerous = create_monster(Monster.armored_bug_dangerous, MonsterCategory.cave_insects, skull_cavern, 2) # Requires 'Bug Killer' enchantment + +duggy = create_monster(Monster.duggy, MonsterCategory.duggies, mines_floor_20, 0) +duggy_dangerous = create_monster(Monster.duggy_dangerous, MonsterCategory.duggies, dangerous_mines_20, 3) +magma_duggy = create_monster(Monster.magma_duggy, MonsterCategory.duggies, volcano, 4) + +dust_sprite = create_monster(Monster.dust_sprite, MonsterCategory.dust_sprites, mines_floor_60, 0) +dust_sprite_dangerous = create_monster(Monster.dust_sprite_dangerous, MonsterCategory.dust_sprites, dangerous_mines_60, 3) + +rock_crab = create_monster(Monster.rock_crab, MonsterCategory.rock_crabs, mines_floor_20, 0) +rock_crab_dangerous = create_monster(Monster.rock_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_20, 3) +lava_crab = create_monster(Monster.lava_crab, MonsterCategory.rock_crabs, mines_floor_100, 2) +lava_crab_dangerous = create_monster(Monster.lava_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_100, 4) +iridium_crab = create_monster(Monster.iridium_crab, MonsterCategory.rock_crabs, skull_cavern, 3) + +mummy = create_monster(Monster.mummy, MonsterCategory.mummies, skull_cavern, 3) # Requires bombs or "Crusader" enchantment +mummy_dangerous = create_monster(Monster.mummy_dangerous, MonsterCategory.mummies, skull_cavern_dangerous, 4) # Requires bombs or "Crusader" enchantment + +pepper_rex = create_monster(Monster.pepper_rex, MonsterCategory.pepper_rex, skull_cavern, 3) + +serpent = create_monster(Monster.serpent, MonsterCategory.serpents, skull_cavern, 4) +royal_serpent = create_monster(Monster.royal_serpent, MonsterCategory.serpents, skull_cavern_dangerous, 5) + +magma_sprite = create_monster(Monster.magma_sprite, MonsterCategory.magma_sprites, volcano, 4) +magma_sparker = create_monster(Monster.magma_sparker, MonsterCategory.magma_sprites, volcano_high, 4) + +all_monsters_by_name = {monster.name: monster for monster in all_monsters} +all_monsters_by_category = {} +for monster in all_monsters: + if monster.category not in all_monsters_by_category: + all_monsters_by_category[monster.category] = [] + all_monsters_by_category[monster.category].append(monster) diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index b786f5b2d00c..9ce76459b39d 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -5,7 +5,7 @@ from . import common_data as common from .game_item import GameItem -from .monster_data import Monster +from worlds.stardew_valley.strings.monster_names import Monster from ..strings.region_names import Region from ..strings.geode_names import Geode diff --git a/worlds/stardew_valley/data/shipsanity_unimplemented_items.csv b/worlds/stardew_valley/data/shipsanity_unimplemented_items.csv new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 345796b0311e..064c68b86c08 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -62,6 +62,11 @@ class LocationTags(enum.Enum): SPECIAL_ORDER_QI = enum.auto() GINGER_ISLAND = enum.auto() WALNUT_PURCHASE = enum.auto() + REQUIRES_MUSEUM = enum.auto() + MONSTERSANITY = enum.auto() + MONSTERSANITY_GOALS = enum.auto() + MONSTERSANITY_PROGRESSIVE_GOALS = enum.auto() + MONSTERSANITY_MONSTER = enum.auto() # Skill Mods LUCK_LEVEL = enum.auto() BINNING_LEVEL = enum.auto() @@ -293,6 +298,26 @@ def extend_elevator_locations(randomized_locations: List[LocationData], options: randomized_locations.extend(filtered_elevator_locations) +def extend_monstersanity_locations(randomized_locations: List[LocationData], world_options): + monstersanity = world_options[options.Monstersanity] + if monstersanity == options.Monstersanity.option_none: + return + if monstersanity == options.Monstersanity.option_one_per_monster or monstersanity == options.Monstersanity.option_split_goals: + monster_locations = [location for location in locations_by_tag[LocationTags.MONSTERSANITY_MONSTER]] + filtered_monster_locations = filter_disabled_locations(world_options, monster_locations) + randomized_locations.extend(filtered_monster_locations) + return + goal_locations = [location for location in locations_by_tag[LocationTags.MONSTERSANITY_GOALS]] + filtered_goal_locations = filter_disabled_locations(world_options, goal_locations) + randomized_locations.extend(filtered_goal_locations) + if monstersanity != options.Monstersanity.option_progressive_goals: + return + progressive_goal_locations = [location for location in locations_by_tag[LocationTags.MONSTERSANITY_PROGRESSIVE_GOALS]] + filtered_progressive_goal_locations = filter_disabled_locations(world_options, progressive_goal_locations) + randomized_locations.extend(filtered_progressive_goal_locations) + + + def create_locations(location_collector: StardewLocationCollector, options: StardewValleyOptions, random: Random): @@ -332,10 +357,17 @@ def create_locations(location_collector: StardewLocationCollector, extend_special_order_locations(randomized_locations, options) extend_walnut_purchase_locations(randomized_locations, options) + extend_monstersanity_locations(randomized_locations, world_options) + for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) +def filter_museum_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: + include_museum = world_options[options.Museumsanity] != options.Museumsanity.option_none + return [location for location in locations if include_museum or LocationTags.REQUIRES_MUSEUM not in location.tags] + + def filter_ginger_island(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: include_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false return [location for location in locations if include_island or LocationTags.GINGER_ISLAND not in location.tags] @@ -347,6 +379,7 @@ def filter_modded_locations(options: StardewValleyOptions, locations: List[Locat def filter_disabled_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: - locations_first_pass = filter_ginger_island(options, locations) - locations_second_pass = filter_modded_locations(options, locations_first_pass) - return locations_second_pass + locations_museum_filter = filter_museum_locations(options, locations) + locations_island_filter = filter_ginger_island(options, locations_museum_filter) + locations_mod_filter = filter_modded_locations(options, locations_island_filter) + return locations_mod_filter diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 267ebd7a63de..0d22bfaf3901 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -375,6 +375,60 @@ class FriendsanityHeartSize(Range): # step = 1 +class Monstersanity(Choice): + """Locations for slaying monsters? + None: There are no checks for slaying monsters + One per category: Every category visible at the adventure guild gives one check + One per Monster: Every unique monster gives one check + Monster Eradication Goals: The Monster Eradication Goals each contain one check + Short Monster Eradication Goals: The Monster Eradication Goals each contain one check, but are reduced by 60% + Very Short Monster Eradication Goals: The Monster Eradication Goals each contain one check, but are reduced by 90% + Progressive Eradication Goals: The Monster Eradication Goals each contain 5 checks, each 20% of the way + Split Eradication Goals: The Monster Eradication Goals are split by monsters, each monster has one check + """ + internal_name = "monstersanity" + display_name = "Monstersanity" + default = 1 + option_none = 0 + option_one_per_category = 1 + option_one_per_monster = 2 + option_goals = 3 + option_short_goals = 4 + option_very_short_goals = 5 + option_progressive_goals = 6 + option_split_goals = 7 + + +class Shipsanity(Choice): + """Locations for shipping items? + None: There are no checks for shipping items + Crops: Every crop being shipped is a check + Quality Crops: Every crop being shipped is a check, but only granted if it is gold-quality + Fish: Every fish being shipped is a check except legendaries + Quality Fish: Every fish being shipped is a check except legendaries, but only granted if it is gold-quality + Full Shipment: Every item in the Collections page is a check + Quality Full Shipment: Every item in the Collections page is a check, but only granted if it is gold-quality when applicable + Full Shipment With Fish: Every item in the Collections page and every fish is a check + Quality Full Shipment With Fish: Every item in the Collections page and every fish is a check, but only granted if it is gold-quality when applicable + Everything: Every item in the game that can be shipped is a check + Quality Everything: Every item in the game that can be shipped is a check, but only granted if it is gold-quality when applicable + """ + internal_name = "shipsanity" + display_name = "Shipsanity" + default = 0 + option_none = 0 + option_crops = 1 + option_quality_crops = 2 + option_fish = 3 + option_quality_fish = 4 + option_full_shipment = 5 + option_quality_full_shipment = 6 + option_full_shipment_with_fish = 7 + option_quality_full_shipment_with_fish = 8 + option_everything = 9 + option_quality_everything = 10 + + class NumberOfMovementBuffs(Range): """Number of movement speed buffs to the player that exist as items in the pool. Each movement speed buff is a +25% multiplier that stacks additively""" diff --git a/worlds/stardew_valley/regions_mati.py b/worlds/stardew_valley/regions_mati.py deleted file mode 100644 index 48a8fcc827c5..000000000000 --- a/worlds/stardew_valley/regions_mati.py +++ /dev/null @@ -1,39 +0,0 @@ -def shuffle_archipelago_entrances(archipelago_data): - # archipelago_data is a representation of the current layout with entrance information - - # Extract all the entrances from the archipelago_data - entrances = extract_entrances(archipelago_data) - - # Shuffle the entrances randomly - random.shuffle(entrances) - - # Assign the shuffled entrances back to the archipelago_data - assign_shuffled_entrances(archipelago_data, entrances) - - -def extract_entrances(archipelago_data): - # Extract all the entrance information from the archipelago_data - # For example, you might have a data structure that represents entrances as tuples or objects. - entrances = [] - # Code to extract the entrances from the archipelago_data and add them to the entrances list - return entrances - - -def assign_shuffled_entrances(archipelago_data, shuffled_entrances): - # Assign the shuffled entrances back to the archipelago_data - # Modify the archipelago_data to have the shuffled entrances in their new positions - pass # Replace this with the actual code to update the archipelago_data - - -def main(): - # Example usage - archipelago_data = { - # Your representation of the current layout with entrance information - } - - shuffle_archipelago_entrances(archipelago_data) - # Now archipelago_data should contain the layout with shuffled entrances - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/worlds/stardew_valley/strings/monster_names.py b/worlds/stardew_valley/strings/monster_names.py new file mode 100644 index 000000000000..e28d70b7bfe1 --- /dev/null +++ b/worlds/stardew_valley/strings/monster_names.py @@ -0,0 +1,67 @@ +class Monster: + green_slime = "Green Slime" + blue_slime = "Blue Slime" + red_slime = "Red Slime" + purple_slime = "Purple Slime" + yellow_slime = "Yellow Slime" + black_slime = "Black Slime" + copper_slime = "Copper Slime" + iron_slime = "Iron Slime" + tiger_slime = "Tiger Slime" + shadow_shaman = "Shadow Shaman" + shadow_shaman_dangerous = "Dangerous Shadow Shaman" + shadow_brute = "Shadow Brute" + shadow_brute_dangerous = "Dangerous Shadow Brute" + shadow_sniper = "Shadow Sniper" + bat = "Bat" + bat_dangerous = "Dangerous Bat" + frost_bat = "Frost Bat" + frost_bat_dangerous = "Dangerous Frost Bat" + lava_bat = "Lava Bat" + iridium_bat = "Iridium Bat" + skeleton = "Skeleton" + skeleton_dangerous = "Dangerous Skeleton" + skeleton_mage = "Skeleton Mage" + bug = "Bug" + bug_dangerous = "Dangerous Bug" + cave_fly = "Cave Fly" + cave_fly_dangerous = "Dangerous Cave Fly" + grub = "Grub" + grub_dangerous = "Dangerous Grub" + mutant_fly = "Mutant Fly" + mutant_grub = "Mutant Grub" + armored_bug = "Armored Bug" + armored_bug_dangerous = "Armored Bug (dangerous)" + duggy = "Duggy" + duggy_dangerous = "Dangerous Duggy" + magma_duggy = "Magma Duggy" + dust_sprite = "Dust Sprite" + dust_sprite_dangerous = "Dangerous Dust Sprite" + rock_crab = "Rock Crab" + rock_crab_dangerous = "Dangerous Rock Crab" + lava_crab = "Lava Crab" + lava_crab_dangerous = "Dangerous Lava Crab" + iridium_crab = "Iridium Crab" + mummy = "Mummy" + mummy_dangerous = "Dangerous Mummy" + pepper_rex = "Pepper Rex" + serpent = "Serpent" + royal_serpent = "Royal Serpent" + magma_sprite = "Magma Sprite" + magma_sparker = "Magma Sparker" + + +class MonsterCategory: + slime = "Slime" + void_spirits = "Void Spirits" + bats = "Bats" + skeletons = "Skeletons" + cave_insects = "Cave Insects" + duggies = "Duggies" + dust_sprites = "Dust Sprites" + rock_crabs = "Rock Crabs" + mummies = "Mummies" + pepper_rex = "Pepper Rex" + serpents = "Serpents" + magma_sprites = "Magma Sprites" + diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 2059609901ab..159c6a56a9fb 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -63,6 +63,7 @@ class Region: skull_cavern_150 = "Skull Cavern Floor 150" skull_cavern_175 = "Skull Cavern Floor 175" skull_cavern_200 = "Skull Cavern Floor 200" + dangerous_skull_cavern = "Dangerous Skull Cavern" hospital = "Hospital" carpenter = "Carpenter Shop" alex_house = "Alex's House" @@ -107,6 +108,7 @@ class Region: bathhouse_entrance = "Bathhouse Entrance" locker_room = "Locker Room" public_bath = "Public Bath" + slime_hutch = "Slime Hutch" jotpk_world_1 = "JotPK World 1" jotpk_world_2 = "JotPK World 2" jotpk_world_3 = "JotPK World 3" @@ -137,6 +139,9 @@ class Region: mines_floor_110 = "The Mines - Floor 110" mines_floor_115 = "The Mines - Floor 115" mines_floor_120 = "The Mines - Floor 120" + dangerous_mines_20 = "Dangerous Mines - Floor 20" + dangerous_mines_60 = "Dangerous Mines - Floor 60" + dangerous_mines_100 = "Dangerous Mines - Floor 100" blacksmith_copper = "Blacksmith Copper Upgrades" blacksmith_iron = "Blacksmith Iron Upgrades" blacksmith_gold = "Blacksmith Gold Upgrades" From 1320fe332b1d440179b2c5915fc3dd2c9a735049 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 6 Aug 2023 10:56:54 -0400 Subject: [PATCH 026/482] - Split logic.py into a large number of thematically separated logic files --- worlds/stardew_valley/__init__.py | 9 +- worlds/stardew_valley/bundles.py | 2 +- worlds/stardew_valley/data/monster_data.py | 128 +- worlds/stardew_valley/data/museum_data.py | 3 +- worlds/stardew_valley/locations.py | 1 + worlds/stardew_valley/logic.py | 1722 ----------------- worlds/stardew_valley/logic/__init__.py | 0 worlds/stardew_valley/logic/ability_logic.py | 68 + worlds/stardew_valley/logic/action_logic.py | 36 + worlds/stardew_valley/logic/arcade_logic.py | 36 + worlds/stardew_valley/logic/artisan_logic.py | 63 + worlds/stardew_valley/logic/building_logic.py | 96 + worlds/stardew_valley/logic/combat_logic.py | 57 + worlds/stardew_valley/logic/cooking_logic.py | 62 + worlds/stardew_valley/logic/crop_logic.py | 45 + worlds/stardew_valley/logic/fishing_logic.py | 30 + worlds/stardew_valley/logic/gift_logic.py | 17 + worlds/stardew_valley/logic/has_logic.py | 34 + worlds/stardew_valley/logic/logic.py | 805 ++++++++ worlds/stardew_valley/logic/mine_logic.py | 128 ++ worlds/stardew_valley/logic/money_logic.py | 36 + worlds/stardew_valley/logic/monster_logic.py | 30 + worlds/stardew_valley/logic/museum_logic.py | 70 + worlds/stardew_valley/logic/pet_logic.py | 63 + worlds/stardew_valley/logic/received_logic.py | 32 + worlds/stardew_valley/logic/region_logic.py | 32 + .../logic/relationship_logic.py | 159 ++ worlds/stardew_valley/logic/season_logic.py | 47 + worlds/stardew_valley/logic/skill_logic.py | 165 ++ .../logic/special_order_logic.py | 123 ++ worlds/stardew_valley/logic/time_logic.py | 27 + worlds/stardew_valley/logic/tool_logic.py | 83 + worlds/stardew_valley/logic/wallet_logic.py | 28 + worlds/stardew_valley/mods/logic/buildings.py | 16 - .../mods/logic/buildings_logic.py | 29 + worlds/stardew_valley/mods/logic/deepwoods.py | 35 - .../mods/logic/deepwoods_logic.py | 62 + .../mods/logic/elevator_logic.py | 24 + worlds/stardew_valley/mods/logic/magic.py | 80 - .../stardew_valley/mods/logic/magic_logic.py | 84 + worlds/stardew_valley/mods/logic/mod_logic.py | 51 + .../mods/logic/mod_skills_levels.py | 19 + worlds/stardew_valley/mods/logic/quests.py | 30 - .../stardew_valley/mods/logic/quests_logic.py | 50 + worlds/stardew_valley/mods/logic/skills.py | 92 - .../stardew_valley/mods/logic/skills_logic.py | 121 ++ .../mods/logic/skullcavernelevator.py | 10 - .../mods/logic/special_orders.py | 24 - .../mods/logic/special_orders_logic.py | 45 + worlds/stardew_valley/options.py | 64 +- worlds/stardew_valley/rules.py | 352 ++-- worlds/stardew_valley/test/TestLogic.py | 8 +- .../test/TestLogicSimplification.py | 3 +- worlds/stardew_valley/test/TestRules.py | 108 +- 54 files changed, 3219 insertions(+), 2325 deletions(-) delete mode 100644 worlds/stardew_valley/logic.py create mode 100644 worlds/stardew_valley/logic/__init__.py create mode 100644 worlds/stardew_valley/logic/ability_logic.py create mode 100644 worlds/stardew_valley/logic/action_logic.py create mode 100644 worlds/stardew_valley/logic/arcade_logic.py create mode 100644 worlds/stardew_valley/logic/artisan_logic.py create mode 100644 worlds/stardew_valley/logic/building_logic.py create mode 100644 worlds/stardew_valley/logic/combat_logic.py create mode 100644 worlds/stardew_valley/logic/cooking_logic.py create mode 100644 worlds/stardew_valley/logic/crop_logic.py create mode 100644 worlds/stardew_valley/logic/fishing_logic.py create mode 100644 worlds/stardew_valley/logic/gift_logic.py create mode 100644 worlds/stardew_valley/logic/has_logic.py create mode 100644 worlds/stardew_valley/logic/logic.py create mode 100644 worlds/stardew_valley/logic/mine_logic.py create mode 100644 worlds/stardew_valley/logic/money_logic.py create mode 100644 worlds/stardew_valley/logic/monster_logic.py create mode 100644 worlds/stardew_valley/logic/museum_logic.py create mode 100644 worlds/stardew_valley/logic/pet_logic.py create mode 100644 worlds/stardew_valley/logic/received_logic.py create mode 100644 worlds/stardew_valley/logic/region_logic.py create mode 100644 worlds/stardew_valley/logic/relationship_logic.py create mode 100644 worlds/stardew_valley/logic/season_logic.py create mode 100644 worlds/stardew_valley/logic/skill_logic.py create mode 100644 worlds/stardew_valley/logic/special_order_logic.py create mode 100644 worlds/stardew_valley/logic/time_logic.py create mode 100644 worlds/stardew_valley/logic/tool_logic.py create mode 100644 worlds/stardew_valley/logic/wallet_logic.py delete mode 100644 worlds/stardew_valley/mods/logic/buildings.py create mode 100644 worlds/stardew_valley/mods/logic/buildings_logic.py delete mode 100644 worlds/stardew_valley/mods/logic/deepwoods.py create mode 100644 worlds/stardew_valley/mods/logic/deepwoods_logic.py create mode 100644 worlds/stardew_valley/mods/logic/elevator_logic.py delete mode 100644 worlds/stardew_valley/mods/logic/magic.py create mode 100644 worlds/stardew_valley/mods/logic/magic_logic.py create mode 100644 worlds/stardew_valley/mods/logic/mod_logic.py create mode 100644 worlds/stardew_valley/mods/logic/mod_skills_levels.py delete mode 100644 worlds/stardew_valley/mods/logic/quests.py create mode 100644 worlds/stardew_valley/mods/logic/quests_logic.py delete mode 100644 worlds/stardew_valley/mods/logic/skills.py create mode 100644 worlds/stardew_valley/mods/logic/skills_logic.py delete mode 100644 worlds/stardew_valley/mods/logic/skullcavernelevator.py delete mode 100644 worlds/stardew_valley/mods/logic/special_orders.py create mode 100644 worlds/stardew_valley/mods/logic/special_orders_logic.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index a56870e37619..2f82ff141013 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -8,13 +8,15 @@ from .bundles import get_all_bundles, Bundle from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData -from .logic import StardewLogic, StardewRule, True_, MAX_MONTHS +from .logic.logic import StardewLogic +from .logic.time_logic import MAX_MONTHS from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \ BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems from .presets import sv_options_presets from .regions import create_regions from .rules import set_rules from worlds.generic.Rules import set_rule +from .stardew_rule import True_, StardewRule from .strings.goal_names import Goal as GoalName client_version = 0 @@ -186,6 +188,7 @@ def setup_victory(self): "Victory") elif self.options.goal == Goal.option_bottom_of_the_mines: self.create_event_location(location_table[GoalName.bottom_of_the_mines], + self.logic.mine.can_mine_to_floor(120).simplify(), item="Victory") elif self.options.goal == Goal.option_cryptic_note: self.create_event_location(location_table[GoalName.cryptic_note], @@ -197,11 +200,11 @@ def setup_victory(self): "Victory") elif self.options.goal == Goal.option_complete_collection: self.create_event_location(location_table[GoalName.complete_museum], - self.logic.can_complete_museum().simplify(), + self.logic.museum.can_complete_museum().simplify(), "Victory") elif self.options.goal == Goal.option_full_house: self.create_event_location(location_table[GoalName.full_house], - (self.logic.has_children(2) & self.logic.can_reproduce()).simplify(), + (self.logic.relationship.has_children(2) & self.logic.relationship.can_reproduce()).simplify(), "Victory") elif self.options.goal == Goal.option_greatest_walnut_hunter: self.create_event_location(location_table[GoalName.greatest_walnut_hunter], diff --git a/worlds/stardew_valley/bundles.py b/worlds/stardew_valley/bundles.py index 4af21542a4ec..2deec4878ea9 100644 --- a/worlds/stardew_valley/bundles.py +++ b/worlds/stardew_valley/bundles.py @@ -1,8 +1,8 @@ from random import Random from typing import List, Dict, Union +from .logic.logic import StardewLogic from .data.bundle_data import * -from .logic import StardewLogic from .options import BundleRandomization, BundlePrice vanilla_bundles = { diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 49898902babe..42546e5653e3 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -4,6 +4,7 @@ from . import season_data as season from .game_item import GameItem from ..strings.monster_names import Monster, MonsterCategory +from ..strings.performance_names import Performance from ..strings.region_names import Region @@ -12,12 +13,13 @@ class StardewMonster: name: str category: str locations: Tuple[str] - difficulty: int + difficulty: str def __repr__(self): return f"{self.name} [{self.category}] (Locations: {self.locations} |" \ f" Difficulty: {self.difficulty}) |" + slime_hutch = (Region.slime_hutch,) mines_floor_20 = (Region.mines_floor_20,) mines_floor_60 = (Region.mines_floor_60,) @@ -37,73 +39,73 @@ def __repr__(self): all_monsters: List[StardewMonster] = [] -def create_monster(name: str, category: str, locations: Tuple[str, ...], difficulty: int) -> StardewMonster: +def create_monster(name: str, category: str, locations: Tuple[str, ...], difficulty: str) -> StardewMonster: monster = StardewMonster(name, category, locations, difficulty) all_monsters.append(monster) return monster -green_slime = create_monster(Monster.green_slime, MonsterCategory.slime, mines_floor_20, 0) -blue_slime = create_monster(Monster.blue_slime, MonsterCategory.slime, mines_floor_60, 1) -red_slime = create_monster(Monster.red_slime, MonsterCategory.slime, mines_floor_100, 2) -purple_slime = create_monster(Monster.purple_slime, MonsterCategory.slime, skull_cavern, 3) -yellow_slime = create_monster(Monster.yellow_slime, MonsterCategory.slime, skull_cavern_high, 4) -black_slime = create_monster(Monster.black_slime, MonsterCategory.slime, slime_hutch, 1) -copper_slime = create_monster(Monster.copper_slime, MonsterCategory.slime, quarry_mine, 1) -iron_slime = create_monster(Monster.iron_slime, MonsterCategory.slime, quarry_mine, 2) -tiger_slime = create_monster(Monster.tiger_slime, MonsterCategory.slime, tiger_slime_grove, 4) - -shadow_shaman = create_monster(Monster.shadow_shaman, MonsterCategory.void_spirits, mines_floor_100, 2) -shadow_shaman_dangerous = create_monster(Monster.shadow_shaman_dangerous, MonsterCategory.void_spirits, dangerous_mines_100, 4) -shadow_brute = create_monster(Monster.shadow_brute, MonsterCategory.void_spirits, mines_floor_100, 2) -shadow_brute_dangerous = create_monster(Monster.shadow_brute_dangerous, MonsterCategory.void_spirits, dangerous_mines_100, 4) -shadow_sniper = create_monster(Monster.shadow_sniper, MonsterCategory.void_spirits, dangerous_mines_100, 4) - -bat = create_monster(Monster.bat, MonsterCategory.bats, mines_floor_20, 0) -bat_dangerous = create_monster(Monster.bat_dangerous, MonsterCategory.bats, dangerous_mines_20, 4) -frost_bat = create_monster(Monster.frost_bat, MonsterCategory.bats, mines_floor_60, 1) -frost_bat_dangerous = create_monster(Monster.frost_bat_dangerous, MonsterCategory.bats, dangerous_mines_60, 4) -lava_bat = create_monster(Monster.lava_bat, MonsterCategory.bats,mines_floor_100, 2) -iridium_bat = create_monster(Monster.iridium_bat, MonsterCategory.bats, skull_cavern_high, 3) - -skeleton = create_monster(Monster.skeleton, MonsterCategory.skeletons, mines_floor_100, 2) -skeleton_dangerous = create_monster(Monster.skeleton_dangerous, MonsterCategory.skeletons, dangerous_mines_100, 4) -skeleton_mage = create_monster(Monster.skeleton_mage, MonsterCategory.skeletons, dangerous_mines_100, 4) - -bug = create_monster(Monster.bug, MonsterCategory.cave_insects, mines_floor_20, 0) -bug_dangerous = create_monster(Monster.bug_dangerous, MonsterCategory.cave_insects, dangerous_mines_20, 4) -cave_fly = create_monster(Monster.cave_fly, MonsterCategory.cave_insects, mines_floor_20, 0) -cave_fly_dangerous = create_monster(Monster.cave_fly_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, 4) -grub = create_monster(Monster.grub, MonsterCategory.cave_insects, mines_floor_20, 0) -grub_dangerous = create_monster(Monster.grub_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, 4) -mutant_fly = create_monster(Monster.mutant_fly, MonsterCategory.cave_insects, mutant_bug_lair, 2) -mutant_grub = create_monster(Monster.mutant_grub, MonsterCategory.cave_insects, mutant_bug_lair, 2) -armored_bug = create_monster(Monster.armored_bug, MonsterCategory.cave_insects, skull_cavern, 0) # Requires 'Bug Killer' enchantment -armored_bug_dangerous = create_monster(Monster.armored_bug_dangerous, MonsterCategory.cave_insects, skull_cavern, 2) # Requires 'Bug Killer' enchantment - -duggy = create_monster(Monster.duggy, MonsterCategory.duggies, mines_floor_20, 0) -duggy_dangerous = create_monster(Monster.duggy_dangerous, MonsterCategory.duggies, dangerous_mines_20, 3) -magma_duggy = create_monster(Monster.magma_duggy, MonsterCategory.duggies, volcano, 4) - -dust_sprite = create_monster(Monster.dust_sprite, MonsterCategory.dust_sprites, mines_floor_60, 0) -dust_sprite_dangerous = create_monster(Monster.dust_sprite_dangerous, MonsterCategory.dust_sprites, dangerous_mines_60, 3) - -rock_crab = create_monster(Monster.rock_crab, MonsterCategory.rock_crabs, mines_floor_20, 0) -rock_crab_dangerous = create_monster(Monster.rock_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_20, 3) -lava_crab = create_monster(Monster.lava_crab, MonsterCategory.rock_crabs, mines_floor_100, 2) -lava_crab_dangerous = create_monster(Monster.lava_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_100, 4) -iridium_crab = create_monster(Monster.iridium_crab, MonsterCategory.rock_crabs, skull_cavern, 3) - -mummy = create_monster(Monster.mummy, MonsterCategory.mummies, skull_cavern, 3) # Requires bombs or "Crusader" enchantment -mummy_dangerous = create_monster(Monster.mummy_dangerous, MonsterCategory.mummies, skull_cavern_dangerous, 4) # Requires bombs or "Crusader" enchantment - -pepper_rex = create_monster(Monster.pepper_rex, MonsterCategory.pepper_rex, skull_cavern, 3) - -serpent = create_monster(Monster.serpent, MonsterCategory.serpents, skull_cavern, 4) -royal_serpent = create_monster(Monster.royal_serpent, MonsterCategory.serpents, skull_cavern_dangerous, 5) - -magma_sprite = create_monster(Monster.magma_sprite, MonsterCategory.magma_sprites, volcano, 4) -magma_sparker = create_monster(Monster.magma_sparker, MonsterCategory.magma_sprites, volcano_high, 4) +green_slime = create_monster(Monster.green_slime, MonsterCategory.slime, mines_floor_20, Performance.basic) +blue_slime = create_monster(Monster.blue_slime, MonsterCategory.slime, mines_floor_60, Performance.decent) +red_slime = create_monster(Monster.red_slime, MonsterCategory.slime, mines_floor_100, Performance.good) +purple_slime = create_monster(Monster.purple_slime, MonsterCategory.slime, skull_cavern, Performance.great) +yellow_slime = create_monster(Monster.yellow_slime, MonsterCategory.slime, skull_cavern_high, Performance.galaxy) +black_slime = create_monster(Monster.black_slime, MonsterCategory.slime, slime_hutch, Performance.decent) +copper_slime = create_monster(Monster.copper_slime, MonsterCategory.slime, quarry_mine, Performance.decent) +iron_slime = create_monster(Monster.iron_slime, MonsterCategory.slime, quarry_mine, Performance.good) +tiger_slime = create_monster(Monster.tiger_slime, MonsterCategory.slime, tiger_slime_grove, Performance.galaxy) + +shadow_shaman = create_monster(Monster.shadow_shaman, MonsterCategory.void_spirits, mines_floor_100, Performance.good) +shadow_shaman_dangerous = create_monster(Monster.shadow_shaman_dangerous, MonsterCategory.void_spirits, dangerous_mines_100, Performance.galaxy) +shadow_brute = create_monster(Monster.shadow_brute, MonsterCategory.void_spirits, mines_floor_100, Performance.good) +shadow_brute_dangerous = create_monster(Monster.shadow_brute_dangerous, MonsterCategory.void_spirits, dangerous_mines_100, Performance.galaxy) +shadow_sniper = create_monster(Monster.shadow_sniper, MonsterCategory.void_spirits, dangerous_mines_100, Performance.galaxy) + +bat = create_monster(Monster.bat, MonsterCategory.bats, mines_floor_20, Performance.basic) +bat_dangerous = create_monster(Monster.bat_dangerous, MonsterCategory.bats, dangerous_mines_20, Performance.galaxy) +frost_bat = create_monster(Monster.frost_bat, MonsterCategory.bats, mines_floor_60, Performance.decent) +frost_bat_dangerous = create_monster(Monster.frost_bat_dangerous, MonsterCategory.bats, dangerous_mines_60, Performance.galaxy) +lava_bat = create_monster(Monster.lava_bat, MonsterCategory.bats,mines_floor_100, Performance.good) +iridium_bat = create_monster(Monster.iridium_bat, MonsterCategory.bats, skull_cavern_high, Performance.great) + +skeleton = create_monster(Monster.skeleton, MonsterCategory.skeletons, mines_floor_100, Performance.good) +skeleton_dangerous = create_monster(Monster.skeleton_dangerous, MonsterCategory.skeletons, dangerous_mines_100, Performance.galaxy) +skeleton_mage = create_monster(Monster.skeleton_mage, MonsterCategory.skeletons, dangerous_mines_100, Performance.galaxy) + +bug = create_monster(Monster.bug, MonsterCategory.cave_insects, mines_floor_20, Performance.basic) +bug_dangerous = create_monster(Monster.bug_dangerous, MonsterCategory.cave_insects, dangerous_mines_20, Performance.galaxy) +cave_fly = create_monster(Monster.cave_fly, MonsterCategory.cave_insects, mines_floor_20, Performance.basic) +cave_fly_dangerous = create_monster(Monster.cave_fly_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, Performance.galaxy) +grub = create_monster(Monster.grub, MonsterCategory.cave_insects, mines_floor_20, Performance.basic) +grub_dangerous = create_monster(Monster.grub_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, Performance.galaxy) +mutant_fly = create_monster(Monster.mutant_fly, MonsterCategory.cave_insects, mutant_bug_lair, Performance.good) +mutant_grub = create_monster(Monster.mutant_grub, MonsterCategory.cave_insects, mutant_bug_lair, Performance.good) +armored_bug = create_monster(Monster.armored_bug, MonsterCategory.cave_insects, skull_cavern, Performance.basic) # Requires 'Bug Killer' enchantment +armored_bug_dangerous = create_monster(Monster.armored_bug_dangerous, MonsterCategory.cave_insects, skull_cavern, Performance.good) # Requires 'Bug Killer' enchantment + +duggy = create_monster(Monster.duggy, MonsterCategory.duggies, mines_floor_20, Performance.basic) +duggy_dangerous = create_monster(Monster.duggy_dangerous, MonsterCategory.duggies, dangerous_mines_20, Performance.great) +magma_duggy = create_monster(Monster.magma_duggy, MonsterCategory.duggies, volcano, Performance.galaxy) + +dust_sprite = create_monster(Monster.dust_sprite, MonsterCategory.dust_sprites, mines_floor_60, Performance.basic) +dust_sprite_dangerous = create_monster(Monster.dust_sprite_dangerous, MonsterCategory.dust_sprites, dangerous_mines_60, Performance.great) + +rock_crab = create_monster(Monster.rock_crab, MonsterCategory.rock_crabs, mines_floor_20, Performance.basic) +rock_crab_dangerous = create_monster(Monster.rock_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_20, Performance.great) +lava_crab = create_monster(Monster.lava_crab, MonsterCategory.rock_crabs, mines_floor_100, Performance.good) +lava_crab_dangerous = create_monster(Monster.lava_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_100, Performance.galaxy) +iridium_crab = create_monster(Monster.iridium_crab, MonsterCategory.rock_crabs, skull_cavern, Performance.great) + +mummy = create_monster(Monster.mummy, MonsterCategory.mummies, skull_cavern, Performance.great) # Requires bombs or "Crusader" enchantment +mummy_dangerous = create_monster(Monster.mummy_dangerous, MonsterCategory.mummies, skull_cavern_dangerous, Performance.maximum) # Requires bombs or "Crusader" enchantment + +pepper_rex = create_monster(Monster.pepper_rex, MonsterCategory.pepper_rex, skull_cavern, Performance.great) + +serpent = create_monster(Monster.serpent, MonsterCategory.serpents, skull_cavern, Performance.galaxy) +royal_serpent = create_monster(Monster.royal_serpent, MonsterCategory.serpents, skull_cavern_dangerous, Performance.maximum) + +magma_sprite = create_monster(Monster.magma_sprite, MonsterCategory.magma_sprites, volcano, Performance.galaxy) +magma_sparker = create_monster(Monster.magma_sparker, MonsterCategory.magma_sprites, volcano_high, Performance.galaxy) all_monsters_by_name = {monster.name: monster for monster in all_monsters} all_monsters_by_category = {} diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index 9ce76459b39d..82d8ed75e27b 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -171,8 +171,7 @@ class Artifact: class Mineral: - quartz = create_mineral("Quartz", 80, Region.mines_floor_20, - monsters=Monster.stone_golem) + quartz = create_mineral("Quartz", 80, Region.mines_floor_20) fire_quartz = create_mineral("Fire Quartz", 82, Region.mines_floor_100, geodes=(Geode.magma, Geode.omni, common.fishing_chest), difficulty=1.0 / 12.0) diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 064c68b86c08..1d7a19b82f78 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -67,6 +67,7 @@ class LocationTags(enum.Enum): MONSTERSANITY_GOALS = enum.auto() MONSTERSANITY_PROGRESSIVE_GOALS = enum.auto() MONSTERSANITY_MONSTER = enum.auto() + SHIPSANITY = enum.auto() # Skill Mods LUCK_LEVEL = enum.auto() BINNING_LEVEL = enum.auto() diff --git a/worlds/stardew_valley/logic.py b/worlds/stardew_valley/logic.py deleted file mode 100644 index 0c2fb1cab573..000000000000 --- a/worlds/stardew_valley/logic.py +++ /dev/null @@ -1,1722 +0,0 @@ -from __future__ import annotations - -import math -from dataclasses import dataclass, field -from typing import Dict, Union, Optional, Iterable, Sized, List, Set - -from .data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops, CropItem -from .data.bundle_data import BundleItem -from .data.crops_data import crops_by_name -from .data.fish_data import island_fish -from .data.museum_data import all_museum_items, MuseumItem, all_museum_artifacts, all_museum_minerals -from .data.recipe_data import all_cooking_recipes, CookingRecipe, RecipeSource, FriendshipSource, QueenOfSauceSource, \ - StarterSource, ShopSource, SkillSource -from .data.villagers_data import all_villagers_by_name, Villager -from .items import all_items, Group -from .mods.logic.buildings import get_modded_building_rules -from .mods.logic.quests import get_modded_quest_rules -from .mods.logic.special_orders import get_modded_special_orders_rules -from .mods.mod_data import ModNames -from .mods.logic import magic, skills -from .options import Museumsanity, SeasonRandomization, StardewValleyOptions, BuildingProgression, SkillProgression, ToolProgression, Friendsanity, Cropsanity, \ - ExcludeGingerIsland, ElevatorProgression, ArcadeMachineLocations, FestivalLocations, SpecialOrderLocations -from .regions import vanilla_regions -from .stardew_rule import False_, Reach, Or, True_, Received, Count, And, Has, TotalReceived, StardewRule -from .strings.animal_names import Animal, coop_animals, barn_animals -from .strings.animal_product_names import AnimalProduct -from .strings.ap_names.buff_names import Buff -from .strings.ap_names.transport_names import Transportation -from .strings.artisan_good_names import ArtisanGood -from .strings.building_names import Building -from .strings.calendar_names import Weekday -from .strings.craftable_names import Craftable -from .strings.crop_names import Fruit, Vegetable, all_fruits, all_vegetables -from .strings.fertilizer_names import Fertilizer -from .strings.festival_check_names import FestivalCheck -from .strings.fish_names import Fish, Trash, WaterItem -from .strings.flower_names import Flower -from .strings.forageable_names import Forageable -from .strings.fruit_tree_names import Sapling -from .strings.generic_names import Generic -from .strings.geode_names import Geode -from .strings.gift_names import Gift -from .strings.ingredient_names import Ingredient -from .strings.material_names import Material -from .strings.machine_names import Machine -from .strings.food_names import Meal, Beverage -from .strings.metal_names import Ore, MetalBar, Mineral, Fossil -from .strings.monster_drop_names import Loot -from .strings.performance_names import Performance -from .strings.quest_names import Quest -from .strings.region_names import Region -from .strings.season_names import Season -from .strings.seed_names import Seed -from .strings.skill_names import Skill, ModSkill -from .strings.special_order_names import SpecialOrder -from .strings.spells import MagicSpell -from .strings.tool_names import Tool, ToolMaterial, APTool -from .strings.tv_channel_names import Channel -from .strings.villager_names import NPC -from .strings.wallet_item_names import Wallet -from .strings.weapon_names import Weapon - -MAX_MONTHS = 12 -MONEY_PER_MONTH = 15000 -MISSING_ITEM = "THIS ITEM IS MISSING" - -tool_materials = { - ToolMaterial.copper: 1, - ToolMaterial.iron: 2, - ToolMaterial.gold: 3, - ToolMaterial.iridium: 4 -} - -tool_upgrade_prices = { - ToolMaterial.copper: 2000, - ToolMaterial.iron: 5000, - ToolMaterial.gold: 10000, - ToolMaterial.iridium: 25000 -} - -fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] - - -@dataclass(frozen=False, repr=False) -class StardewLogic: - player: int - options: StardewValleyOptions - - item_rules: Dict[str, StardewRule] = field(default_factory=dict) - sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) - tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) - seed_rules: Dict[str, StardewRule] = field(default_factory=dict) - cooking_rules: Dict[str, StardewRule] = field(default_factory=dict) - crop_rules: Dict[str, StardewRule] = field(default_factory=dict) - fish_rules: Dict[str, StardewRule] = field(default_factory=dict) - museum_rules: Dict[str, StardewRule] = field(default_factory=dict) - building_rules: Dict[str, StardewRule] = field(default_factory=dict) - quest_rules: Dict[str, StardewRule] = field(default_factory=dict) - festival_rules: Dict[str, StardewRule] = field(default_factory=dict) - special_order_rules: Dict[str, StardewRule] = field(default_factory=dict) - cached_rules: Dict[str, StardewRule] = field(default_factory=dict) - - def __post_init__(self): - self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) - self.museum_rules.update({donation.name: self.can_find_museum_item(donation) for donation in all_museum_items}) - - for recipe in all_cooking_recipes: - can_cook_rule = self.can_cook(recipe) - if recipe.meal in self.cooking_rules: - can_cook_rule = can_cook_rule | self.cooking_rules[recipe.meal] - self.cooking_rules[recipe.meal] = can_cook_rule - - self.sapling_rules.update({ - Sapling.apple: self.can_buy_sapling(Fruit.apple), - Sapling.apricot: self.can_buy_sapling(Fruit.apricot), - Sapling.cherry: self.can_buy_sapling(Fruit.cherry), - Sapling.orange: self.can_buy_sapling(Fruit.orange), - Sapling.peach: self.can_buy_sapling(Fruit.peach), - Sapling.pomegranate: self.can_buy_sapling(Fruit.pomegranate), - Sapling.banana: self.can_buy_sapling(Fruit.banana), - Sapling.mango: self.can_buy_sapling(Fruit.mango), - }) - - self.tree_fruit_rules.update({ - Fruit.apple: self.can_plant_and_grow_item(Season.fall), - Fruit.apricot: self.can_plant_and_grow_item(Season.spring), - Fruit.cherry: self.can_plant_and_grow_item(Season.spring), - Fruit.orange: self.can_plant_and_grow_item(Season.summer), - Fruit.peach: self.can_plant_and_grow_item(Season.summer), - Fruit.pomegranate: self.can_plant_and_grow_item(Season.fall), - Fruit.banana: self.can_plant_and_grow_item(Season.summer), - Fruit.mango: self.can_plant_and_grow_item(Season.summer), - }) - - for tree_fruit in self.tree_fruit_rules: - existing_rules = self.tree_fruit_rules[tree_fruit] - sapling = f"{tree_fruit} Sapling" - self.tree_fruit_rules[tree_fruit] = existing_rules & self.has(sapling) & self.has_lived_months(1) - - self.seed_rules.update({seed.name: self.can_buy_seed(seed) for seed in all_purchasable_seeds}) - self.crop_rules.update({crop.name: self.can_grow_crop(crop) for crop in all_crops}) - self.crop_rules.update({ - Seed.coffee: (self.has_season(Season.spring) | self.has_season( - Season.summer)) & self.can_buy_seed(crops_by_name[Seed.coffee].seed), - Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & - self.can_reach_region(Region.greenhouse) & self.has(Machine.seed_maker), - }) - - self.item_rules.update({ - ArtisanGood.aged_roe: self.can_preserves_jar(AnimalProduct.roe), - AnimalProduct.any_egg: self.has(AnimalProduct.chicken_egg) | self.has(AnimalProduct.duck_egg), - Fish.any: Or([self.can_catch_fish(fish) for fish in all_fish]), - Geode.artifact_trove: self.has(Geode.omni) & self.can_reach_region(Region.desert), - Craftable.bait: (self.has_skill_level(Skill.fishing, 2) & self.has(Loot.bug_meat)) | self.has(Machine.worm_bin), - Fertilizer.basic: (self.has(Material.sap) & self.has_farming_level(1)) | (self.has_lived_months(1) & self.can_spend_money_at(Region.pierre_store, 100)), - Fertilizer.quality: (self.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.has_year_two() & self.can_spend_money_at(Region.pierre_store, 150)), - Fertilizer.deluxe: False_(), - # self.received("Deluxe Fertilizer Recipe") & self.has(MetalBar.iridium) & self.has(SVItem.sap), - Fertilizer.tree: self.has_skill_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), - Loot.bat_wing: self.can_mine_in_the_mines_floor_41_80() | self.can_mine_in_the_skull_cavern(), - ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.has_any_season_not_winter()) | self.has(Machine.solar_panel), - Machine.bee_house: self.has_farming_level(3) & self.has(MetalBar.iron) & self.has(ArtisanGood.maple_syrup) & self.has(Material.coal) & self.has(Material.wood), - Beverage.beer: self.can_keg(Vegetable.wheat) | self.can_spend_money_at(Region.saloon, 400), - Forageable.blackberry: self.can_forage(Season.fall), - Craftable.bomb: self.has_skill_level(Skill.mining, 6) & self.has(Material.coal) & self.has(Ore.iron), - Fossil.bone_fragment: self.can_reach_region(Region.dig_site), - Gift.bouquet: self.has_relationship(Generic.bachelor, 8) & self.can_spend_money_at(Region.pierre_store, 100), - Meal.bread: self.can_spend_money_at(Region.saloon, 120), - Trash.broken_cd: self.can_crab_pot(), - Trash.broken_glasses: self.can_crab_pot(), - Loot.bug_meat: self.can_mine_in_the_mines_floor_1_40(), - Forageable.cactus_fruit: self.can_forage(Generic.any, Region.desert), - Machine.cask: self.has_house(3) & self.can_reach_region(Region.cellar) & self.has(Material.wood) & self.has(Material.hardwood), - Forageable.cave_carrot: self.can_forage(Generic.any, Region.mines_floor_10, True), - ArtisanGood.caviar: self.can_preserves_jar(AnimalProduct.sturgeon_roe), - Forageable.chanterelle: self.can_forage(Season.fall, Region.secret_woods), - Machine.cheese_press: self.has_farming_level(6) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.hardwood) & self.has(MetalBar.copper), - ArtisanGood.cheese: (self.has(AnimalProduct.cow_milk) & self.has(Machine.cheese_press)) | (self.can_reach_region(Region.desert) & self.has(Mineral.emerald)), - Craftable.cherry_bomb: self.has_skill_level(Skill.mining, 1) & self.has(Material.coal) & self.has(Ore.copper), - Animal.chicken: self.can_buy_animal(Animal.chicken), - AnimalProduct.chicken_egg: self.has([AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg], 1), - Material.cinder_shard: self.can_reach_region(Region.volcano_floor_5), - WaterItem.clam: self.can_forage(Generic.any, Region.beach), - Material.clay: self.can_reach_any_region([Region.farm, Region.beach, Region.quarry]) & self.has_tool(Tool.hoe), - ArtisanGood.cloth: (self.has(AnimalProduct.wool) & self.has(Machine.loom)) | (self.can_reach_region(Region.desert) & self.has(Mineral.aquamarine)), - Material.coal: self.can_mine_in_the_mines_floor_41_80() | self.can_do_panning(), - WaterItem.cockle: self.can_forage(Generic.any, Region.beach), - Forageable.coconut: self.can_forage(Generic.any, Region.desert), - Beverage.coffee: self.can_keg(Seed.coffee) | self.has(Machine.coffee_maker) | (self.can_spend_money_at(Region.saloon, 300)) | self.has("Hot Java Ring"), - Machine.coffee_maker: self.received(Machine.coffee_maker), - Forageable.common_mushroom: self.can_forage(Season.fall) | (self.can_forage(Season.spring, Region.secret_woods)), - MetalBar.copper: self.can_smelt(Ore.copper), - Ore.copper: self.can_mine_in_the_mines_floor_1_40() | self.can_mine_in_the_skull_cavern() | self.can_do_panning(), - WaterItem.coral: self.can_forage(Generic.any, Region.tide_pools) | self.can_forage(Season.summer, Region.beach), - Animal.cow: self.can_buy_animal(Animal.cow), - AnimalProduct.cow_milk: self.has(AnimalProduct.milk) | self.has(AnimalProduct.large_milk), - Fish.crab: self.can_crab_pot(Region.beach), - Machine.crab_pot: self.has_skill_level(Skill.fishing, 3) & (self.can_spend_money_at(Region.fish_shop, 1500) | (self.has(MetalBar.iron) & self.has(Material.wood))), - Fish.crayfish: self.can_crab_pot(Region.town), - Forageable.crocus: self.can_forage(Season.winter), - Forageable.crystal_fruit: self.can_forage(Season.winter), - Forageable.daffodil: self.can_forage(Season.spring), - Forageable.dandelion: self.can_forage(Season.spring), - Animal.dinosaur: self.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), - Forageable.dragon_tooth: self.can_forage(Generic.any, Region.volcano_floor_10), - "Dried Starfish": self.can_fish() & self.can_reach_region(Region.beach), - Trash.driftwood: self.can_crab_pot(), - AnimalProduct.duck_egg: self.has_animal(Animal.duck), - AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), - Animal.duck: self.can_buy_animal(Animal.duck), - AnimalProduct.egg: self.has_animal(Animal.chicken), - AnimalProduct.brown_egg: self.has_animal(Animal.chicken), - "Energy Tonic": self.can_reach_region(Region.hospital) & self.can_spend_money(1000), - Material.fiber: True_(), - Forageable.fiddlehead_fern: self.can_forage(Season.summer, Region.secret_woods), - "Magic Rock Candy": self.can_reach_region(Region.desert) & self.has("Prismatic Shard"), - "Fishing Chest": self.can_fish_chests(), - Craftable.flute_block: self.has_relationship(NPC.robin, 6) & self.can_reach_region(Region.carpenter) & self.has(Material.wood) & self.has(Ore.copper) & self.has(Material.fiber), - Geode.frozen: self.can_mine_in_the_mines_floor_41_80(), - Machine.furnace: self.has(Material.stone) & self.has(Ore.copper), - Geode.geode: self.can_mine_in_the_mines_floor_1_40(), - Forageable.ginger: self.can_forage(Generic.any, Region.island_west, True), - ArtisanGood.goat_cheese: self.has(AnimalProduct.goat_milk) & self.has(Machine.cheese_press), - AnimalProduct.goat_milk: self.has(Animal.goat), - Animal.goat: self.can_buy_animal(Animal.goat), - MetalBar.gold: self.can_smelt(Ore.gold), - Ore.gold: self.can_mine_in_the_mines_floor_81_120() | self.can_mine_in_the_skull_cavern() | self.can_do_panning(), - Geode.golden_coconut: self.can_reach_region(Region.island_north), - Gift.golden_pumpkin: self.has_season(Season.fall) | self.can_open_geode(Geode.artifact_trove), - WaterItem.green_algae: self.can_fish_in_freshwater(), - ArtisanGood.green_tea: self.can_keg(Vegetable.tea_leaves), - Material.hardwood: self.has_tool(Tool.axe, ToolMaterial.copper) & (self.can_reach_region(Region.secret_woods) | self.can_reach_region(Region.island_south)), - Forageable.hay: self.has_building(Building.silo) & self.has_tool(Tool.scythe), - Forageable.hazelnut: self.can_forage(Season.fall), - Forageable.holly: self.can_forage(Season.winter), - ArtisanGood.honey: self.can_spend_money_at(Region.oasis, 200) | (self.has(Machine.bee_house) & self.has_any_season_not_winter()), - "Hot Java Ring": self.can_reach_region(Region.volcano_floor_10), - Meal.ice_cream: (self.has_season(Season.summer) & self.can_spend_money_at(Region.town, 250)) | self.can_spend_money_at(Region.oasis, 240), - # | (self.can_cook() & self.has_relationship(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)), - MetalBar.iridium: self.can_smelt(Ore.iridium), - Ore.iridium: self.can_mine_in_the_skull_cavern(), - MetalBar.iron: self.can_smelt(Ore.iron), - Ore.iron: self.can_mine_in_the_mines_floor_41_80() | self.can_mine_in_the_skull_cavern() | self.can_do_panning(), - ArtisanGood.jelly: self.has_jelly(), - Trash.joja_cola: self.can_spend_money_at(Region.saloon, 75), - "JotPK Small Buff": self.has_jotpk_power_level(2), - "JotPK Medium Buff": self.has_jotpk_power_level(4), - "JotPK Big Buff": self.has_jotpk_power_level(7), - "JotPK Max Buff": self.has_jotpk_power_level(9), - ArtisanGood.juice: self.has_juice(), - "Junimo Kart Small Buff": self.has_junimo_kart_power_level(2), - "Junimo Kart Medium Buff": self.has_junimo_kart_power_level(4), - "Junimo Kart Big Buff": self.has_junimo_kart_power_level(6), - "Junimo Kart Max Buff": self.has_junimo_kart_power_level(8), - Machine.keg: self.has_farming_level(8) & self.has(Material.wood) & self.has(MetalBar.iron) & self.has(MetalBar.copper) & self.has(ArtisanGood.oak_resin), - AnimalProduct.large_egg: self.has_happy_animal(Animal.chicken), - AnimalProduct.large_brown_egg: self.has_happy_animal(Animal.chicken), - AnimalProduct.large_goat_milk: self.has_happy_animal(Animal.goat), - AnimalProduct.large_milk: self.has_happy_animal(Animal.cow), - Forageable.leek: self.can_forage(Season.spring), - Craftable.life_elixir: self.has_skill_level(Skill.combat, 2) & self.has(Forageable.red_mushroom) & self.has(Forageable.purple_mushroom) & self.has(Forageable.morel) & self.has(Forageable.chanterelle), - Machine.lightning_rod: self.has_skill_level(Skill.foraging, 6) & self.has(MetalBar.iron) & self.has(MetalBar.quartz) & self.has(Loot.bat_wing), - Fish.lobster: self.can_crab_pot(Region.beach), - Machine.loom: self.has_farming_level(7) & self.has(Material.wood) & self.has(Material.fiber) & self.has(ArtisanGood.pine_tar), - Forageable.magma_cap: self.can_forage(Generic.any, Region.volcano_floor_5), - Geode.magma: self.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.has_building(Building.fish_pond)), - ArtisanGood.maple_syrup: self.has(Machine.tapper), - ArtisanGood.mayonnaise: self.has(Machine.mayonnaise_machine) & self.has(AnimalProduct.chicken_egg), - Machine.mayonnaise_machine: self.has_farming_level(2) & self.has(Material.wood) & self.has(Material.stone) & self.has("Earth Crystal") & self.has(MetalBar.copper), - ArtisanGood.mead: self.can_keg(ArtisanGood.honey), - Craftable.mega_bomb: self.has_skill_level(Skill.mining, 8) & self.has(Ore.gold) & self.has(Loot.solar_essence) & self.has(Loot.void_essence), - Gift.mermaid_pendant: self.can_reach_region(Region.tide_pools) & self.has_relationship(Generic.bachelor, 10) & self.has_house(1) & self.has(Craftable.rain_totem), - AnimalProduct.milk: self.has_animal(Animal.cow), - Craftable.monster_musk: self.has_prismatic_jelly_reward_access() & self.has(Loot.slime) & self.has(Loot.bat_wing), - Forageable.morel: self.can_forage(Season.spring, Region.secret_woods), - "Muscle Remedy": self.can_reach_region(Region.hospital) & self.can_spend_money(1000), - Fish.mussel: self.can_forage(Generic.any, Region.beach) or self.has(Fish.mussel_node), - Fish.mussel_node: self.can_reach_region(Region.island_west), - WaterItem.nautilus_shell: self.can_forage(Season.winter, Region.beach), - ArtisanGood.oak_resin: self.has(Machine.tapper), - Ingredient.oil: self.can_spend_money_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), - Machine.oil_maker: self.has_farming_level(8) & self.has(Loot.slime) & self.has(Material.hardwood) & self.has(MetalBar.gold), - Craftable.oil_of_garlic: (self.has_skill_level(Skill.combat, 6) & self.has(Vegetable.garlic) & self.has(Ingredient.oil)) | (self.can_spend_money_at(Region.mines_dwarf_shop, 3000)), - Geode.omni: self.can_mine_in_the_mines_floor_41_80() | self.can_reach_region(Region.desert) | self.can_do_panning() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.has_building(Building.fish_pond)) | self.can_reach_region(Region.volcano_floor_10), - Animal.ostrich: self.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), - AnimalProduct.ostrich_egg: self.can_forage(Generic.any, Region.island_north, True), - Machine.ostrich_incubator: self.received("Ostrich Incubator Recipe") & self.has(Fossil.bone_fragment) & self.has(Material.hardwood) & self.has(Material.cinder_shard), - Fish.oyster: self.can_forage(Generic.any, Region.beach), - ArtisanGood.pale_ale: self.can_keg(Vegetable.hops), - Gift.pearl: (self.has(Fish.blobfish) & self.has_building(Building.fish_pond)) | self.can_open_geode(Geode.artifact_trove), - Fish.periwinkle: self.can_crab_pot(Region.town), - ArtisanGood.pickles: self.has_pickle(), - Animal.pig: self.can_buy_animal(Animal.pig), - Beverage.pina_colada: self.can_spend_money_at(Region.island_resort, 600), - ArtisanGood.pine_tar: self.has(Machine.tapper), - Meal.pizza: self.can_spend_money_at(Region.saloon, 600), - Machine.preserves_jar: self.has_farming_level(4) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.coal), - Forageable.purple_mushroom: self.can_forage(Generic.any, Region.mines_floor_95) | self.can_forage(Generic.any, Region.skull_cavern_25), - Animal.rabbit: self.can_buy_animal(Animal.rabbit), - AnimalProduct.rabbit_foot: self.has_happy_animal(Animal.rabbit), - MetalBar.radioactive: self.can_smelt(Ore.radioactive), - Ore.radioactive: self.can_mine_perfectly() & self.can_reach_region(Region.qi_walnut_room), - Forageable.rainbow_shell: self.can_forage(Season.summer, Region.beach), - Craftable.rain_totem: self.has_skill_level(Skill.foraging, 9) & self.has(Material.hardwood) & self.has(ArtisanGood.truffle_oil) & self.has(ArtisanGood.pine_tar), - Machine.recycling_machine: self.has_skill_level(Skill.fishing, 4) & self.has(Material.wood) & self.has(Material.stone) & self.has(MetalBar.iron), - Forageable.red_mushroom: self.can_forage(Season.summer, Region.secret_woods) | self.can_forage(Season.fall, Region.secret_woods), - MetalBar.quartz: self.can_smelt("Quartz") | self.can_smelt("Fire Quartz") | - (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), - Ingredient.rice: self.can_spend_money_at(Region.pierre_store, 200) | ( - self.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), - AnimalProduct.roe: self.can_fish() & self.has_building(Building.fish_pond), - Meal.salad: self.can_spend_money_at(Region.saloon, 220), - # | (self.can_cook() & self.has_relationship(NPC.emily, 3) & self.has(Forageable.leek) & self.has(Forageable.dandelion) & - # self.has(Ingredient.vinegar)), - Forageable.salmonberry: self.can_forage(Season.spring), - Material.sap: self.can_chop_trees(), - Craftable.scarecrow: self.has_farming_level(1) & self.has(Material.wood) & self.has(Material.coal) & self.has(Material.fiber), - WaterItem.sea_urchin: self.can_forage(Generic.any, Region.tide_pools), - WaterItem.seaweed: (self.can_fish() & self.can_reach_region(Region.beach)) | self.can_reach_region( - Region.tide_pools), - Forageable.secret_note: self.received(Wallet.magnifying_glass) & (self.can_chop_trees() | self.can_mine_in_the_mines_floor_1_40()), - Machine.seed_maker: self.has_farming_level(9) & self.has(Material.wood) & self.has(MetalBar.gold) & self.has( - Material.coal), - Animal.sheep: self.can_buy_animal(Animal.sheep), - Fish.shrimp: self.can_crab_pot(Region.beach), - Loot.slime: self.can_mine_in_the_mines_floor_1_40(), - Weapon.any_slingshot: self.received(Weapon.slingshot) | self.received(Weapon.master_slingshot), - Fish.snail: self.can_crab_pot(Region.town), - Forageable.snow_yam: self.can_forage(Season.winter, Region.beach, True), - Trash.soggy_newspaper: self.can_crab_pot(), - Loot.solar_essence: self.can_mine_in_the_mines_floor_41_80() | self.can_mine_in_the_skull_cavern(), - Machine.solar_panel: self.received("Solar Panel Recipe") & self.has(MetalBar.quartz) & self.has( - MetalBar.iron) & self.has(MetalBar.gold), - Meal.spaghetti: self.can_spend_money_at(Region.saloon, 240), - Forageable.spice_berry: self.can_forage(Season.summer), - Forageable.spring_onion: self.can_forage(Season.spring), - AnimalProduct.squid_ink: self.can_mine_in_the_mines_floor_81_120() | (self.has_building(Building.fish_pond) & self.has(Fish.squid)), - Craftable.staircase: self.has_skill_level(Skill.mining, 2) & self.has(Material.stone), - Material.stone: self.has_tool(Tool.pickaxe), - Meal.strange_bun: self.has_relationship(NPC.shane, 7) & self.has(Ingredient.wheat_flour) & self.has(Fish.periwinkle) & self.has(ArtisanGood.void_mayonnaise), - AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.has_building(Building.fish_pond), - Ingredient.sugar: self.can_spend_money_at(Region.pierre_store, 100) | ( - self.has_building(Building.mill) & self.has(Vegetable.beet)), - Forageable.sweet_pea: self.can_forage(Season.summer), - Machine.tapper: self.has_skill_level(Skill.foraging, 3) & self.has(Material.wood) & self.has(MetalBar.copper), - Vegetable.tea_leaves: self.has(Sapling.tea) & self.has_lived_months(2) & self.has_any_season_not_winter(), - Sapling.tea: self.has_relationship(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), - Trash.trash: self.can_crab_pot(), - Beverage.triple_shot_espresso: self.has("Hot Java Ring"), - ArtisanGood.truffle_oil: self.has(AnimalProduct.truffle) & self.has(Machine.oil_maker), - AnimalProduct.truffle: self.has_animal(Animal.pig) & self.has_any_season_not_winter(), - Ingredient.vinegar: self.can_spend_money_at(Region.pierre_store, 200), - AnimalProduct.void_egg: self.can_spend_money_at(Region.sewer, 5000) | (self.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), - Loot.void_essence: self.can_mine_in_the_mines_floor_81_120() | self.can_mine_in_the_skull_cavern(), - ArtisanGood.void_mayonnaise: (self.can_reach_region(Region.witch_swamp) & self.can_fish()) | (self.has(Machine.mayonnaise_machine) & self.has(AnimalProduct.void_egg)), - Ingredient.wheat_flour: self.can_spend_money_at(Region.pierre_store, 100) | - (self.has_building(Building.mill) & self.has(Vegetable.wheat)), - WaterItem.white_algae: self.can_fish() & self.can_reach_region(Region.mines_floor_20), - Forageable.wild_horseradish: self.can_forage(Season.spring), - Forageable.wild_plum: self.can_forage(Season.fall), - Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), - ArtisanGood.wine: self.has_wine(), - Forageable.winter_root: self.can_forage(Season.winter, Region.forest, True), - Material.wood: self.has_tool(Tool.axe), - AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), - Machine.worm_bin: self.has_skill_level(Skill.fishing, 8) & self.has(Material.hardwood) & self.has(MetalBar.gold) & self.has(MetalBar.iron) & self.has(Material.fiber), - }) - self.item_rules.update(self.fish_rules) - self.item_rules.update(self.museum_rules) - self.item_rules.update(self.sapling_rules) - self.item_rules.update(self.tree_fruit_rules) - self.item_rules.update(self.seed_rules) - self.item_rules.update(self.crop_rules) - - # For some recipes, the cooked item can be obtained directly, so we either cook it or get it - for recipe in self.cooking_rules: - cooking_rule = self.cooking_rules[recipe] - obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() - self.item_rules[recipe] = obtention_rule | cooking_rule - - self.building_rules.update({ - Building.barn: self.can_spend_money_at(Region.carpenter, 6000) & self.has([Material.wood, Material.stone]), - Building.big_barn: self.can_spend_money_at(Region.carpenter, 12000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.barn), - Building.deluxe_barn: self.can_spend_money_at(Region.carpenter, 25000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.big_barn), - Building.coop: self.can_spend_money_at(Region.carpenter, 4000) & self.has([Material.wood, Material.stone]), - Building.big_coop: self.can_spend_money_at(Region.carpenter, 10000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.coop), - Building.deluxe_coop: self.can_spend_money_at(Region.carpenter, 20000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.big_coop), - Building.fish_pond: self.can_spend_money_at(Region.carpenter, 5000) & self.has([Material.stone, WaterItem.seaweed, WaterItem.green_algae]), - Building.mill: self.can_spend_money_at(Region.carpenter, 2500) & self.has([Material.stone, Material.wood, ArtisanGood.cloth]), - Building.shed: self.can_spend_money_at(Region.carpenter, 15000) & self.has(Material.wood), - Building.big_shed: self.can_spend_money_at(Region.carpenter, 20000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.shed), - Building.silo: self.can_spend_money_at(Region.carpenter, 100) & self.has([Material.stone, Material.clay, MetalBar.copper]), - Building.slime_hutch: self.can_spend_money_at(Region.carpenter, 10000) & self.has([Material.stone, MetalBar.quartz, MetalBar.iridium]), - Building.stable: self.can_spend_money_at(Region.carpenter, 10000) & self.has([Material.hardwood, MetalBar.iron]), - Building.well: self.can_spend_money_at(Region.carpenter, 1000) & self.has(Material.stone), - Building.shipping_bin: self.can_spend_money_at(Region.carpenter, 250) & self.has(Material.wood), - Building.kitchen: self.can_spend_money_at(Region.carpenter, 10000) & self.has(Material.wood) & self.has_house(0), - Building.kids_room: self.can_spend_money_at(Region.carpenter, 50000) & self.has(Material.hardwood) & self.has_house(1), - Building.cellar: self.can_spend_money_at(Region.carpenter, 100000) & self.has_house(2), - }) - - self.building_rules.update(get_modded_building_rules(self, self.options.mods)) - - self.quest_rules.update({ - Quest.introductions: True_(), - Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), - Quest.getting_started: self.has(Vegetable.parsnip), - Quest.to_the_beach: self.can_reach_region(Region.beach), - Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.has_building(Building.coop), - Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), - Quest.archaeology: self.has_tool(Tool.hoe) | self.can_mine_in_the_mines_floor_1_40() | self.can_fish(), - Quest.rat_problem: self.can_reach_region(Region.town) & self.can_reach_region(Region.community_center), - Quest.meet_the_wizard: self.can_complete_quest(Quest.rat_problem), - Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), - Quest.smelting: self.has(MetalBar.copper), - Quest.initiation: self.can_mine_in_the_mines_floor_1_40(), - Quest.robins_lost_axe: self.has_season(Season.spring) & self.can_meet(NPC.robin), - Quest.jodis_request: self.has_season(Season.spring) & self.has(Vegetable.cauliflower) & self.can_meet(NPC.jodi), - Quest.mayors_shorts: self.has_season(Season.summer) & - (self.has_relationship(NPC.marnie, 2) | (magic.can_blink(self))) & - self.can_meet(NPC.lewis), - Quest.blackberry_basket: self.has_season(Season.fall) & self.can_meet(NPC.linus), - Quest.marnies_request: self.has_relationship(NPC.marnie, 3) & self.has(Forageable.cave_carrot), - Quest.pam_is_thirsty: self.has_season(Season.summer) & self.has(ArtisanGood.pale_ale) & self.can_meet(NPC.pam), - Quest.a_dark_reagent: self.has_season(Season.winter) & self.has(Loot.void_essence) & self.can_meet(NPC.wizard), - Quest.cows_delight: self.has_season(Season.fall) & self.has(Vegetable.amaranth) & self.can_meet(NPC.marnie), - Quest.the_skull_key: self.received(Wallet.skull_key), - Quest.crop_research: self.has_season(Season.summer) & self.has(Fruit.melon) & self.can_meet(NPC.demetrius), - Quest.knee_therapy: self.has_season(Season.summer) & self.has(Fruit.hot_pepper) & self.can_meet(NPC.george), - Quest.robins_request: self.has_season(Season.winter) & self.has(Material.hardwood) & self.can_meet(NPC.robin), - Quest.qis_challenge: True_(), # The skull cavern floor 25 already has rules - Quest.the_mysterious_qi: self.can_reach_region(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.can_reach_region(Region.mayor_house) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), - Quest.carving_pumpkins: self.has_season(Season.fall) & self.has(Vegetable.pumpkin) & self.can_meet(NPC.caroline), - Quest.a_winter_mystery: self.has_season(Season.winter), - Quest.strange_note: self.has(Forageable.secret_note) & self.has(ArtisanGood.maple_syrup), - Quest.cryptic_note: self.has(Forageable.secret_note), - Quest.fresh_fruit: self.has_season(Season.spring) & self.has(Fruit.apricot) & self.can_meet(NPC.emily), - Quest.aquatic_research: self.has_season(Season.summer) & self.has(Fish.pufferfish) & self.can_meet(NPC.demetrius), - Quest.a_soldiers_star: self.has_season(Season.summer) & self.has_year_two() & self.has(Fruit.starfruit) & self.can_meet(NPC.kent), - Quest.mayors_need: self.has_season(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.can_meet(NPC.lewis), - Quest.wanted_lobster: self.has_season(Season.fall) & self.has_season(Season.fall) & self.has(Fish.lobster) & self.can_meet(NPC.gus), - Quest.pam_needs_juice: self.has_season(Season.fall) & self.has(ArtisanGood.battery_pack) & self.can_meet(NPC.pam), - Quest.fish_casserole: self.has_relationship(NPC.jodi, 4) & self.has(Fish.largemouth_bass), - Quest.catch_a_squid: self.has_season(Season.winter) & self.has(Fish.squid) & self.can_meet(NPC.willy), - Quest.fish_stew: self.has_season(Season.winter) & self.has(Fish.albacore) & self.can_meet(NPC.gus), - Quest.pierres_notice: self.has_season(Season.spring) & self.has("Sashimi") & self.can_meet(NPC.pierre), - Quest.clints_attempt: self.has_season(Season.winter) & self.has(Mineral.amethyst) & self.can_meet(NPC.emily), - Quest.a_favor_for_clint: self.has_season(Season.winter) & self.has(MetalBar.iron) & self.can_meet(NPC.clint), - Quest.staff_of_power: self.has_season(Season.winter) & self.has(MetalBar.iridium) & self.can_meet(NPC.wizard), - Quest.grannys_gift: self.has_season(Season.spring) & self.has(Forageable.leek) & self.can_meet(NPC.evelyn), - Quest.exotic_spirits: self.has_season(Season.winter) & self.has(Forageable.coconut) & self.can_meet(NPC.gus), - Quest.catch_a_lingcod: self.has_season(Season.winter) & self.has("Lingcod") & self.can_meet(NPC.willy), - Quest.dark_talisman: self.has_rusty_key() & self.can_meet(NPC.krobus) & self.can_reach_region(Region.mutant_bug_lair), - Quest.goblin_problem: self.has(ArtisanGood.void_mayonnaise), - Quest.magic_ink: self.can_meet(NPC.wizard), - Quest.the_pirates_wife: self.can_meet(NPC.kent) & self.can_meet(NPC.gus) & - self.can_meet(NPC.sandy) & self.can_meet(NPC.george) & - self.can_meet(NPC.wizard) & self.can_meet(NPC.willy), - }) - - self.quest_rules.update(get_modded_quest_rules(self, self.options.mods)) - - self.festival_rules.update({ - FestivalCheck.egg_hunt: self.can_win_egg_hunt(), - FestivalCheck.strawberry_seeds: self.can_spend_money(1000), - FestivalCheck.dance: self.has_relationship(Generic.bachelor, 4), - FestivalCheck.rarecrow_5: self.can_spend_money(2500), - FestivalCheck.luau_soup: self.can_succeed_luau_soup(), - FestivalCheck.moonlight_jellies: True_(), - FestivalCheck.smashing_stone: True_(), - FestivalCheck.grange_display: self.can_succeed_grange_display(), - FestivalCheck.rarecrow_1: True_(), # only cost star tokens - FestivalCheck.fair_stardrop: True_(), # only cost star tokens - FestivalCheck.spirit_eve_maze: True_(), - FestivalCheck.rarecrow_2: self.can_spend_money(5000), - FestivalCheck.fishing_competition: self.can_win_fishing_competition(), - FestivalCheck.rarecrow_4: self.can_spend_money(5000), - FestivalCheck.mermaid_pearl: self.has(Forageable.secret_note), - FestivalCheck.cone_hat: self.can_spend_money(2500), - FestivalCheck.iridium_fireplace: self.can_spend_money(15000), - FestivalCheck.rarecrow_7: self.can_spend_money(5000) & self.can_donate_museum_artifacts(20), - FestivalCheck.rarecrow_8: self.can_spend_money(5000) & self.can_donate_museum_items(40), - FestivalCheck.lupini_red_eagle: self.can_spend_money(1200), - FestivalCheck.lupini_portrait_mermaid: self.can_spend_money(1200), - FestivalCheck.lupini_solar_kingdom: self.can_spend_money(1200), - FestivalCheck.lupini_clouds: self.has_year_two() & self.can_spend_money(1200), - FestivalCheck.lupini_1000_years: self.has_year_two() & self.can_spend_money(1200), - FestivalCheck.lupini_three_trees: self.has_year_two() & self.can_spend_money(1200), - FestivalCheck.lupini_the_serpent: self.has_year_three() & self.can_spend_money(1200), - FestivalCheck.lupini_tropical_fish: self.has_year_three() & self.can_spend_money(1200), - FestivalCheck.lupini_land_of_clay: self.has_year_three() & self.can_spend_money(1200), - FestivalCheck.secret_santa: self.has_any_universal_love(), - FestivalCheck.legend_of_the_winter_star: True_(), - FestivalCheck.all_rarecrows: self.can_reach_region(Region.farm) & self.has_all_rarecrows(), - }) - - self.special_order_rules.update({ - SpecialOrder.island_ingredients: self.can_meet(NPC.caroline) & self.has_island_transport() & self.can_farm_perfectly() & - self.can_ship(Vegetable.taro_root) & self.can_ship(Fruit.pineapple) & self.can_ship(Forageable.ginger), - SpecialOrder.cave_patrol: self.can_meet(NPC.clint), - SpecialOrder.aquatic_overpopulation: self.can_meet(NPC.demetrius) & self.can_fish_perfectly(), - SpecialOrder.biome_balance: self.can_meet(NPC.demetrius) & self.can_fish_perfectly(), - SpecialOrder.rock_rejuivenation: self.has_relationship(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & - self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & - self.has(ArtisanGood.cloth), - SpecialOrder.gifts_for_george: self.has_season(Season.spring) & self.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.can_reach_region(Region.dig_site) & self.has_tool(Tool.pickaxe), - SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), - SpecialOrder.crop_order: self.can_farm_perfectly() & self.can_ship(), - SpecialOrder.community_cleanup: self.can_crab_pot(), - SpecialOrder.the_strong_stuff: self.can_keg(Vegetable.potato), - SpecialOrder.pierres_prime_produce: self.can_farm_perfectly(), - SpecialOrder.robins_project: self.can_meet(NPC.robin) & self.can_chop_perfectly() & - self.has(Material.hardwood), - SpecialOrder.robins_resource_rush: self.can_meet(NPC.robin) & self.can_chop_perfectly() & - self.has(Fertilizer.tree) & self.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted_yum: self.has(Loot.bug_meat), - SpecialOrder.tropical_fish: self.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & - self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), - SpecialOrder.a_curious_substance: self.can_reach_region(Region.wizard_tower), - SpecialOrder.prismatic_jelly: self.can_reach_region(Region.wizard_tower), - SpecialOrder.qis_crop: self.can_farm_perfectly() & self.can_reach_region(Region.greenhouse) & - self.can_reach_region(Region.island_west) & self.has_total_skill_level(50) & - self.has(Machine.seed_maker) & self.has_building(Building.shipping_bin), - SpecialOrder.lets_play_a_game: self.has_junimo_kart_max_level(), - SpecialOrder.four_precious_stones: self.has_lived_months(MAX_MONTHS) & self.has("Prismatic Shard") & - self.can_mine_perfectly_in_the_skull_cavern(), - SpecialOrder.qis_hungry_challenge: self.can_mine_perfectly_in_the_skull_cavern() & self.has_max_buffs(), - SpecialOrder.qis_cuisine: self.can_cook() & (self.can_spend_money_at(Region.saloon, 205000) | self.can_spend_money_at(Region.pierre_store, 170000)) & - self.can_ship(), - SpecialOrder.qis_kindness: self.can_give_loved_gifts_to_everyone(), - SpecialOrder.extended_family: self.can_fish_perfectly() & self.has(Fish.angler) & self.has(Fish.glacierfish) & - self.has(Fish.crimsonfish) & self.has(Fish.mutant_carp) & self.has(Fish.legend), - SpecialOrder.danger_in_the_deep: self.can_mine_perfectly() & self.has_mine_elevator_to_floor(120), - SpecialOrder.skull_cavern_invasion: self.can_mine_perfectly_in_the_skull_cavern() & self.has_max_buffs(), - SpecialOrder.qis_prismatic_grange: self.has(Loot.bug_meat) & # 100 Bug Meat - self.can_spend_money_at(Region.saloon, 24000) & # 100 Spaghetti - self.can_spend_money_at(Region.blacksmith, 15000) & # 100 Copper Ore - self.can_spend_money_at(Region.ranch, 5000) & # 100 Hay - self.can_spend_money_at(Region.saloon, 22000) & # 100 Salads - self.can_spend_money_at(Region.saloon, 7500) & # 100 Joja Cola - self.can_spend_money(80000), # I need this extra rule because money rules aren't additive... - }) - - self.special_order_rules.update(get_modded_special_orders_rules(self, self.options.mods)) - - def has(self, items: Union[str, (Iterable[str], Sized)], count: Optional[int] = None) -> StardewRule: - if not isinstance(items, str): - items = list(items) - key = f"has {items} {count}" - if key not in self.cached_rules: - self.cached_rules[key] = self._has(items, count) - return self.cached_rules[key] - - def _has(self, items: Union[str, (Iterable[str], Sized)], count: Optional[int] = None) -> StardewRule: - if isinstance(items, str): - return Has(items, self.item_rules) - - if len(items) == 0: - return True_() - - if count is None or count == len(items): - return And(self.has(item) for item in items) - - if count == 1: - return Or(self.has(item) for item in items) - - return Count(count, (self.has(item) for item in items)) - - def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: - if not isinstance(items, str): - items = list(items) - key = f"received {items} {count}" - if key not in self.cached_rules: - self.cached_rules[key] = self._received(items, count) - return self.cached_rules[key] - - def _received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: - if count <= 0 or not items: - return True_() - - if isinstance(items, str): - return Received(items, self.player, count) - - if count is None: - return And(self.received(item) for item in items) - - if count == 1: - return Or(self.received(item) for item in items) - - return TotalReceived(count, items, self.player) - - def can_reach_region(self, spot: str) -> StardewRule: - key = f"can_reach_region {spot}" - if key not in self.cached_rules: - self.cached_rules[key] = Reach(spot, "Region", self.player) - return self.cached_rules[key] - - def can_reach_any_region(self, spots: Iterable[str]) -> StardewRule: - spots = list(spots) - key = f"can_reach_any_region {spots}" - if key not in self.cached_rules: - self.cached_rules[key] = Or(self.can_reach_region(spot) for spot in spots) - return self.cached_rules[key] - - def can_reach_all_regions(self, spots: List[str]) -> StardewRule: - key = f"can_reach_all_regions {spots}" - if key not in self.cached_rules: - self.cached_rules[key] = And(self.can_reach_region(spot) for spot in spots) - return self.cached_rules[key] - - def can_reach_location(self, spot: str) -> StardewRule: - key = f"can_reach_location {spot}" - if key not in self.cached_rules: - self.cached_rules[key] = Reach(spot, "Location", self.player) - return self.cached_rules[key] - - def can_reach_entrance(self, spot: str) -> StardewRule: - key = f"can_reach_entrance {spot}" - if key not in self.cached_rules: - self.cached_rules[key] = Reach(spot, "Entrance", self.player) - return self.cached_rules[key] - - def can_have_earned_total_money(self, amount: int) -> StardewRule: - key = f"can_have_earned_total_money {amount}" - if key not in self.cached_rules: - self.cached_rules[key] = self.has_lived_months(min(8, amount // MONEY_PER_MONTH)) - return self.cached_rules[key] - - def can_spend_money(self, amount: int) -> StardewRule: - key = f"can_spend_money {amount}" - if key not in self.cached_rules: - if self.options.starting_money == -1: - self.cached_rules[key] = True_() - else: - self.cached_rules[key] = self.has_lived_months(min(8, amount // (MONEY_PER_MONTH // 5))) - return self.cached_rules[key] - - def can_spend_money_at(self, region: str, amount: int) -> StardewRule: - key = f"can_spend_money_at {region} {amount}" - if key not in self.cached_rules: - self.cached_rules[key] = self.can_reach_region(region) & self.can_spend_money(amount) - return self.cached_rules[key] - - def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: - key = f"has_tool {tool} {material}" - if key not in self.cached_rules: - self.cached_rules[key] = self._has_tool(tool, material) - return self.cached_rules[key] - - def _has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: - if material == ToolMaterial.basic or tool == Tool.scythe: - return True_() - - if self.options.tool_progression == ToolProgression.option_progressive: - return self.received(f"Progressive {tool}", count=tool_materials[material]) - - return self.has(f"{material} Bar") & self.can_spend_money(tool_upgrade_prices[material]) - - def can_earn_skill_level(self, skill: str, level: int) -> StardewRule: - key = f"can_earn_skill_level {skill} {level}" - if key not in self.cached_rules: - self.cached_rules[key] = self._can_earn_skill_level(skill, level) - return self.cached_rules[key] - - def _can_earn_skill_level(self, skill: str, level: int) -> StardewRule: - if level <= 0: - return True_() - - tool_level = (level - 1) // 2 - tool_material = ToolMaterial.tiers[tool_level] - months = max(1, level - 1) - months_rule = self.has_lived_months(months) - previous_level_rule = self.has_skill_level(skill, level - 1) - - if skill == Skill.fishing: - xp_rule = self.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) - elif skill == Skill.farming: - xp_rule = self.has_tool(Tool.hoe, tool_material) & self.can_water(tool_level) - elif skill == Skill.foraging: - xp_rule = self.has_tool(Tool.axe, tool_material) | magic.can_use_clear_debris_instead_of_tool_level(self, tool_level) - elif skill == Skill.mining: - xp_rule = self.has_tool(Tool.pickaxe, tool_material) | magic.can_use_clear_debris_instead_of_tool_level(self, tool_level) - elif skill == Skill.combat: - combat_tier = Performance.tiers[tool_level] - xp_rule = self.can_do_combat_at_level(combat_tier) - else: - xp_rule = skills.can_earn_mod_skill_level(self, skill, level) - - return previous_level_rule & months_rule & xp_rule - - def has_skill_level(self, skill: str, level: int) -> StardewRule: - key = f"has_skill_level {skill} {level}" - if key not in self.cached_rules: - self.cached_rules[key] = self._has_skill_level(skill, level) - return self.cached_rules[key] - - def _has_skill_level(self, skill: str, level: int) -> StardewRule: - if level <= 0: - return True_() - - if self.options.skill_progression == SkillProgression.option_progressive: - return self.received(f"{skill} Level", count=level) - - return self.can_earn_skill_level(skill, level) - - def has_farming_level(self, level: int) -> StardewRule: - return self.has_skill_level(Skill.farming, level) - - def has_total_skill_level(self, level: int, allow_modded_skills: bool = False) -> StardewRule: - if level <= 0: - return True_() - - if self.options.skill_progression == SkillProgression.option_progressive: - skills_items = ["Farming Level", "Mining Level", "Foraging Level", - "Fishing Level", "Combat Level"] - if allow_modded_skills: - skills.append_mod_skill_level(skills_items, self.options) - return self.received(skills_items, count=level) - - months_with_4_skills = max(1, (level // 4) - 1) - months_with_5_skills = max(1, (level // 5) - 1) - rule_with_fishing = self.has_lived_months(months_with_5_skills) & self.can_get_fishing_xp() - if level > 40: - return rule_with_fishing - return self.has_lived_months(months_with_4_skills) | rule_with_fishing - - def has_building(self, building: str) -> StardewRule: - carpenter_rule = self.can_reach_region(Region.carpenter) - if not self.options.building_progression == BuildingProgression.option_vanilla: - count = 1 - if building in [Building.coop, Building.barn, Building.shed]: - building = f"Progressive {building}" - elif building.startswith("Big"): - count = 2 - building = " ".join(["Progressive", *building.split(" ")[1:]]) - elif building.startswith("Deluxe"): - count = 3 - building = " ".join(["Progressive", *building.split(" ")[1:]]) - return self.received(f"{building}", count) & carpenter_rule - - return Has(building, self.building_rules) & carpenter_rule - - def has_house(self, upgrade_level: int) -> StardewRule: - key = f"has_house {upgrade_level}" - if key not in self.cached_rules: - self.cached_rules[key] = self._has_house(upgrade_level) - return self.cached_rules[key] - - def _has_house(self, upgrade_level: int) -> StardewRule: - if upgrade_level < 1: - return True_() - - if upgrade_level > 3: - return False_() - - if not self.options.building_progression == BuildingProgression.option_vanilla: - return self.received(f"Progressive House", upgrade_level) & self.can_reach_region(Region.carpenter) - - if upgrade_level == 1: - return Has(Building.kitchen, self.building_rules) - - if upgrade_level == 2: - return Has(Building.kids_room, self.building_rules) - - # if upgrade_level == 3: - return Has(Building.cellar, self.building_rules) - - def can_complete_quest(self, quest: str) -> StardewRule: - return Has(quest, self.quest_rules) - - def can_complete_special_order(self, specialorder: str) -> StardewRule: - return Has(specialorder, self.special_order_rules) - - def can_get_farming_xp(self) -> StardewRule: - key = f"can_get_farming_xp" - if key not in self.cached_rules: - crop_rules = [] - for crop in all_crops: - crop_rules.append(self.can_grow_crop(crop)) - self.cached_rules[key] = Or(crop_rules) - return self.cached_rules[key] - - def can_get_fishing_xp(self) -> StardewRule: - key = f"can_get_fishing_xp" - if key not in self.cached_rules: - if self.options.skill_progression == SkillProgression.option_progressive: - self.cached_rules[key] = self.can_fish() | self.can_crab_pot() - else: - self.cached_rules[key] = self.can_fish() - return self.cached_rules[key] - - def can_fish(self, difficulty: int = 0) -> StardewRule: - key = f"can_fish {difficulty}" - if key not in self.cached_rules: - skill_required = max(0, int((difficulty / 10) - 1)) - if difficulty <= 40: - skill_required = 0 - skill_rule = self.has_skill_level(Skill.fishing, skill_required) - region_rule = self.can_reach_any_region(fishing_regions) - tool_rule = True_() - if self.options.tool_progression == ToolProgression.option_progressive: - number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) - tool_rule = self.received("Progressive Fishing Rod", number_fishing_rod_required) - self.cached_rules[key] = skill_rule & region_rule & tool_rule - return self.cached_rules[key] - - def can_fish_in_freshwater(self) -> StardewRule: - return self.can_fish() & self.can_reach_any_region([Region.forest, Region.town, Region.mountain]) - - def has_max_fishing(self) -> StardewRule: - skill_rule = self.has_skill_level(Skill.fishing, 10) - return self.has_max_fishing_rod() & skill_rule - - def can_fish_chests(self) -> StardewRule: - skill_rule = self.has_skill_level(Skill.fishing, 6) - return self.has_max_fishing_rod() & skill_rule - - def can_buy_seed(self, seed: SeedItem) -> StardewRule: - key = f"can_buy_seed {seed.name}" - if key not in self.cached_rules: - if self.options.cropsanity == Cropsanity.option_disabled: - item_rule = True_() - else: - item_rule = self.received(seed.name) - season_rule = self.has_any_season(seed.seasons) - region_rule = self.can_reach_all_regions(seed.regions) - currency_rule = self.can_spend_money(1000) - if seed.name == Seed.pineapple: - currency_rule = self.has(Forageable.magma_cap) - if seed.name == Seed.taro: - currency_rule = self.has(Fossil.bone_fragment) - self.cached_rules[key] = season_rule & region_rule & item_rule & currency_rule - return self.cached_rules[key] - - def can_buy_sapling(self, fruit: str) -> StardewRule: - sapling_prices = {Fruit.apple: 4000, Fruit.apricot: 2000, Fruit.cherry: 3400, Fruit.orange: 4000, - Fruit.peach: 6000, - Fruit.pomegranate: 6000, Fruit.banana: 0, Fruit.mango: 0} - received_sapling = self.received(f"{fruit} Sapling") - if self.options.cropsanity == Cropsanity.option_disabled: - allowed_buy_sapling = True_() - else: - allowed_buy_sapling = received_sapling - can_buy_sapling = self.can_spend_money_at(Region.pierre_store, sapling_prices[fruit]) - if fruit == Fruit.banana: - can_buy_sapling = self.has_island_trader() & self.has(Forageable.dragon_tooth) - elif fruit == Fruit.mango: - can_buy_sapling = self.has_island_trader() & self.has(Fish.mussel_node) - - return allowed_buy_sapling & can_buy_sapling - - def can_grow_crop(self, crop: CropItem) -> StardewRule: - key = f"can_grow_crop {crop.name}" - if key not in self.cached_rules: - season_rule = self.has_any_season(crop.farm_growth_seasons) - seed_rule = self.has(crop.seed.name) - farm_rule = self.can_reach_region(Region.farm) & season_rule - tool_rule = self.has_tool(Tool.hoe) & self.has_tool(Tool.watering_can) - region_rule = farm_rule | self.can_reach_region(Region.greenhouse) | self.can_reach_region(Region.island_west) - self.cached_rules[key] = seed_rule & region_rule & tool_rule - return self.cached_rules[key] - - def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> StardewRule: - if isinstance(seasons, str): - seasons = [seasons] - season_rule = self.has_any_season(seasons) | self.can_reach_region(Region.greenhouse) | self.has_island_farm() - farm_rule = self.can_reach_region(Region.farm) | self.can_reach_region( - Region.greenhouse) | self.has_island_farm() - return season_rule & farm_rule - - def has_island_farm(self) -> StardewRule: - return self.can_reach_region(Region.island_south) - - def can_catch_fish(self, fish: FishItem) -> StardewRule: - key = f"can_catch_fish {fish.name}" - if key not in self.cached_rules: - region_rule = self.can_reach_any_region(fish.locations) - season_rule = self.has_any_season(fish.seasons) - if fish.difficulty == -1: - difficulty_rule = self.can_crab_pot() - else: - difficulty_rule = self.can_fish(fish.difficulty) - self.cached_rules[key] = region_rule & season_rule & difficulty_rule - return self.cached_rules[key] - - def can_catch_every_fish(self) -> StardewRule: - rules = [self.has_skill_level(Skill.fishing, 10), self.has_max_fishing_rod()] - for fish in all_fish: - if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true and \ - fish in island_fish: - continue - rules.append(self.can_catch_fish(fish)) - return And(rules) - - def has_max_fishing_rod(self) -> StardewRule: - if self.options.tool_progression == ToolProgression.option_progressive: - return self.received(APTool.fishing_rod, 4) - return self.can_get_fishing_xp() - - def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: - if recipe is None: - key = f"can_cook" - else: - key = f"can_cook {recipe.meal} {type(recipe.source)}" - if key not in self.cached_rules: - cook_rule = self.has_house(1) | self.has_skill_level(Skill.foraging, 9) - if recipe is None: - self.cached_rules[key] = cook_rule - return self.cached_rules[key] - - learn_rule = self.can_learn_recipe(recipe.source) - ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) - number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) - time_rule = self.has_lived_months(number_ingredients) - self.cached_rules[key] = cook_rule & learn_rule & ingredients_rule & time_rule - return self.cached_rules[key] - - def can_learn_recipe(self, source: RecipeSource) -> StardewRule: - key = f"can_learn_recipe {source}" - if key not in self.cached_rules: - self.cached_rules[key] = self._can_learn_recipe(source) - return self.cached_rules[key] - - def _can_learn_recipe(self, source: RecipeSource) -> StardewRule: - if isinstance(source, StarterSource): - return True_() - if isinstance(source, ShopSource): - return self.can_spend_money_at(source.region, source.price) - if isinstance(source, SkillSource): - return self.has_skill_level(source.skill, source.level) - if isinstance(source, FriendshipSource): - return self.has_relationship(source.friend, source.hearts) - if isinstance(source, QueenOfSauceSource): - year_rule = self.has_year_two() if source.year == 2 else self.has_year_three() - return self.can_watch(Channel.queen_of_sauce) & self.has_season(source.season) & year_rule - - return False_() - - def can_watch(self, channel: str = None): - tv_rule = True_() - if channel is None: - return tv_rule - return self.received(channel) & tv_rule - - def can_smelt(self, item: str) -> StardewRule: - return self.has(Machine.furnace) & self.has(item) - - def can_do_panning(self, item: str = Generic.any) -> StardewRule: - return self.received("Glittering Boulder Removed") - - def can_crab_pot(self, region: str = Generic.any) -> StardewRule: - key = f"can_crab_pot {region}" - if key not in self.cached_rules: - crab_pot_rule = self.has(Craftable.bait) - if self.options.skill_progression == SkillProgression.option_progressive: - crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) - else: - crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp() - - if region != Generic.any: - self.cached_rules[key] = crab_pot_rule & self.can_reach_region(region) - else: - water_region_rules = self.can_reach_any_region(fishing_regions) - self.cached_rules[key] = crab_pot_rule & water_region_rules - return self.cached_rules[key] - - # Regions - def can_mine_in_the_mines_floor_1_40(self) -> StardewRule: - return self.can_reach_region(Region.mines_floor_5) - - def can_mine_in_the_mines_floor_41_80(self) -> StardewRule: - return self.can_reach_region(Region.mines_floor_45) - - def can_mine_in_the_mines_floor_81_120(self) -> StardewRule: - return self.can_reach_region(Region.mines_floor_85) - - def can_mine_in_the_skull_cavern(self) -> StardewRule: - return (self.can_progress_in_the_mines_from_floor(120) & - self.can_reach_region(Region.skull_cavern)) - - def can_mine_perfectly(self) -> StardewRule: - return self.can_progress_in_the_mines_from_floor(160) - - def can_mine_perfectly_in_the_skull_cavern(self) -> StardewRule: - return (self.can_mine_perfectly() & - self.can_reach_region(Region.skull_cavern)) - - def can_farm_perfectly(self) -> StardewRule: - tool_rule = self.has_tool(Tool.hoe, ToolMaterial.iridium) & self.can_water(4) - return tool_rule & self.has_farming_level(10) - - def can_fish_perfectly(self) -> StardewRule: - skill_rule = self.has_skill_level(Skill.fishing, 10) - return skill_rule & self.has_max_fishing_rod() - - def can_chop_trees(self) -> StardewRule: - return self.has_tool(Tool.axe) & self.can_reach_region(Region.forest) - - def can_chop_perfectly(self) -> StardewRule: - magic_rule = (magic.can_use_clear_debris_instead_of_tool_level(self, 3)) & self.has_skill_level(ModSkill.magic, 10) - tool_rule = self.has_tool(Tool.axe, ToolMaterial.iridium) - foraging_rule = self.has_skill_level(Skill.foraging, 10) - region_rule = self.can_reach_region(Region.forest) - return region_rule & ((tool_rule & foraging_rule) | magic_rule) - - def has_max_buffs(self) -> StardewRule: - return self.received(Buff.movement, self.options.movement_buff_number.value) & self.received(Buff.luck, self.options.luck_buff_number.value) - - def get_weapon_rule_for_floor_tier(self, tier: int): - if tier >= 4: - return self.can_do_combat_at_level(Performance.galaxy) - if tier >= 3: - return self.can_do_combat_at_level(Performance.great) - if tier >= 2: - return self.can_do_combat_at_level(Performance.good) - if tier >= 1: - return self.can_do_combat_at_level(Performance.decent) - return self.can_do_combat_at_level(Performance.basic) - - def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: - key = f"can_progress_in_the_mines_from_floor {floor}" - if key not in self.cached_rules: - tier = floor // 40 - rules = [] - weapon_rule = self.get_weapon_rule_for_floor_tier(tier) - rules.append(weapon_rule) - if self.options.tool_progression == ToolProgression.option_progressive: - rules.append(self.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) - if self.options.skill_progression == SkillProgression.option_progressive: - combat_tier = min(10, max(0, tier * 2)) - rules.append(self.has_skill_level(Skill.combat, combat_tier)) - self.cached_rules[key] = And(rules) - return self.cached_rules[key] - - def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: - key = f"has_mine_elevator_to_floor {floor}" - if key not in self.cached_rules: - if floor <= 0: - floor = 0 - if self.options.elevator_progression != ElevatorProgression.option_vanilla: - self.cached_rules[key] = self.received("Progressive Mine Elevator", count=int(floor / 5)) - else: - self.cached_rules[key] = True_() - return self.cached_rules[key] - - def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: - tier = floor // 50 - rules = [] - weapon_rule = self.has_great_weapon() - rules.append(weapon_rule) - rules.append(self.can_cook()) - if self.options.tool_progression == ToolProgression.option_progressive: - rules.append(self.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) - if self.options.skill_progression == SkillProgression.option_progressive: - skill_tier = min(10, max(0, tier * 2 + 6)) - rules.extend({self.has_skill_level(Skill.combat, skill_tier), - self.has_skill_level(Skill.mining, skill_tier)}) - return And(rules) - - def has_jotpk_power_level(self, power_level: int) -> StardewRule: - if self.options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: - return True_() - jotpk_buffs = ["JotPK: Progressive Boots", "JotPK: Progressive Gun", - "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate"] - return self.received(jotpk_buffs, power_level) - - def has_junimo_kart_power_level(self, power_level: int) -> StardewRule: - if self.options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: - return True_() - return self.received("Junimo Kart: Extra Life", power_level) - - def has_junimo_kart_max_level(self) -> StardewRule: - play_rule = self.can_reach_region(Region.junimo_kart_3) - if self.options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: - return play_rule - return self.has_junimo_kart_power_level(8) - - def has_traveling_merchant(self, tier: int = 1): - traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] - return self.received(traveling_merchant_days, tier) - - def can_get_married(self) -> StardewRule: - return self.has_relationship(Generic.bachelor, 10) & self.has(Gift.mermaid_pendant) - - def has_children(self, number_children: int) -> StardewRule: - if number_children <= 0: - return True_() - possible_kids = ["Cute Baby", "Ugly Baby"] - return self.received(possible_kids, number_children) & self.has_house(2) - - def can_reproduce(self, number_children: int = 1) -> StardewRule: - if number_children <= 0: - return True_() - return self.can_get_married() & self.has_house(2) & self.has_relationship(Generic.bachelor, 12) & self.has_children(number_children - 1) - - def has_relationship(self, npc: str, hearts: int = 1) -> StardewRule: - key = f"has_relationship {npc} {hearts}" - if key not in self.cached_rules: - self.cached_rules[key] = self._has_relationship(npc, hearts) - return self.cached_rules[key] - - def _has_relationship(self, npc: str, hearts: int = 1) -> StardewRule: - if hearts <= 0: - return True_() - friendsanity = self.options.friendsanity - if friendsanity == Friendsanity.option_none: - return self.can_earn_relationship(npc, hearts) - if npc not in all_villagers_by_name: - if npc == NPC.pet: - if friendsanity == Friendsanity.option_bachelors: - return self.can_befriend_pet(hearts) - return self.received_hearts(NPC.pet, hearts) - if npc == Generic.any or npc == Generic.bachelor: - possible_friends = [] - for name in all_villagers_by_name: - if not self.npc_is_in_current_slot(name): - continue - if npc == Generic.any or all_villagers_by_name[name].bachelor: - possible_friends.append(self.has_relationship(name, hearts)) - return Or(possible_friends) - if npc == Generic.all: - mandatory_friends = [] - for name in all_villagers_by_name: - if not self.npc_is_in_current_slot(name): - continue - mandatory_friends.append(self.has_relationship(name, hearts)) - return And(mandatory_friends) - if npc.isnumeric(): - possible_friends = [] - for name in all_villagers_by_name: - if not self.npc_is_in_current_slot(name): - continue - possible_friends.append(self.has_relationship(name, hearts)) - return Count(int(npc), possible_friends) - return self.can_earn_relationship(npc, hearts) - - if not self.npc_is_in_current_slot(npc): - return True_() - villager = all_villagers_by_name[npc] - if friendsanity == Friendsanity.option_bachelors and not villager.bachelor: - return self.can_earn_relationship(npc, hearts) - if friendsanity == Friendsanity.option_starting_npcs and not villager.available: - return self.can_earn_relationship(npc, hearts) - is_capped_at_8 = villager.bachelor and friendsanity != Friendsanity.option_all_with_marriage - if is_capped_at_8 and hearts > 8: - return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) - return self.received_hearts(villager.name, hearts) - - def received_hearts(self, npc: str, hearts: int) -> StardewRule: - key = f"received_hearts {npc}, {hearts}" - if key not in self.cached_rules: - heart_size = self.options.friendsanity_heart_size.value - self.cached_rules[key] = self.received(self.heart(npc), math.ceil(hearts / heart_size)) - return self.cached_rules[key] - - def can_meet(self, npc: str) -> StardewRule: - key = f"can_meet {npc}" - if key not in self.cached_rules: - if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): - self.cached_rules[key] = True_() - return self.cached_rules[key] - villager = all_villagers_by_name[npc] - rules = [self.can_reach_any_region(villager.locations)] - if npc == NPC.kent: - rules.append(self.has_year_two()) - elif npc == NPC.leo: - rules.append(self.received("Island West Turtle")) - - self.cached_rules[key] = And(rules) - return self.cached_rules[key] - - def can_give_loved_gifts_to_everyone(self) -> StardewRule: - rules = [] - for npc in all_villagers_by_name: - if not self.npc_is_in_current_slot(npc): - continue - meet_rule = self.can_meet(npc) - rules.append(meet_rule) - loved_gifts_rules = And(rules) & self.has_any_universal_love() - return loved_gifts_rules - - def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: - key = f"can_meet {npc} {hearts}" - if key not in self.cached_rules: - self.cached_rules[key] = self._can_earn_relationship(npc, hearts) - return self.cached_rules[key] - - def _can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: - if hearts <= 0: - return True_() - - heart_size = self.options.friendsanity_heart_size.value - previous_heart = hearts - heart_size - previous_heart_rule = self.has_relationship(npc, previous_heart) - - if npc == NPC.pet: - earn_rule = self.can_befriend_pet(hearts) - elif npc == NPC.wizard and ModNames.magic in self.options.mods: - earn_rule = self.can_meet(npc) & self.has_lived_months(hearts) - elif npc in all_villagers_by_name: - if not self.npc_is_in_current_slot(npc): - return previous_heart_rule - villager = all_villagers_by_name[npc] - rule_if_birthday = self.has_season(villager.birthday) & self.has_any_universal_love() & self.has_lived_months(hearts // 2) - rule_if_not_birthday = self.has_lived_months(hearts) - earn_rule = self.can_meet(npc) & (rule_if_birthday | rule_if_not_birthday) - if villager.bachelor: - if hearts > 8: - earn_rule = earn_rule & self.can_date(npc) - if hearts > 10: - earn_rule = earn_rule & self.can_marry(npc) - else: - earn_rule = self.has_lived_months(min(hearts // 2, 8)) - - return previous_heart_rule & earn_rule - - def can_date(self, npc: str) -> StardewRule: - return self.has_relationship(npc, 8) & self.has(Gift.bouquet) - - def can_marry(self, npc: str) -> StardewRule: - return self.has_relationship(npc, 10) & self.has(Gift.mermaid_pendant) - - def can_befriend_pet(self, hearts: int): - if hearts <= 0: - return True_() - points = hearts * 200 - points_per_month = 12 * 14 - points_per_water_month = 18 * 14 - return self.can_reach_region(Region.farm) & \ - ((self.can_water(0) & self.has_lived_months(points // points_per_water_month)) | - self.has_lived_months(points // points_per_month)) - - def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: - item_rules = [] - highest_quality_yet = 0 - can_speak_junimo = self.can_reach_region(Region.wizard_tower) - for bundle_item in bundle_requirements: - if bundle_item.item.item_id == -1: - return can_speak_junimo & self.can_spend_money(bundle_item.amount) - else: - item_rules.append(bundle_item.item.name) - if bundle_item.quality > highest_quality_yet: - highest_quality_yet = bundle_item.quality - return can_speak_junimo & self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) - - def can_grow_gold_quality(self, quality: int) -> StardewRule: - if quality <= 0: - return True_() - if quality == 1: - return self.has_farming_level(5) | (self.has_fertilizer(1) & self.has_farming_level(2)) | ( - self.has_fertilizer(2) & self.has_farming_level(1)) | self.has_fertilizer(3) - if quality == 2: - return self.has_farming_level(10) | (self.has_fertilizer(1) & self.has_farming_level(5)) | ( - self.has_fertilizer(2) & self.has_farming_level(3)) | ( - self.has_fertilizer(3) & self.has_farming_level(2)) - if quality >= 3: - return self.has_fertilizer(3) & self.has_farming_level(4) - - def has_fertilizer(self, tier: int) -> StardewRule: - if tier <= 0: - return True_() - if tier == 1: - return self.has(Fertilizer.basic) - if tier == 2: - return self.has(Fertilizer.quality) - if tier >= 3: - return self.has(Fertilizer.deluxe) - - def can_complete_field_office(self) -> StardewRule: - field_office = self.can_reach_region(Region.field_office) - professor_snail = self.received("Open Professor Snail Cave") - dig_site = self.can_reach_region(Region.dig_site) - tools = self.has_tool(Tool.pickaxe) & self.has_tool(Tool.hoe) & self.has_tool(Tool.scythe) - leg_and_snake_skull = dig_site - ribs_and_spine = self.can_reach_region(Region.island_south) - skull = self.can_open_geode(Geode.golden_coconut) - tail = self.can_do_panning() & dig_site - frog = self.can_reach_region(Region.island_east) - bat = self.can_reach_region(Region.volcano_floor_5) - snake_vertebrae = self.can_reach_region(Region.island_west) - return field_office & professor_snail & tools & leg_and_snake_skull & ribs_and_spine & skull & tail & frog & bat & snake_vertebrae - - def can_complete_community_center(self) -> StardewRule: - return (self.can_reach_location("Complete Crafts Room") & - self.can_reach_location("Complete Pantry") & - self.can_reach_location("Complete Fish Tank") & - self.can_reach_location("Complete Bulletin Board") & - self.can_reach_location("Complete Vault") & - self.can_reach_location("Complete Boiler Room")) - - def can_finish_grandpa_evaluation(self) -> StardewRule: - # https://stardewvalleywiki.com/Grandpa - rules_worth_a_point = [self.can_have_earned_total_money(50000), # 50 000g - self.can_have_earned_total_money(100000), # 100 000g - self.can_have_earned_total_money(200000), # 200 000g - self.can_have_earned_total_money(300000), # 300 000g - self.can_have_earned_total_money(500000), # 500 000g - self.can_have_earned_total_money(1000000), # 1 000 000g first point - self.can_have_earned_total_money(1000000), # 1 000 000g second point - self.has_total_skill_level(30), # Total Skills: 30 - self.has_total_skill_level(50), # Total Skills: 50 - self.can_complete_museum(), # Completing the museum for a point - # Catching every fish not expected - # Shipping every item not expected - self.can_get_married() & self.has_house(2), - self.has_relationship("5", 8), # 5 Friends - self.has_relationship("10", 8), # 10 friends - self.has_relationship(NPC.pet, 5), # Max Pet - self.can_complete_community_center(), # Community Center Completion - self.can_complete_community_center(), # CC Ceremony first point - self.can_complete_community_center(), # CC Ceremony second point - self.received(Wallet.skull_key), # Skull Key obtained - self.has_rusty_key(), # Rusty key obtained - ] - return Count(12, rules_worth_a_point) - - def has_island_transport(self) -> StardewRule: - return self.received(Transportation.island_obelisk) | self.received(Transportation.boat_repair) - - def has_any_weapon(self) -> StardewRule: - key = "has_any_weapon" - if key not in self.cached_rules: - self.cached_rules[key] = self.has_decent_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups) - return self.cached_rules[key] - - def has_decent_weapon(self) -> StardewRule: - key = "has_decent_weapon" - if key not in self.cached_rules: - self.cached_rules[key] = self.has_good_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) - return self.cached_rules[key] - - def has_good_weapon(self) -> StardewRule: - key = "has_good_weapon" - if key not in self.cached_rules: - self.cached_rules[key] = self.has_great_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) - return self.cached_rules[key] - - def has_great_weapon(self) -> StardewRule: - key = "has_great_weapon" - if key not in self.cached_rules: - self.cached_rules[key] = self.has_galaxy_weapon() | self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) - return self.cached_rules[key] - - def has_galaxy_weapon(self) -> StardewRule: - key = "has_galaxy_weapon" - if key not in self.cached_rules: - self.cached_rules[key] = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) - return self.cached_rules[key] - - def has_year_two(self) -> StardewRule: - return self.has_lived_months(4) - - def has_year_three(self) -> StardewRule: - return self.has_lived_months(8) - - def can_speak_dwarf(self) -> StardewRule: - return self.received("Dwarvish Translation Guide") - - def can_find_museum_item(self, item: MuseumItem) -> StardewRule: - key = f"can_find_museum_item {item.name}" - if key not in self.cached_rules: - region_rule = self.can_reach_any_region(item.locations) - geodes_rule = And([self.can_open_geode(geode) for geode in item.geodes]) - # monster_rule = self.can_farm_monster(item.monsters) - # extra_rule = True_() - pan_rule = False_() - if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": - pan_rule = self.can_do_panning() - self.cached_rules[key] = pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule - return self.cached_rules[key] - - def can_donate_museum_artifacts(self, number: int) -> StardewRule: - return self.can_reach_region(Region.museum) & self.can_find_museum_artifacts(number) - - def can_find_museum_artifacts(self, number: int) -> StardewRule: - rules = [] - for artifact in all_museum_artifacts: - rules.append(self.can_find_museum_item(artifact)) - - return Count(number, rules) - - def can_find_museum_minerals(self, number: int) -> StardewRule: - rules = [] - for mineral in all_museum_minerals: - rules.append(self.can_find_museum_item(mineral)) - - return Count(number, rules) - - def can_donate_museum_items(self, number: int) -> StardewRule: - return self.can_reach_region(Region.museum) & self.can_find_museum_items(number) - - def can_find_museum_items(self, number: int) -> StardewRule: - rules = [] - for donation in all_museum_items: - rules.append(self.can_find_museum_item(donation)) - - return Count(number, rules) - - def can_complete_museum(self) -> StardewRule: - rules = [self.can_reach_region(Region.museum), self.can_mine_perfectly()] - - if self.options.museumsanity != Museumsanity.option_none: - rules.append(self.received("Traveling Merchant Metal Detector", 4)) - - for donation in all_museum_items: - rules.append(self.can_find_museum_item(donation)) - return And(rules) - - def has_season(self, season: str) -> StardewRule: - key = f"has_season {season}" - if key not in self.cached_rules: - self.cached_rules[key] = self._has_season(season) - return self.cached_rules[key] - - def _has_season(self, season: str) -> StardewRule: - if season == Generic.any: - return True_() - seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] - if self.options.season_randomization == SeasonRandomization.option_progressive: - return self.received(Season.progressive, seasons_order.index(season)) - if self.options.season_randomization == SeasonRandomization.option_disabled: - if season == Season.spring: - return True_() - return self.has_lived_months(1) - return self.received(season) - - def has_any_season(self, seasons: Iterable[str]): - if not seasons: - return True_() - return Or([self.has_season(season) for season in seasons]) - - def has_any_season_not_winter(self): - return self.has_any_season([Season.spring, Season.summer, Season.fall]) - - def has_all_seasons(self, seasons: Iterable[str]): - if not seasons: - return True_() - return And([self.has_season(season) for season in seasons]) - - def has_lived_months(self, number: int) -> StardewRule: - key = f"has_lived_months {number}" - if key not in self.cached_rules: - number = max(0, min(number, MAX_MONTHS)) - self.cached_rules[key] = self.received("Month End", number) - return self.cached_rules[key] - - def has_rusty_key(self) -> StardewRule: - return self.received(Wallet.rusty_key) - - def can_win_egg_hunt(self) -> StardewRule: - number_of_movement_buffs = self.options.movement_buff_number.value - if self.options.festival_locations == FestivalLocations.option_hard or number_of_movement_buffs < 2: - return True_() - return self.received(Buff.movement, number_of_movement_buffs // 2) - - def can_succeed_luau_soup(self) -> StardewRule: - if self.options.festival_locations != FestivalLocations.option_hard: - return True_() - eligible_fish = [Fish.blobfish, Fish.crimsonfish, "Ice Pip", Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish, - Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, "Super Cucumber"] - fish_rule = [self.has(fish) for fish in eligible_fish] - eligible_kegables = [Fruit.ancient_fruit, Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, - Fruit.melon, Fruit.orange, Fruit.peach, Fruit.pineapple, Fruit.pomegranate, Fruit.rhubarb, - Fruit.starfruit, Fruit.strawberry, Forageable.cactus_fruit, - Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, Vegetable.hops, Vegetable.wheat] - keg_rules = [self.can_keg(kegable) for kegable in eligible_kegables] - aged_rule = [self.can_age(rule, "Iridium") for rule in keg_rules] - # There are a few other valid items but I don't feel like coding them all - return Or(fish_rule) | Or(aged_rule) - - def can_succeed_grange_display(self) -> StardewRule: - if self.options.festival_locations != FestivalLocations.option_hard: - return True_() - animal_rule = self.has_animal(Generic.any) - artisan_rule = self.can_keg(Generic.any) | self.can_preserves_jar(Generic.any) - cooking_rule = True_() # Salads at the bar are good enough - fish_rule = self.can_fish(50) - forage_rule = True_() # Hazelnut always available since the grange display is in fall - mineral_rule = self.can_open_geode(Generic.any) # More than half the minerals are good enough - good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, - Fruit.pomegranate, - Fruit.strawberry, Fruit.melon, Fruit.rhubarb, Fruit.pineapple, Fruit.ancient_fruit, Fruit.starfruit, ] - fruit_rule = Or([self.has(fruit) for fruit in good_fruits]) - good_vegetables = [Vegetable.amaranth, Vegetable.artichoke, Vegetable.beet, Vegetable.cauliflower, Forageable.fiddlehead_fern, Vegetable.kale, - Vegetable.radish, Vegetable.taro_root, Vegetable.yam, Vegetable.red_cabbage, Vegetable.pumpkin] - vegetable_rule = Or([self.has(vegetable) for vegetable in good_vegetables]) - - return animal_rule & artisan_rule & cooking_rule & fish_rule & \ - forage_rule & fruit_rule & mineral_rule & vegetable_rule - - def can_win_fishing_competition(self) -> StardewRule: - return self.can_fish(60) - - def has_any_universal_love(self) -> StardewRule: - key = f"has_any_universal_love" - if key not in self.cached_rules: - self.cached_rules[key] = self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) - return self.cached_rules[key] - - def has_jelly(self) -> StardewRule: - return self.can_preserves_jar(Fruit.any) - - def has_pickle(self) -> StardewRule: - return self.can_preserves_jar(Vegetable.any) - - def can_preserves_jar(self, item: str) -> StardewRule: - machine_rule = self.has(Machine.preserves_jar) - if item == Generic.any: - return machine_rule - if item == Fruit.any: - return machine_rule & self.has(all_fruits, 1) - if item == Vegetable.any: - return machine_rule & self.has(all_vegetables, 1) - return machine_rule & self.has(item) - - def has_wine(self) -> StardewRule: - return self.can_keg(Fruit.any) - - def has_juice(self) -> StardewRule: - return self.can_keg(Vegetable.any) - - def can_keg(self, item: str) -> StardewRule: - machine_rule = self.has(Machine.keg) - if item == Generic.any: - return machine_rule - if item == Fruit.any: - return machine_rule & self.has(all_fruits, 1) - if item == Vegetable.any: - return machine_rule & self.has(all_vegetables, 1) - return machine_rule & self.has(item) - - def can_age(self, item: Union[str, StardewRule], quality: str) -> StardewRule: - months = 1 - if quality == "Gold": - months = 2 - elif quality == "Iridium": - months = 3 - if isinstance(item, str): - rule = self.has(item) - else: - rule: StardewRule = item - return self.has(Machine.cask) & self.has_lived_months(months) & rule - - def can_buy_animal(self, animal: str) -> StardewRule: - price = 0 - building = "" - if animal == Animal.chicken: - price = 800 - building = Building.coop - elif animal == Animal.cow: - price = 1500 - building = Building.barn - elif animal == Animal.goat: - price = 4000 - building = Building.big_barn - elif animal == Animal.duck: - price = 1200 - building = Building.big_coop - elif animal == Animal.sheep: - price = 8000 - building = Building.deluxe_barn - elif animal == Animal.rabbit: - price = 8000 - building = Building.deluxe_coop - elif animal == Animal.pig: - price = 16000 - building = Building.deluxe_barn - else: - return True_() - return self.can_spend_money_at(Region.ranch, price) & self.has_building(building) - - def has_animal(self, animal: str) -> StardewRule: - if animal == Generic.any: - return self.has_any_animal() - elif animal == Building.coop: - return self.has_any_coop_animal() - elif animal == Building.barn: - return self.has_any_barn_animal() - return self.has(animal) - - def has_happy_animal(self, animal: str) -> StardewRule: - return self.has_animal(animal) & self.has(Forageable.hay) - - def has_any_animal(self) -> StardewRule: - return self.has_any_coop_animal() | self.has_any_barn_animal() - - def has_any_coop_animal(self) -> StardewRule: - coop_rule = Or([self.has_animal(coop_animal) for coop_animal in coop_animals]) - return coop_rule - - def has_any_barn_animal(self) -> StardewRule: - barn_rule = Or([self.has_animal(barn_animal) for barn_animal in barn_animals]) - return barn_rule - - def can_open_geode(self, geode: str) -> StardewRule: - key = f"can_open_geode {geode}" - if key not in self.cached_rules: - blacksmith_access = self.can_reach_region("Clint's Blacksmith") - geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] - if geode == Generic.any: - self.cached_rules[key] = blacksmith_access & Or([self.has(geode_type) for geode_type in geodes]) - else: - self.cached_rules[key] = blacksmith_access & self.has(geode) - return self.cached_rules[key] - - def has_island_trader(self) -> StardewRule: - if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: - return False_() - return self.can_reach_region(Region.island_trader) - - def has_walnut(self, number: int) -> StardewRule: - if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: - return False_() - if number <= 0: - return True_() - # https://stardewcommunitywiki.com/Golden_Walnut#Walnut_Locations - reach_south = self.can_reach_region(Region.island_south) - reach_north = self.can_reach_region(Region.island_north) - reach_west = self.can_reach_region(Region.island_west) - reach_hut = self.can_reach_region(Region.leo_hut) - reach_southeast = self.can_reach_region(Region.island_south_east) - reach_field_office = self.can_reach_region(Region.field_office) - reach_pirate_cove = self.can_reach_region(Region.pirate_cove) - reach_outside_areas = And(reach_south, reach_north, reach_west, reach_hut) - reach_volcano_regions = [self.can_reach_region(Region.volcano), - self.can_reach_region(Region.volcano_secret_beach), - self.can_reach_region(Region.volcano_floor_5), - self.can_reach_region(Region.volcano_floor_10)] - reach_volcano = Or(reach_volcano_regions) - reach_all_volcano = And(reach_volcano_regions) - reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano, reach_field_office] - reach_caves = And(self.can_reach_region(Region.qi_walnut_room), self.can_reach_region(Region.dig_site), - self.can_reach_region(Region.gourmand_frog_cave), - self.can_reach_region(Region.colored_crystals_cave), - self.can_reach_region(Region.shipwreck), self.has(Weapon.any_slingshot)) - reach_entire_island = And(reach_outside_areas, reach_field_office, reach_all_volcano, - reach_caves, reach_southeast, reach_pirate_cove) - if number <= 5: - return Or(reach_south, reach_north, reach_west, reach_volcano) - if number <= 10: - return Count(2, reach_walnut_regions) - if number <= 15: - return Count(3, reach_walnut_regions) - if number <= 20: - return And(reach_walnut_regions) - if number <= 50: - return reach_entire_island - gems = [Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz] - return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.can_mine_perfectly() & \ - self.can_fish_perfectly() & self.has(Craftable.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) & \ - self.can_complete_field_office() - - def has_everything(self, all_progression_items: Set[str]) -> StardewRule: - all_regions = [region.name for region in vanilla_regions] - rules = self.received(all_progression_items, len(all_progression_items)) & \ - self.can_reach_all_regions(all_regions) - return rules - - def heart(self, npc: Union[str, Villager]) -> str: - if isinstance(npc, str): - return f"{npc} <3" - return self.heart(npc.name) - - def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: - key = f"can_forage {season} {region} {need_hoe}" - if key not in self.cached_rules: - season_rule = self.has_season(season) - region_rule = self.can_reach_region(region) - if need_hoe: - self.cached_rules[key] = season_rule & region_rule & self.has_tool(Tool.hoe) - else: - self.cached_rules[key] = season_rule & region_rule - return self.cached_rules[key] - - def npc_is_in_current_slot(self, name: str) -> bool: - npc = all_villagers_by_name[name] - mod = npc.mod_name - return mod is None or mod in self.options.mods - - def can_do_combat_at_level(self, level: str) -> StardewRule: - key = f"can_do_combat_at_level {level}" - if key not in self.cached_rules: - if level == Performance.basic: - self.cached_rules[key] = self.has_any_weapon() | magic.has_any_spell(self) - elif level == Performance.decent: - self.cached_rules[key] = self.has_decent_weapon() | magic.has_decent_spells(self) - elif level == Performance.good: - self.cached_rules[key] = self.has_good_weapon() | magic.has_good_spells(self) - elif level == Performance.great: - self.cached_rules[key] = self.has_great_weapon() | magic.has_great_spells(self) - elif level == Performance.galaxy: - self.cached_rules[key] = self.has_galaxy_weapon() | magic.has_amazing_spells(self) - else: - self.cached_rules[key] = False_() - return self.cached_rules[key] - - def can_water(self, level: int) -> StardewRule: - key = f"can_water {level}" - if key not in self.cached_rules: - tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) - spell_rule = (self.received(MagicSpell.water) & magic.can_use_altar(self) & self.has_skill_level(ModSkill.magic, level)) - self.cached_rules[key] = tool_rule | spell_rule - return self.cached_rules[key] - - def has_prismatic_jelly_reward_access(self) -> StardewRule: - if self.options.special_order_locations == SpecialOrderLocations.option_disabled: - return self.can_complete_special_order("Prismatic Jelly") - return self.received("Monster Musk Recipe") - - def has_all_rarecrows(self) -> StardewRule: - rules = [] - for rarecrow_number in range(1, 9): - rules.append(self.received(f"Rarecrow #{rarecrow_number}")) - return And(rules) - - def can_ship(self, item: str = "") -> StardewRule: - shipping_bin_rule = self.has_building(Building.shipping_bin) - if item == "": - return shipping_bin_rule - return shipping_bin_rule & self.has(item) - diff --git a/worlds/stardew_valley/logic/__init__.py b/worlds/stardew_valley/logic/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py new file mode 100644 index 000000000000..19d8ddfea98b --- /dev/null +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -0,0 +1,68 @@ +from .mine_logic import MineLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .skill_logic import SkillLogic +from .tool_logic import ToolLogic +from ..mods.logic.magic_logic import MagicLogic +from ..mods.logic.skills_logic import ModSkillLogic +from ..stardew_rule import StardewRule +from ..strings.ap_names.buff_names import Buff +from ..strings.region_names import Region +from ..strings.skill_names import Skill, ModSkill +from ..strings.tool_names import ToolMaterial, Tool + + +class AbilityLogic: + player: int + movement_buff_option: int + luck_buff_option: int + received: ReceivedLogic + region: RegionLogic + tool: ToolLogic + skill: SkillLogic + mine: MineLogic + magic: MagicLogic + mod_skill: ModSkillLogic + + def __init__(self, player: int, movement_buff_option: int, luck_buff_option: int, received: ReceivedLogic, region: RegionLogic, tool: ToolLogic, + skill: SkillLogic, mine: MineLogic): + self.player = player + self.movement_buff_option = movement_buff_option + self.luck_buff_option = luck_buff_option + self.received = received + self.region = region + self.tool = tool + self.skill = skill + self.mine = mine + + def set_magic(self, magic: MagicLogic, mod_skill: ModSkillLogic): + self.magic = magic + self.mod_skill = mod_skill + + def can_mine_perfectly(self) -> StardewRule: + return self.mine.can_progress_in_the_mines_from_floor(160) + + def can_mine_perfectly_in_the_skull_cavern(self) -> StardewRule: + return (self.can_mine_perfectly() & + self.region.can_reach(Region.skull_cavern)) + + def can_farm_perfectly(self) -> StardewRule: + tool_rule = self.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.tool.can_water(4) + return tool_rule & self.skill.has_farming_level(10) + + def can_fish_perfectly(self) -> StardewRule: + skill_rule = self.skill.has_level(Skill.fishing, 10) + return skill_rule & self.tool.has_fishing_rod(4) + + def can_chop_trees(self) -> StardewRule: + return self.tool.has_tool(Tool.axe) & self.region.can_reach(Region.forest) + + def can_chop_perfectly(self) -> StardewRule: + magic_rule = (self.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.mod_skill.has_mod_level(ModSkill.magic, 10) + tool_rule = self.tool.has_tool(Tool.axe, ToolMaterial.iridium) + foraging_rule = self.skill.has_level(Skill.foraging, 10) + region_rule = self.region.can_reach(Region.forest) + return region_rule & ((tool_rule & foraging_rule) | magic_rule) + + def has_max_buffs(self) -> StardewRule: + return self.received(Buff.movement, self.movement_buff_option) & self.received(Buff.luck, self.luck_buff_option) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py new file mode 100644 index 000000000000..5dd13f9d7db8 --- /dev/null +++ b/worlds/stardew_valley/logic/action_logic.py @@ -0,0 +1,36 @@ +from .has_logic import HasLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from ..stardew_rule import StardewRule, True_, Or +from ..strings.generic_names import Generic +from ..strings.geode_names import Geode +from ..strings.region_names import Region + + +class ActionLogic: + player: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + + def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic): + self.player = player + self.received = received + self.has = has + self.region = region + + def can_watch(self, channel: str = None): + tv_rule = True_() + if channel is None: + return tv_rule + return self.received(channel) & tv_rule + + def can_do_panning(self, item: str = Generic.any) -> StardewRule: + return self.received("Glittering Boulder Removed") + + def can_open_geode(self, geode: str) -> StardewRule: + blacksmith_access = self.region.can_reach(Region.blacksmith) + geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] + if geode == Generic.any: + return blacksmith_access & Or([self.has(geode_type) for geode_type in geodes]) + return blacksmith_access & self.has(geode) diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py new file mode 100644 index 000000000000..0ff9615bdb4a --- /dev/null +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -0,0 +1,36 @@ +from .. import options +from ..stardew_rule import StardewRule, True_ +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from ..strings.region_names import Region + + +class ArcadeLogic: + player: int + arcade_option: int + received = ReceivedLogic + region: RegionLogic + + def __init__(self, player: int, arcade_option: int, received: ReceivedLogic, region: RegionLogic): + self.player = player + self.arcade_option = arcade_option + self.received = received + self.region = region + + def has_jotpk_power_level(self, power_level: int) -> StardewRule: + if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: + return True_() + jotpk_buffs = ["JotPK: Progressive Boots", "JotPK: Progressive Gun", + "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate"] + return self.received(jotpk_buffs, power_level) + + def has_junimo_kart_power_level(self, power_level: int) -> StardewRule: + if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: + return True_() + return self.received("Junimo Kart: Extra Life", power_level) + + def has_junimo_kart_max_level(self) -> StardewRule: + play_rule = self.region.can_reach(Region.junimo_kart_3) + if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: + return play_rule + return self.has_junimo_kart_power_level(8) diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py new file mode 100644 index 000000000000..64e6b572065c --- /dev/null +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -0,0 +1,63 @@ +from typing import Union + +from .has_logic import HasLogic +from .time_logic import TimeLogic +from ..stardew_rule import StardewRule +from ..strings.crop_names import all_vegetables, all_fruits, Vegetable, Fruit +from ..strings.generic_names import Generic +from ..strings.machine_names import Machine + + +class ArtisanLogic: + player: int + has: HasLogic + time: TimeLogic + + def __init__(self, player: int, has: HasLogic, time: TimeLogic): + self.player = player + self.has = has + self.time = time + + def has_jelly(self) -> StardewRule: + return self.can_preserves_jar(Fruit.any) + + def has_pickle(self) -> StardewRule: + return self.can_preserves_jar(Vegetable.any) + + def can_preserves_jar(self, item: str) -> StardewRule: + machine_rule = self.has(Machine.preserves_jar) + if item == Generic.any: + return machine_rule + if item == Fruit.any: + return machine_rule & self.has(all_fruits, 1) + if item == Vegetable.any: + return machine_rule & self.has(all_vegetables, 1) + return machine_rule & self.has(item) + + def has_wine(self) -> StardewRule: + return self.can_keg(Fruit.any) + + def has_juice(self) -> StardewRule: + return self.can_keg(Vegetable.any) + + def can_keg(self, item: str) -> StardewRule: + machine_rule = self.has(Machine.keg) + if item == Generic.any: + return machine_rule + if item == Fruit.any: + return machine_rule & self.has(all_fruits, 1) + if item == Vegetable.any: + return machine_rule & self.has(all_vegetables, 1) + return machine_rule & self.has(item) + + def can_age(self, item: Union[str, StardewRule], quality: str) -> StardewRule: + months = 1 + if quality == "Gold": + months = 2 + elif quality == "Iridium": + months = 3 + if isinstance(item, str): + rule = self.has(item) + else: + rule: StardewRule = item + return self.has(Machine.cask) & self.time.has_lived_months(months) & rule diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py new file mode 100644 index 000000000000..a710d75c537d --- /dev/null +++ b/worlds/stardew_valley/logic/building_logic.py @@ -0,0 +1,96 @@ +from typing import Iterable, Dict + +from .has_logic import HasLogic +from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .. import options +from ..stardew_rule import StardewRule, True_, False_, Has +from ..strings.artisan_good_names import ArtisanGood +from ..strings.building_names import Building +from ..strings.fish_names import WaterItem +from ..strings.material_names import Material +from ..strings.metal_names import MetalBar +from ..strings.region_names import Region + + +class BuildingLogic: + player: int + building_option: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + money: MoneyLogic + building_rules: Dict[str, StardewRule] + mods_option: Iterable[str] + + def __init__(self, player: int, building_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic, mods_option: Iterable[str]): + self.player = player + self.building_option = building_option + self.received = received + self.has = has + self.region = region + self.money = money + self.mods_option = mods_option + self.building_rules = dict() + + def initialize_rules(self): + self.building_rules.update({ + Building.barn: self.money.can_spend_at(Region.carpenter, 6000) & self.has([Material.wood, Material.stone]), + Building.big_barn: self.money.can_spend_at(Region.carpenter, 12000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.barn), + Building.deluxe_barn: self.money.can_spend_at(Region.carpenter, 25000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.big_barn), + Building.coop: self.money.can_spend_at(Region.carpenter, 4000) & self.has([Material.wood, Material.stone]), + Building.big_coop: self.money.can_spend_at(Region.carpenter, 10000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.coop), + Building.deluxe_coop: self.money.can_spend_at(Region.carpenter, 20000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.big_coop), + Building.fish_pond: self.money.can_spend_at(Region.carpenter, 5000) & self.has([Material.stone, WaterItem.seaweed, WaterItem.green_algae]), + Building.mill: self.money.can_spend_at(Region.carpenter, 2500) & self.has([Material.stone, Material.wood, ArtisanGood.cloth]), + Building.shed: self.money.can_spend_at(Region.carpenter, 15000) & self.has(Material.wood), + Building.big_shed: self.money.can_spend_at(Region.carpenter, 20000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.shed), + Building.silo: self.money.can_spend_at(Region.carpenter, 100) & self.has([Material.stone, Material.clay, MetalBar.copper]), + Building.slime_hutch: self.money.can_spend_at(Region.carpenter, 10000) & self.has([Material.stone, MetalBar.quartz, MetalBar.iridium]), + Building.stable: self.money.can_spend_at(Region.carpenter, 10000) & self.has([Material.hardwood, MetalBar.iron]), + Building.well: self.money.can_spend_at(Region.carpenter, 1000) & self.has(Material.stone), + Building.shipping_bin: self.money.can_spend_at(Region.carpenter, 250) & self.has(Material.wood), + Building.kitchen: self.money.can_spend_at(Region.carpenter, 10000) & self.has(Material.wood) & self.has_house(0), + Building.kids_room: self.money.can_spend_at(Region.carpenter, 50000) & self.has(Material.hardwood) & self.has_house(1), + Building.cellar: self.money.can_spend_at(Region.carpenter, 100000) & self.has_house(2), + }) + + def update_rules(self, new_rules: Dict[str, StardewRule]): + self.building_rules.update(new_rules) + + def has_building(self, building: str) -> StardewRule: + carpenter_rule = self.region.can_reach(Region.carpenter) + if self.building_option == options.BuildingProgression.option_vanilla: + return Has(building, self.building_rules) & carpenter_rule + + count = 1 + if building in [Building.coop, Building.barn, Building.shed]: + building = f"Progressive {building}" + elif building.startswith("Big"): + count = 2 + building = " ".join(["Progressive", *building.split(" ")[1:]]) + elif building.startswith("Deluxe"): + count = 3 + building = " ".join(["Progressive", *building.split(" ")[1:]]) + return self.received(f"{building}", count) & carpenter_rule + + def has_house(self, upgrade_level: int) -> StardewRule: + if upgrade_level < 1: + return True_() + + if upgrade_level > 3: + return False_() + + if not self.building_option == options.BuildingProgression.option_vanilla: + return self.received(f"Progressive House", upgrade_level) & self.region.can_reach(Region.carpenter) + + if upgrade_level == 1: + return Has(Building.kitchen, self.building_rules) + + if upgrade_level == 2: + return Has(Building.kids_room, self.building_rules) + + # if upgrade_level == 3: + return Has(Building.cellar, self.building_rules) + diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py new file mode 100644 index 000000000000..b4c0ce22be0c --- /dev/null +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -0,0 +1,57 @@ +from .received_logic import ReceivedLogic +from ..mods.logic.magic_logic import MagicLogic +from ..stardew_rule import StardewRule +from ..strings.performance_names import Performance +from ..items import all_items, Group + + +class CombatLogic: + player: int + received: ReceivedLogic + magic: MagicLogic + + def __init__(self, player: int, received: ReceivedLogic): + self.player = player + self.received = received + + def set_magic(self, magic: MagicLogic): + self.magic = magic + + def can_fight_at_level(self, level: str) -> StardewRule: + if level == Performance.basic: + return self.has_any_weapon() | self.magic.has_any_spell() + if level == Performance.decent: + return self.has_decent_weapon() | self.magic.has_decent_spells() + if level == Performance.good: + return self.has_good_weapon() | self.magic.has_good_spells() + if level == Performance.great: + return self.has_great_weapon() | self.magic.has_great_spells() + if level == Performance.galaxy: + return self.has_galaxy_weapon() | self.magic.has_amazing_spells() + + def has_any_weapon(self) -> StardewRule: + higher_weapon_rule = self.has_decent_weapon() + this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups) + return higher_weapon_rule | this_weapon_rule + + def has_decent_weapon(self) -> StardewRule: + higher_weapon_rule = self.has_good_weapon() + this_weapon_rule = self.received(item.name for item in all_items + if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) + return (higher_weapon_rule | this_weapon_rule) & self.received("Adventurer's Guild") + + def has_good_weapon(self) -> StardewRule: + higher_weapon_rule = self.has_great_weapon() + this_weapon_rule = self.received(item.name for item in all_items + if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) + return (higher_weapon_rule | this_weapon_rule) & self.received("Adventurer's Guild") + + def has_great_weapon(self) -> StardewRule: + higher_weapon_rule = self.has_galaxy_weapon() + this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) + return (higher_weapon_rule | this_weapon_rule) & self.received("Adventurer's Guild") + + def has_galaxy_weapon(self) -> StardewRule: + this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) + return this_weapon_rule & self.received("Adventurer's Guild") + diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py new file mode 100644 index 000000000000..a99c34685edd --- /dev/null +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -0,0 +1,62 @@ +from .action_logic import ActionLogic +from .building_logic import BuildingLogic +from .has_logic import HasLogic +from .money_logic import MoneyLogic +from .relationship_logic import RelationshipLogic +from .season_logic import SeasonLogic +from .skill_logic import SkillLogic +from .time_logic import TimeLogic +from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe +from ..stardew_rule import StardewRule, True_, False_, And +from ..strings.skill_names import Skill +from ..strings.tv_channel_names import Channel + + +class CookingLogic: + player: int + has: HasLogic + season: SeasonLogic + time: TimeLogic + money: MoneyLogic + action: ActionLogic + buildings: BuildingLogic + relationship: RelationshipLogic + skill: SkillLogic + + def __init__(self, player: int, has: HasLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, + relationship: RelationshipLogic, skill: SkillLogic): + self.player = player + self.has = has + self.season = season + self.time = time + self.money = money + self.action = action + self.buildings = buildings + self.relationship = relationship + self.skill = skill + + def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: + cook_rule = self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) + if recipe is None: + return cook_rule + + learn_rule = self.can_learn_recipe(recipe.source) + ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) + number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) + time_rule = self.time.has_lived_months(number_ingredients) + return cook_rule & learn_rule & ingredients_rule & time_rule + + def can_learn_recipe(self, source: RecipeSource) -> StardewRule: + if isinstance(source, StarterSource): + return True_() + if isinstance(source, ShopSource): + return self.money.can_spend_at(source.region, source.price) + if isinstance(source, SkillSource): + return self.skill.has_level(source.skill, source.level) + if isinstance(source, FriendshipSource): + return self.relationship.has_hearts(source.friend, source.hearts) + if isinstance(source, QueenOfSauceSource): + year_rule = self.time.has_year_two() if source.year == 2 else self.time.has_year_three() + return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule + + return False_() diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py new file mode 100644 index 000000000000..02f510732865 --- /dev/null +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -0,0 +1,45 @@ +from typing import Union, Iterable + +from .has_logic import HasLogic +from .region_logic import RegionLogic +from .season_logic import SeasonLogic +from .tool_logic import ToolLogic +from ..data import CropItem +from ..stardew_rule import StardewRule +from ..strings.region_names import Region +from ..strings.tool_names import Tool + + +class CropLogic: + player: int + has: HasLogic + region: RegionLogic + season: SeasonLogic + tool: ToolLogic + + def __init__(self, player: int, has: HasLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic): + self.player = player + self.has = has + self.region = region + self.season = season + self.tool = tool + + def can_grow(self, crop: CropItem) -> StardewRule: + season_rule = self.season.has_any(crop.farm_growth_seasons) + seed_rule = self.has(crop.seed.name) + farm_rule = self.region.can_reach(Region.farm) & season_rule + tool_rule = self.tool.has_tool(Tool.hoe) & self.tool.has_tool(Tool.watering_can) + region_rule = farm_rule | self.region.can_reach(Region.greenhouse) | self.region.can_reach(Region.island_west) + return seed_rule & region_rule & tool_rule + + def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> StardewRule: + if isinstance(seasons, str): + seasons = [seasons] + season_rule = self.season.has_any(seasons) | self.region.can_reach(Region.greenhouse) | self.has_island_farm() + farm_rule = self.region.can_reach(Region.farm) | self.region.can_reach( + Region.greenhouse) | self.has_island_farm() + return season_rule & farm_rule + + def has_island_farm(self) -> StardewRule: + return self.region.can_reach(Region.island_south) + diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py new file mode 100644 index 000000000000..06c8e18aa21c --- /dev/null +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -0,0 +1,30 @@ +from .region_logic import RegionLogic +from .skill_logic import SkillLogic +from .tool_logic import ToolLogic +from ..stardew_rule import StardewRule +from ..strings.region_names import Region +from ..strings.skill_names import Skill + + +class FishingLogic: + player: int + region: RegionLogic + tool: ToolLogic + skill: SkillLogic + + def __init__(self, player: int, region: RegionLogic, tool: ToolLogic, skill: SkillLogic): + self.player = player + self.region = region + self.tool = tool + self.skill = skill + + def can_fish_in_freshwater(self) -> StardewRule: + return self.skill.can_fish() & self.region.can_reach_any([Region.forest, Region.town, Region.mountain]) + + def has_max_fishing(self) -> StardewRule: + skill_rule = self.skill.has_level(Skill.fishing, 10) + return self.tool.has_fishing_rod(4) & skill_rule + + def can_fish_chests(self) -> StardewRule: + skill_rule = self.skill.has_level(Skill.fishing, 4) + return self.tool.has_fishing_rod(4) & skill_rule diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py new file mode 100644 index 000000000000..b883f60a0711 --- /dev/null +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -0,0 +1,17 @@ +from .has_logic import HasLogic +from ..stardew_rule import StardewRule +from ..strings.animal_product_names import AnimalProduct +from ..strings.gift_names import Gift + + +class GiftLogic: + player: int + has: HasLogic + + def __init__(self, player: int, has: HasLogic): + self.player = player + self.has = has + + def has_any_universal_love(self) -> StardewRule: + return self.has(Gift.golden_pumpkin) | self.has("Magic Rock Candy") | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) + diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py new file mode 100644 index 000000000000..76e452a5d124 --- /dev/null +++ b/worlds/stardew_valley/logic/has_logic.py @@ -0,0 +1,34 @@ +from typing import Dict, Union, Optional, Iterable, Sized, List + +from ..stardew_rule import StardewRule, True_, And, Or, Has, Count + + +class HasLogic: + player: int + item_rules: Dict[str, StardewRule] + + def __init__(self, player: int, item_rules: Dict[str, StardewRule]): + self.player = player + self.item_rules = item_rules + + def __call__(self, *args, **kwargs) -> StardewRule: + count = None + if len(args) >= 2: + count = args[1] + return self.has(args[0], count) + + def has(self, items: Union[str, List[str]], count: Optional[int] = None) -> StardewRule: + if isinstance(items, str): + return Has(items, self.item_rules) + + if len(items) == 0: + return True_() + + if count is None or count == len(items): + return And(self.has(item) for item in items) + + if count == 1: + return Or(self.has(item) for item in items) + + return Count(count, (self.has(item) for item in items)) + diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py new file mode 100644 index 000000000000..ac5aa109acb7 --- /dev/null +++ b/worlds/stardew_valley/logic/logic.py @@ -0,0 +1,805 @@ +from __future__ import annotations + +from dataclasses import field, dataclass +from typing import Dict, List, Set + +from .ability_logic import AbilityLogic +from .action_logic import ActionLogic +from .arcade_logic import ArcadeLogic +from .artisan_logic import ArtisanLogic +from .building_logic import BuildingLogic +from .combat_logic import CombatLogic +from .cooking_logic import CookingLogic +from .crop_logic import CropLogic +from .fishing_logic import FishingLogic +from .gift_logic import GiftLogic +from .mine_logic import MineLogic +from .money_logic import MoneyLogic +from .museum_logic import MuseumLogic +from .pet_logic import PetLogic +from .received_logic import ReceivedLogic +from .has_logic import HasLogic +from .region_logic import RegionLogic +from .relationship_logic import RelationshipLogic +from .season_logic import SeasonLogic +from .skill_logic import SkillLogic +from .special_order_logic import SpecialOrderLogic +from .time_logic import TimeLogic +from .tool_logic import ToolLogic +from .wallet_logic import WalletLogic +from ..mods.logic.mod_logic import ModLogic +from .. import options +from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops +from ..data.bundle_data import BundleItem +from ..data.fish_data import island_fish +from ..data.museum_data import all_museum_items +from ..data.recipe_data import all_cooking_recipes +from ..options import StardewOptions +from ..regions import vanilla_regions +from ..stardew_rule import False_, Or, True_, Count, And, Has, StardewRule +from ..strings.animal_names import Animal, coop_animals, barn_animals +from ..strings.animal_product_names import AnimalProduct +from ..strings.ap_names.buff_names import Buff +from ..strings.artisan_good_names import ArtisanGood +from ..strings.building_names import Building +from ..strings.calendar_names import Weekday +from ..strings.craftable_names import Craftable +from ..strings.crop_names import Fruit, Vegetable +from ..strings.fertilizer_names import Fertilizer +from ..strings.festival_check_names import FestivalCheck +from ..strings.fish_names import Fish, Trash, WaterItem +from ..strings.flower_names import Flower +from ..strings.forageable_names import Forageable +from ..strings.fruit_tree_names import Sapling +from ..strings.generic_names import Generic +from ..strings.geode_names import Geode +from ..strings.gift_names import Gift +from ..strings.ingredient_names import Ingredient +from ..strings.material_names import Material +from ..strings.machine_names import Machine +from ..strings.food_names import Meal, Beverage +from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil +from ..strings.monster_drop_names import Loot +from ..strings.quest_names import Quest +from ..strings.region_names import Region +from ..strings.season_names import Season +from ..strings.seed_names import Seed +from ..strings.skill_names import Skill +from ..strings.tool_names import Tool, ToolMaterial +from ..strings.villager_names import NPC +from ..strings.wallet_item_names import Wallet +from ..strings.weapon_names import Weapon + +MISSING_ITEM = "THIS ITEM IS MISSING" + +fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] + + +@dataclass(frozen=False, repr=False) +class StardewLogic: + player: int + options: StardewOptions + + item_rules: Dict[str, StardewRule] = field(default_factory=dict) + sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) + tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) + seed_rules: Dict[str, StardewRule] = field(default_factory=dict) + cooking_rules: Dict[str, StardewRule] = field(default_factory=dict) + crop_rules: Dict[str, StardewRule] = field(default_factory=dict) + fish_rules: Dict[str, StardewRule] = field(default_factory=dict) + museum_rules: Dict[str, StardewRule] = field(default_factory=dict) + quest_rules: Dict[str, StardewRule] = field(default_factory=dict) + festival_rules: Dict[str, StardewRule] = field(default_factory=dict) + + def __post_init__(self): + self.received = ReceivedLogic(self.player) + self.has = HasLogic(self.player, self.item_rules) + self.region = RegionLogic(self.player) + self.time = TimeLogic(self.player, self.received) + self.season = SeasonLogic(self.player, self.options[options.SeasonRandomization], self.received, self.time) + self.money = MoneyLogic(self.player, self.options[options.StartingMoney], self.region, self.time) + self.action = ActionLogic(self.player, self.received, self.has, self.region) + self.arcade = ArcadeLogic(self.player, self.options[options.ArcadeMachineLocations], self.received, self.region) + self.artisan = ArtisanLogic(self.player, self.has, self.time) + self.gifts = GiftLogic(self.player, self.has) + tool_option = self.options[options.ToolProgression] + skill_option = self.options[options.SkillProgression] + elevator_option = self.options[options.ElevatorProgression] + friendsanity_option = self.options[options.Friendsanity] + heart_size_option = self.options[options.FriendsanityHeartSize] + mods_option = self.options[options.Mods] + self.buildings = BuildingLogic(self.player, self.options[options.BuildingProgression], self.received, self.has, self.region, self.money, mods_option) + self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, + self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) + self.museum = MuseumLogic(self.player, self.options[options.Museumsanity], self.received, self.has, self.region, self.action) + self.wallet = WalletLogic(self.player, self.received, self.museum) + self.combat = CombatLogic(self.player, self.received) + self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) + self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) + self.crop = CropLogic(self.player, self.has, self.region, self.season, self.tool) + self.skill = SkillLogic(self.player, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) + self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) + self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, + self.tool, self.skill) + self.cooking = CookingLogic(self.player, self.has, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, + self.region, self.tool, self.skill, self.mine) + self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.arcade, self.artisan, + self.relationship, self.skill, self.mine, self.cooking, self.ability) + + self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, + self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability) + + self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) + self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) + + for recipe in all_cooking_recipes: + can_cook_rule = self.cooking.can_cook(recipe) + if recipe.meal in self.cooking_rules: + can_cook_rule = can_cook_rule | self.cooking_rules[recipe.meal] + self.cooking_rules[recipe.meal] = can_cook_rule + + self.sapling_rules.update({ + Sapling.apple: self.can_buy_sapling(Fruit.apple), + Sapling.apricot: self.can_buy_sapling(Fruit.apricot), + Sapling.cherry: self.can_buy_sapling(Fruit.cherry), + Sapling.orange: self.can_buy_sapling(Fruit.orange), + Sapling.peach: self.can_buy_sapling(Fruit.peach), + Sapling.pomegranate: self.can_buy_sapling(Fruit.pomegranate), + Sapling.banana: self.can_buy_sapling(Fruit.banana), + Sapling.mango: self.can_buy_sapling(Fruit.mango), + }) + + self.tree_fruit_rules.update({ + Fruit.apple: self.crop.can_plant_and_grow_item(Season.fall), + Fruit.apricot: self.crop.can_plant_and_grow_item(Season.spring), + Fruit.cherry: self.crop.can_plant_and_grow_item(Season.spring), + Fruit.orange: self.crop.can_plant_and_grow_item(Season.summer), + Fruit.peach: self.crop.can_plant_and_grow_item(Season.summer), + Fruit.pomegranate: self.crop.can_plant_and_grow_item(Season.fall), + Fruit.banana: self.crop.can_plant_and_grow_item(Season.summer), + Fruit.mango: self.crop.can_plant_and_grow_item(Season.summer), + }) + + for tree_fruit in self.tree_fruit_rules: + existing_rules = self.tree_fruit_rules[tree_fruit] + sapling = f"{tree_fruit} Sapling" + self.tree_fruit_rules[tree_fruit] = existing_rules & self.has(sapling) & self.time.has_lived_months(1) + + self.seed_rules.update({seed.name: self.can_buy_seed(seed) for seed in all_purchasable_seeds}) + self.crop_rules.update({crop.name: self.crop.can_grow(crop) for crop in all_crops}) + self.crop_rules.update({ + Seed.coffee: (self.season.has(Season.spring) | self.season.has( + Season.summer)) & self.has_traveling_merchant(), + Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & + self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), + }) + + self.item_rules.update({ + ArtisanGood.aged_roe: self.artisan.can_preserves_jar(AnimalProduct.roe), + AnimalProduct.any_egg: self.has(AnimalProduct.chicken_egg) | self.has(AnimalProduct.duck_egg), + Fish.any: Or([self.can_catch_fish(fish) for fish in all_fish]), + Geode.artifact_trove: self.has(Geode.omni) & self.region.can_reach(Region.desert), + Craftable.bait: (self.skill.has_level(Skill.fishing, 2) & self.has(Loot.bug_meat)) | self.has(Machine.worm_bin), + Fertilizer.basic: (self.has(Material.sap) & self.skill.has_farming_level(1)) | (self.time.has_lived_months(1) & self.money.can_spend_at(Region.pierre_store, 100)), + Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), + Fertilizer.deluxe: False_(), + # self.received("Deluxe Fertilizer Recipe") & self.has(MetalBar.iridium) & self.has(SVItem.sap), + Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), + Loot.bat_wing: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), + ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.season.has_any_not_winter()) | self.has(Machine.solar_panel), + Machine.bee_house: self.skill.has_farming_level(3) & self.has(MetalBar.iron) & self.has(ArtisanGood.maple_syrup) & self.has(Material.coal) & self.has(Material.wood), + Beverage.beer: self.artisan.can_keg(Vegetable.wheat) | self.money.can_spend_at(Region.saloon, 400), + Forageable.blackberry: self.tool.can_forage(Season.fall), + Craftable.bomb: self.skill.has_level(Skill.mining, 6) & self.has(Material.coal) & self.has(Ore.iron), + Fossil.bone_fragment: self.region.can_reach(Region.dig_site), + Gift.bouquet: self.relationship.has_hearts(Generic.bachelor, 8) & self.money.can_spend_at(Region.pierre_store, 100), + Meal.bread: self.money.can_spend_at(Region.saloon, 120), + Trash.broken_cd: self.skill.can_crab_pot(), + Trash.broken_glasses: self.skill.can_crab_pot(), + Loot.bug_meat: self.mine.can_mine_in_the_mines_floor_1_40(), + Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), + Machine.cask: self.buildings.has_house(3) & self.region.can_reach(Region.cellar) & self.has(Material.wood) & self.has(Material.hardwood), + Forageable.cave_carrot: self.tool.can_forage(Generic.any, Region.mines_floor_10, True), + ArtisanGood.caviar: self.artisan.can_preserves_jar(AnimalProduct.sturgeon_roe), + Forageable.chanterelle: self.tool.can_forage(Season.fall, Region.secret_woods), + Machine.cheese_press: self.skill.has_farming_level(6) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.hardwood) & self.has(MetalBar.copper), + ArtisanGood.cheese: (self.has(AnimalProduct.cow_milk) & self.has(Machine.cheese_press)) | (self.region.can_reach(Region.desert) & self.has(Mineral.emerald)), + Craftable.cherry_bomb: self.skill.has_level(Skill.mining, 1) & self.has(Material.coal) & self.has(Ore.copper), + Animal.chicken: self.can_buy_animal(Animal.chicken), + AnimalProduct.chicken_egg: self.has([AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg], 1), + Material.cinder_shard: self.region.can_reach(Region.volcano_floor_5), + WaterItem.clam: self.tool.can_forage(Generic.any, Region.beach), + Material.clay: self.region.can_reach_any([Region.farm, Region.beach, Region.quarry]) & self.tool.has_tool(Tool.hoe), + ArtisanGood.cloth: (self.has(AnimalProduct.wool) & self.has(Machine.loom)) | (self.region.can_reach(Region.desert) & self.has(Mineral.aquamarine)), + Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.action.can_do_panning(), + WaterItem.cockle: self.tool.can_forage(Generic.any, Region.beach), + Forageable.coconut: self.tool.can_forage(Generic.any, Region.desert), + Beverage.coffee: self.artisan.can_keg(Seed.coffee) | self.has(Machine.coffee_maker) | (self.money.can_spend_at(Region.saloon, 300)) | self.has("Hot Java Ring"), + Machine.coffee_maker: self.received(Machine.coffee_maker), + Forageable.common_mushroom: self.tool.can_forage(Season.fall) | (self.tool.can_forage(Season.spring, Region.secret_woods)), + MetalBar.copper: self.can_smelt(Ore.copper), + Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + WaterItem.coral: self.tool.can_forage(Generic.any, Region.tide_pools) | self.tool.can_forage(Season.summer, Region.beach), + Animal.cow: self.can_buy_animal(Animal.cow), + AnimalProduct.cow_milk: self.has(AnimalProduct.milk) | self.has(AnimalProduct.large_milk), + Fish.crab: self.skill.can_crab_pot(Region.beach), + Machine.crab_pot: self.skill.has_level(Skill.fishing, 3) & (self.money.can_spend_at(Region.fish_shop, 1500) | (self.has(MetalBar.iron) & self.has(Material.wood))), + Fish.crayfish: self.skill.can_crab_pot(Region.town), + Forageable.crocus: self.tool.can_forage(Season.winter), + Forageable.crystal_fruit: self.tool.can_forage(Season.winter), + Forageable.daffodil: self.tool.can_forage(Season.spring), + Forageable.dandelion: self.tool.can_forage(Season.spring), + Animal.dinosaur: self.buildings.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), + Forageable.dragon_tooth: self.tool.can_forage(Generic.any, Region.volcano_floor_10), + "Dried Starfish": self.skill.can_fish() & self.region.can_reach(Region.beach), + Trash.driftwood: self.skill.can_crab_pot(), + AnimalProduct.duck_egg: self.has_animal(Animal.duck), + AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), + Animal.duck: self.can_buy_animal(Animal.duck), + AnimalProduct.egg: self.has_animal(Animal.chicken), + AnimalProduct.brown_egg: self.has_animal(Animal.chicken), + "Energy Tonic": self.region.can_reach(Region.hospital) & self.money.can_spend(1000), + Material.fiber: True_(), + Forageable.fiddlehead_fern: self.tool.can_forage(Season.summer, Region.secret_woods), + "Magic Rock Candy": self.region.can_reach(Region.desert) & self.has("Prismatic Shard"), + "Fishing Chest": self.fishing.can_fish_chests(), + Craftable.flute_block: self.relationship.has_hearts(NPC.robin, 6) & self.region.can_reach(Region.carpenter) & self.has(Material.wood) & self.has(Ore.copper) & self.has(Material.fiber), + Geode.frozen: self.mine.can_mine_in_the_mines_floor_41_80(), + Machine.furnace: self.has(Material.stone) & self.has(Ore.copper), + Geode.geode: self.mine.can_mine_in_the_mines_floor_1_40(), + Forageable.ginger: self.tool.can_forage(Generic.any, Region.island_west, True), + ArtisanGood.goat_cheese: self.has(AnimalProduct.goat_milk) & self.has(Machine.cheese_press), + AnimalProduct.goat_milk: self.has(Animal.goat), + Animal.goat: self.can_buy_animal(Animal.goat), + MetalBar.gold: self.can_smelt(Ore.gold), + Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + Geode.golden_coconut: self.region.can_reach(Region.island_north), + Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), + WaterItem.green_algae: self.fishing.can_fish_in_freshwater(), + ArtisanGood.green_tea: self.artisan.can_keg(Vegetable.tea_leaves), + Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_south)), + Forageable.hay: self.buildings.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), + Forageable.hazelnut: self.tool.can_forage(Season.fall), + Forageable.holly: self.tool.can_forage(Season.winter), + ArtisanGood.honey: self.money.can_spend_at(Region.oasis, 200) | (self.has(Machine.bee_house) & self.season.has_any_not_winter()), + "Hot Java Ring": self.region.can_reach(Region.volcano_floor_10), + Meal.ice_cream: (self.season.has(Season.summer) & self.money.can_spend_at(Region.town, 250)) | self.money.can_spend_at(Region.oasis, 240), + # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)), + MetalBar.iridium: self.can_smelt(Ore.iridium), + Ore.iridium: self.mine.can_mine_in_the_skull_cavern(), + MetalBar.iron: self.can_smelt(Ore.iron), + Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + ArtisanGood.jelly: self.artisan.has_jelly(), + Trash.joja_cola: self.money.can_spend_at(Region.saloon, 75), + "JotPK Small Buff": self.arcade.has_jotpk_power_level(2), + "JotPK Medium Buff": self.arcade.has_jotpk_power_level(4), + "JotPK Big Buff": self.arcade.has_jotpk_power_level(7), + "JotPK Max Buff": self.arcade.has_jotpk_power_level(9), + ArtisanGood.juice: self.artisan.has_juice(), + "Junimo Kart Small Buff": self.arcade.has_junimo_kart_power_level(2), + "Junimo Kart Medium Buff": self.arcade.has_junimo_kart_power_level(4), + "Junimo Kart Big Buff": self.arcade.has_junimo_kart_power_level(6), + "Junimo Kart Max Buff": self.arcade.has_junimo_kart_power_level(8), + Machine.keg: self.skill.has_farming_level(8) & self.has(Material.wood) & self.has(MetalBar.iron) & self.has(MetalBar.copper) & self.has(ArtisanGood.oak_resin), + AnimalProduct.large_egg: self.has_happy_animal(Animal.chicken), + AnimalProduct.large_brown_egg: self.has_happy_animal(Animal.chicken), + AnimalProduct.large_goat_milk: self.has_happy_animal(Animal.goat), + AnimalProduct.large_milk: self.has_happy_animal(Animal.cow), + Forageable.leek: self.tool.can_forage(Season.spring), + Craftable.life_elixir: self.skill.has_level(Skill.combat, 2) & self.has(Forageable.red_mushroom) & self.has(Forageable.purple_mushroom) & self.has(Forageable.morel) & self.has(Forageable.chanterelle), + Machine.lightning_rod: self.skill.has_level(Skill.foraging, 6) & self.has(MetalBar.iron) & self.has(MetalBar.quartz) & self.has(Loot.bat_wing), + Fish.lobster: self.skill.can_crab_pot(Region.beach), + Machine.loom: self.skill.has_farming_level(7) & self.has(Material.wood) & self.has(Material.fiber) & self.has(ArtisanGood.pine_tar), + Forageable.magma_cap: self.tool.can_forage(Generic.any, Region.volcano_floor_5), + Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.buildings.has_building(Building.fish_pond)), + ArtisanGood.maple_syrup: self.has(Machine.tapper), + ArtisanGood.mayonnaise: self.has(Machine.mayonnaise_machine) & self.has(AnimalProduct.chicken_egg), + Machine.mayonnaise_machine: self.skill.has_farming_level(2) & self.has(Material.wood) & self.has(Material.stone) & self.has("Earth Crystal") & self.has(MetalBar.copper), + ArtisanGood.mead: self.artisan.can_keg(ArtisanGood.honey), + Craftable.mega_bomb: self.skill.has_level(Skill.mining, 8) & self.has(Ore.gold) & self.has(Loot.solar_essence) & self.has(Loot.void_essence), + Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Craftable.rain_totem), + AnimalProduct.milk: self.has_animal(Animal.cow), + Craftable.monster_musk: self.has_prismatic_jelly_reward_access() & self.has(Loot.slime) & self.has(Loot.bat_wing), + Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods), + "Muscle Remedy": self.region.can_reach(Region.hospital) & self.money.can_spend(1000), + Fish.mussel: self.tool.can_forage(Generic.any, Region.beach) or self.has(Fish.mussel_node), + Fish.mussel_node: self.region.can_reach(Region.island_west), + WaterItem.nautilus_shell: self.tool.can_forage(Season.winter, Region.beach), + ArtisanGood.oak_resin: self.has(Machine.tapper), + Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), + Machine.oil_maker: self.skill.has_farming_level(8) & self.has(Loot.slime) & self.has(Material.hardwood) & self.has(MetalBar.gold), + Craftable.oil_of_garlic: (self.skill.has_level(Skill.combat, 6) & self.has(Vegetable.garlic) & self.has(Ingredient.oil)) | (self.money.can_spend_at(Region.mines_dwarf_shop, 3000)), + Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_do_panning() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.buildings.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), + Animal.ostrich: self.buildings.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), + AnimalProduct.ostrich_egg: self.tool.can_forage(Generic.any, Region.island_north, True), + Machine.ostrich_incubator: self.received("Ostrich Incubator Recipe") & self.has(Fossil.bone_fragment) & self.has(Material.hardwood) & self.has(Material.cinder_shard), + Fish.oyster: self.tool.can_forage(Generic.any, Region.beach), + ArtisanGood.pale_ale: self.artisan.can_keg(Vegetable.hops), + Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), + Fish.periwinkle: self.skill.can_crab_pot(Region.town), + ArtisanGood.pickles: self.artisan.has_pickle(), + Animal.pig: self.can_buy_animal(Animal.pig), + Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600), + ArtisanGood.pine_tar: self.has(Machine.tapper), + Meal.pizza: self.money.can_spend_at(Region.saloon, 600), + Machine.preserves_jar: self.skill.has_farming_level(4) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.coal), + Forageable.purple_mushroom: self.tool.can_forage(Generic.any, Region.mines_floor_95) | self.tool.can_forage(Generic.any, Region.skull_cavern_25), + Animal.rabbit: self.can_buy_animal(Animal.rabbit), + AnimalProduct.rabbit_foot: self.has_happy_animal(Animal.rabbit), + MetalBar.radioactive: self.can_smelt(Ore.radioactive), + Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), + Forageable.rainbow_shell: self.tool.can_forage(Season.summer, Region.beach), + Craftable.rain_totem: self.skill.has_level(Skill.foraging, 9) & self.has(Material.hardwood) & self.has(ArtisanGood.truffle_oil) & self.has(ArtisanGood.pine_tar), + Machine.recycling_machine: self.skill.has_level(Skill.fishing, 4) & self.has(Material.wood) & self.has(Material.stone) & self.has(MetalBar.iron), + Forageable.red_mushroom: self.tool.can_forage(Season.summer, Region.secret_woods) | self.tool.can_forage(Season.fall, Region.secret_woods), + MetalBar.quartz: self.can_smelt("Quartz") | self.can_smelt("Fire Quartz") | + (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), + Ingredient.rice: self.money.can_spend_at(Region.pierre_store, 200) | ( + self.buildings.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), + AnimalProduct.roe: self.skill.can_fish() & self.buildings.has_building(Building.fish_pond), + Meal.salad: self.money.can_spend_at(Region.saloon, 220), + # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.emily, 3) & self.has(Forageable.leek) & self.has(Forageable.dandelion) & + # self.has(Ingredient.vinegar)), + Forageable.salmonberry: self.tool.can_forage(Season.spring), + Material.sap: self.ability.can_chop_trees(), + Craftable.scarecrow: self.skill.has_farming_level(1) & self.has(Material.wood) & self.has(Material.coal) & self.has(Material.fiber), + WaterItem.sea_urchin: self.tool.can_forage(Generic.any, Region.tide_pools), + WaterItem.seaweed: (self.skill.can_fish() & self.region.can_reach(Region.beach)) | self.region.can_reach( + Region.tide_pools), + Forageable.secret_note: self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), + Machine.seed_maker: self.skill.has_farming_level(9) & self.has(Material.wood) & self.has(MetalBar.gold) & self.has( + Material.coal), + Animal.sheep: self.can_buy_animal(Animal.sheep), + Fish.shrimp: self.skill.can_crab_pot(Region.beach), + Loot.slime: self.mine.can_mine_in_the_mines_floor_1_40(), + Weapon.any_slingshot: self.received(Weapon.slingshot) | self.received(Weapon.master_slingshot), + Fish.snail: self.skill.can_crab_pot(Region.town), + Forageable.snow_yam: self.tool.can_forage(Season.winter, Region.beach, True), + Trash.soggy_newspaper: self.skill.can_crab_pot(), + Loot.solar_essence: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), + Machine.solar_panel: self.received("Solar Panel Recipe") & self.has(MetalBar.quartz) & self.has( + MetalBar.iron) & self.has(MetalBar.gold), + Meal.spaghetti: self.money.can_spend_at(Region.saloon, 240), + Forageable.spice_berry: self.tool.can_forage(Season.summer), + Forageable.spring_onion: self.tool.can_forage(Season.spring), + AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.squid)), + Craftable.staircase: self.skill.has_level(Skill.mining, 2) & self.has(Material.stone), + Material.stone: self.tool.has_tool(Tool.pickaxe), + Meal.strange_bun: self.relationship.has_hearts(NPC.shane, 7) & self.has(Ingredient.wheat_flour) & self.has(Fish.periwinkle) & self.has(ArtisanGood.void_mayonnaise), + AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.buildings.has_building(Building.fish_pond), + Ingredient.sugar: self.money.can_spend_at(Region.pierre_store, 100) | ( + self.buildings.has_building(Building.mill) & self.has(Vegetable.beet)), + Forageable.sweet_pea: self.tool.can_forage(Season.summer), + Machine.tapper: self.skill.has_level(Skill.foraging, 3) & self.has(Material.wood) & self.has(MetalBar.copper), + Vegetable.tea_leaves: self.has(Sapling.tea) & self.time.has_lived_months(2) & self.season.has_any_not_winter(), + Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), + Trash.trash: self.skill.can_crab_pot(), + Beverage.triple_shot_espresso: self.has("Hot Java Ring"), + ArtisanGood.truffle_oil: self.has(AnimalProduct.truffle) & self.has(Machine.oil_maker), + AnimalProduct.truffle: self.has_animal(Animal.pig) & self.season.has_any_not_winter(), + Ingredient.vinegar: self.money.can_spend_at(Region.pierre_store, 200), + AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), + Loot.void_essence: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern(), + ArtisanGood.void_mayonnaise: (self.region.can_reach(Region.witch_swamp) & self.skill.can_fish()) | (self.has(Machine.mayonnaise_machine) & self.has(AnimalProduct.void_egg)), + Ingredient.wheat_flour: self.money.can_spend_at(Region.pierre_store, 100) | + (self.buildings.has_building(Building.mill) & self.has(Vegetable.wheat)), + WaterItem.white_algae: self.skill.can_fish() & self.region.can_reach(Region.mines_floor_20), + Forageable.wild_horseradish: self.tool.can_forage(Season.spring), + Forageable.wild_plum: self.tool.can_forage(Season.fall), + Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), + ArtisanGood.wine: self.artisan.has_wine(), + Forageable.winter_root: self.tool.can_forage(Season.winter, Region.forest, True), + Material.wood: self.tool.has_tool(Tool.axe), + AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), + Machine.worm_bin: self.skill.has_level(Skill.fishing, 8) & self.has(Material.hardwood) & self.has(MetalBar.gold) & self.has(MetalBar.iron) & self.has(Material.fiber), + }) + self.item_rules.update(self.fish_rules) + self.item_rules.update(self.museum_rules) + self.item_rules.update(self.sapling_rules) + self.item_rules.update(self.tree_fruit_rules) + self.item_rules.update(self.seed_rules) + self.item_rules.update(self.crop_rules) + + # For some recipes, the cooked item can be obtained directly, so we either cook it or get it + for recipe in self.cooking_rules: + cooking_rule = self.cooking_rules[recipe] + obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() + self.item_rules[recipe] = obtention_rule | cooking_rule + + self.buildings.initialize_rules() + self.buildings.update_rules(self.mod.buildings.get_modded_building_rules()) + + self.quest_rules.update({ + Quest.introductions: self.region.can_reach(Region.town), + Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), + Quest.getting_started: self.has(Vegetable.parsnip) & self.tool.has_tool(Tool.hoe) & self.tool.can_water(0), + Quest.to_the_beach: self.region.can_reach(Region.beach), + Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.buildings.has_building(Building.coop), + Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), + Quest.archaeology: (self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish()) & self.region.can_reach(Region.museum), + Quest.meet_the_wizard: self.region.can_reach(Region.town) & self.region.can_reach(Region.community_center) & self.region.can_reach(Region.wizard_tower), + Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), + Quest.smelting: self.has(MetalBar.copper), + Quest.initiation: self.mine.can_mine_in_the_mines_floor_1_40(), + Quest.robins_lost_axe: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.can_meet(NPC.robin), + Quest.jodis_request: self.season.has(Season.spring) & self.has(Vegetable.cauliflower) & self.relationship.can_meet(NPC.jodi), + Quest.mayors_shorts: self.season.has(Season.summer) & self.region.can_reach(Region.ranch) & + (self.relationship.has_hearts(NPC.marnie, 2) | (self.mod.magic.can_blink())) & self.relationship.can_meet(NPC.lewis), + Quest.blackberry_basket: self.season.has(Season.fall) & self.relationship.can_meet(NPC.linus), + Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot) & self.region.can_reach(Region.ranch), + Quest.pam_is_thirsty: self.season.has(Season.summer) & self.has(ArtisanGood.pale_ale) & self.relationship.can_meet(NPC.pam), + Quest.a_dark_reagent: self.season.has(Season.winter) & self.has(Loot.void_essence) & self.relationship.can_meet(NPC.wizard), + Quest.cows_delight: self.season.has(Season.fall) & self.has(Vegetable.amaranth) & self.relationship.can_meet(NPC.marnie), + Quest.the_skull_key: self.received(Wallet.skull_key) & self.region.can_reach(Region.skull_cavern_entrance), + Quest.crop_research: self.season.has(Season.summer) & self.has(Fruit.melon) & self.relationship.can_meet(NPC.demetrius), + Quest.knee_therapy: self.season.has(Season.summer) & self.has(Fruit.hot_pepper) & self.relationship.can_meet(NPC.george), + Quest.robins_request: self.season.has(Season.winter) & self.has(Material.hardwood) & self.relationship.can_meet(NPC.robin), + Quest.qis_challenge: self.mine.can_mine_in_the_skull_cavern(), + Quest.the_mysterious_qi: self.region.can_reach(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.region.can_reach(Region.desert) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), + Quest.carving_pumpkins: self.season.has(Season.fall) & self.has(Vegetable.pumpkin) & self.relationship.can_meet(NPC.caroline), + Quest.a_winter_mystery: self.season.has(Season.winter) & self.region.can_reach(Region.town), + Quest.strange_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.secret_woods) & self.has(ArtisanGood.maple_syrup), + Quest.cryptic_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.skull_cavern_100), + Quest.fresh_fruit: self.season.has(Season.spring) & self.has(Fruit.apricot) & self.relationship.can_meet(NPC.emily), + Quest.aquatic_research: self.season.has(Season.summer) & self.has(Fish.pufferfish) & self.relationship.can_meet(NPC.demetrius), + Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two() & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), + Quest.mayors_need: self.season.has(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.relationship.can_meet(NPC.lewis), + Quest.wanted_lobster: self.season.has(Season.fall) & self.season.has(Season.fall) & self.has(Fish.lobster) & self.relationship.can_meet(NPC.gus), + Quest.pam_needs_juice: self.season.has(Season.fall) & self.has(ArtisanGood.battery_pack) & self.relationship.can_meet(NPC.pam), + Quest.fish_casserole: self.relationship.has_hearts(NPC.jodi, 4) & self.has(Fish.largemouth_bass) & self.region.can_reach(Region.sam_house), + Quest.catch_a_squid: self.season.has(Season.winter) & self.has(Fish.squid) & self.relationship.can_meet(NPC.willy), + Quest.fish_stew: self.season.has(Season.winter) & self.has(Fish.albacore) & self.relationship.can_meet(NPC.gus), + Quest.pierres_notice: self.season.has(Season.spring) & self.has("Sashimi") & self.relationship.can_meet(NPC.pierre), + Quest.clints_attempt: self.season.has(Season.winter) & self.has(Mineral.amethyst) & self.relationship.can_meet(NPC.emily), + Quest.a_favor_for_clint: self.season.has(Season.winter) & self.has(MetalBar.iron) & self.relationship.can_meet(NPC.clint), + Quest.staff_of_power: self.season.has(Season.winter) & self.has(MetalBar.iridium) & self.relationship.can_meet(NPC.wizard), + Quest.grannys_gift: self.season.has(Season.spring) & self.has(Forageable.leek) & self.relationship.can_meet(NPC.evelyn), + Quest.exotic_spirits: self.season.has(Season.winter) & self.has(Forageable.coconut) & self.relationship.can_meet(NPC.gus), + Quest.catch_a_lingcod: self.season.has(Season.winter) & self.has("Lingcod") & self.relationship.can_meet(NPC.willy), + Quest.dark_talisman: self.wallet.has_rusty_key() & self.region.can_reach(Region.railroad) & self.relationship.can_meet(NPC.krobus) & self.region.can_reach(Region.mutant_bug_lair), + Quest.goblin_problem: self.region.can_reach(Region.witch_swamp) & self.has(ArtisanGood.void_mayonnaise), + Quest.magic_ink: self.region.can_reach(Region.witch_hut) & self.relationship.can_meet(NPC.wizard), + Quest.the_pirates_wife: self.region.can_reach(Region.island_west) & self.relationship.can_meet(NPC.kent) & + self.relationship.can_meet(NPC.gus) & self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & + self.relationship.can_meet(NPC.wizard) & self.relationship.can_meet(NPC.willy), + }) + + self.quest_rules.update(self.mod.quests.get_modded_quest_rules()) + + self.festival_rules.update({ + FestivalCheck.egg_hunt: self.season.has(Season.spring) & self.region.can_reach(Region.town) & self.can_win_egg_hunt(), + FestivalCheck.strawberry_seeds: self.season.has(Season.spring) & self.region.can_reach(Region.town) & self.money.can_spend(1000), + FestivalCheck.dance: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.has_hearts(Generic.bachelor, 4), + FestivalCheck.rarecrow_5: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.money.can_spend(2500), + FestivalCheck.luau_soup: self.season.has(Season.summer) & self.region.can_reach(Region.beach) & self.can_succeed_luau_soup(), + FestivalCheck.moonlight_jellies: self.season.has(Season.summer) & self.region.can_reach(Region.beach), + FestivalCheck.smashing_stone: self.season.has(Season.fall) & self.region.can_reach(Region.town), + FestivalCheck.grange_display: self.season.has(Season.fall) & self.region.can_reach(Region.town) & self.can_succeed_grange_display(), + FestivalCheck.rarecrow_1: self.season.has(Season.fall) & self.region.can_reach(Region.town), # only cost star tokens + FestivalCheck.fair_stardrop: self.season.has(Season.fall) & self.region.can_reach(Region.town), # only cost star tokens + FestivalCheck.spirit_eve_maze: self.season.has(Season.fall) & self.region.can_reach(Region.town), + FestivalCheck.rarecrow_2: self.season.has(Season.fall) & self.region.can_reach(Region.town) & self.money.can_spend(5000), + FestivalCheck.fishing_competition: self.season.has(Season.winter) & self.region.can_reach(Region.forest) & self.can_win_fishing_competition(), + FestivalCheck.rarecrow_4: self.season.has(Season.winter) & self.region.can_reach(Region.forest) & self.money.can_spend(5000), + FestivalCheck.mermaid_pearl: self.season.has(Season.winter) & self.region.can_reach(Region.beach), + FestivalCheck.cone_hat: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(2500), + FestivalCheck.iridium_fireplace: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(15000), + FestivalCheck.rarecrow_7: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_find_museum_artifacts(20), + FestivalCheck.rarecrow_8: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_find_museum_items(40), + FestivalCheck.lupini_red_eagle: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), + FestivalCheck.lupini_portrait_mermaid: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), + FestivalCheck.lupini_solar_kingdom: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), + FestivalCheck.lupini_clouds: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_two() & self.money.can_spend(1200), + FestivalCheck.lupini_1000_years: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_two() & self.money.can_spend(1200), + FestivalCheck.lupini_three_trees: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_two() & self.money.can_spend(1200), + FestivalCheck.lupini_the_serpent: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_three() & self.money.can_spend(1200), + FestivalCheck.lupini_tropical_fish: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_three() & self.money.can_spend(1200), + FestivalCheck.lupini_land_of_clay: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_three() & self.money.can_spend(1200), + FestivalCheck.secret_santa: self.season.has(Season.winter) & self.region.can_reach(Region.town) & self.gifts.has_any_universal_love(), + FestivalCheck.legend_of_the_winter_star: self.season.has(Season.winter) & self.region.can_reach(Region.town), + FestivalCheck.all_rarecrows: self.region.can_reach(Region.farm) & self.has_all_rarecrows(), + }) + + self.special_order.initialize_rules() + self.special_order.update_rules(self.mod.special_orders.get_modded_special_orders_rules(self.special_order.special_order_rules)) + + def can_complete_quest(self, quest: str) -> StardewRule: + return Has(quest, self.quest_rules) + + def can_buy_seed(self, seed: SeedItem) -> StardewRule: + if self.options[options.Cropsanity] == options.Cropsanity.option_disabled: + item_rule = True_() + else: + item_rule = self.received(seed.name) + season_rule = self.season.has_any(seed.seasons) + region_rule = self.region.can_reach_all(seed.regions) + currency_rule = self.money.can_spend(1000) + if seed.name == Seed.pineapple: + currency_rule = self.has(Forageable.magma_cap) + if seed.name == Seed.taro: + currency_rule = self.has(Fossil.bone_fragment) + return season_rule & region_rule & item_rule & currency_rule + + def can_buy_sapling(self, fruit: str) -> StardewRule: + sapling_prices = {Fruit.apple: 4000, Fruit.apricot: 2000, Fruit.cherry: 3400, Fruit.orange: 4000, + Fruit.peach: 6000, + Fruit.pomegranate: 6000, Fruit.banana: 0, Fruit.mango: 0} + received_sapling = self.received(f"{fruit} Sapling") + if self.options[options.Cropsanity] == options.Cropsanity.option_disabled: + allowed_buy_sapling = True_() + else: + allowed_buy_sapling = received_sapling + can_buy_sapling = self.money.can_spend_at(Region.pierre_store, sapling_prices[fruit]) + if fruit == Fruit.banana: + can_buy_sapling = self.has_island_trader() & self.has(Forageable.dragon_tooth) + elif fruit == Fruit.mango: + can_buy_sapling = self.has_island_trader() & self.has(Fish.mussel_node) + + return allowed_buy_sapling & can_buy_sapling + + def can_catch_fish(self, fish: FishItem) -> StardewRule: + region_rule = self.region.can_reach_any(fish.locations) + season_rule = self.season.has_any(fish.seasons) + if fish.difficulty == -1: + difficulty_rule = self.skill.can_crab_pot() + else: + difficulty_rule = self.skill.can_fish(fish.difficulty) + return region_rule & season_rule & difficulty_rule + + def can_catch_every_fish(self) -> StardewRule: + rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] + for fish in all_fish: + if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true and \ + fish in island_fish: + continue + rules.append(self.can_catch_fish(fish)) + return And(rules) + + def can_smelt(self, item: str) -> StardewRule: + return self.has(Machine.furnace) & self.has(item) + + def has_traveling_merchant(self, tier: int = 1): + traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] + return self.received(traveling_merchant_days, tier) + + def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: + item_rules = [] + highest_quality_yet = 0 + for bundle_item in bundle_requirements: + if bundle_item.item.item_id == -1: + return self.money.can_spend(bundle_item.amount) + else: + item_rules.append(bundle_item.item.name) + if bundle_item.quality > highest_quality_yet: + highest_quality_yet = bundle_item.quality + return self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) + + def can_grow_gold_quality(self, quality: int) -> StardewRule: + if quality <= 0: + return True_() + if quality == 1: + return self.skill.has_farming_level(5) | (self.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( + self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) + if quality == 2: + return self.skill.has_farming_level(10) | (self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( + self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( + self.has_fertilizer(3) & self.skill.has_farming_level(2)) + if quality >= 3: + return self.has_fertilizer(3) & self.skill.has_farming_level(4) + + def has_fertilizer(self, tier: int) -> StardewRule: + if tier <= 0: + return True_() + if tier == 1: + return self.has(Fertilizer.basic) + if tier == 2: + return self.has(Fertilizer.quality) + if tier >= 3: + return self.has(Fertilizer.deluxe) + + def can_complete_field_office(self) -> StardewRule: + field_office = self.region.can_reach(Region.field_office) + professor_snail = self.received("Open Professor Snail Cave") + dig_site = self.region.can_reach(Region.dig_site) + tools = self.tool.has_tool(Tool.pickaxe) & self.tool.has_tool(Tool.hoe) & self.tool.has_tool(Tool.scythe) + leg_and_snake_skull = dig_site + ribs_and_spine = self.region.can_reach(Region.island_south) + skull = self.action.can_open_geode(Geode.golden_coconut) + tail = self.action.can_do_panning() & dig_site + frog = self.region.can_reach(Region.island_east) + bat = self.region.can_reach(Region.volcano_floor_5) + snake_vertebrae = self.region.can_reach(Region.island_west) + return field_office & professor_snail & tools & leg_and_snake_skull & ribs_and_spine & skull & tail & frog & bat & snake_vertebrae + + def can_complete_community_center(self) -> StardewRule: + return (self.region.can_reach_location("Complete Crafts Room") & + self.region.can_reach_location("Complete Pantry") & + self.region.can_reach_location("Complete Fish Tank") & + self.region.can_reach_location("Complete Bulletin Board") & + self.region.can_reach_location("Complete Vault") & + self.region.can_reach_location("Complete Boiler Room")) + + def can_finish_grandpa_evaluation(self) -> StardewRule: + # https://stardewvalleywiki.com/Grandpa + rules_worth_a_point = [self.money.can_have_earned_total(50000), # 50 000g + self.money.can_have_earned_total(100000), # 100 000g + self.money.can_have_earned_total(200000), # 200 000g + self.money.can_have_earned_total(300000), # 300 000g + self.money.can_have_earned_total(500000), # 500 000g + self.money.can_have_earned_total(1000000), # 1 000 000g first point + self.money.can_have_earned_total(1000000), # 1 000 000g second point + self.skill.has_total_level(30), # Total Skills: 30 + self.skill.has_total_level(50), # Total Skills: 50 + # Completing the museum not expected + # Catching every fish not expected + # Shipping every item not expected + self.relationship.can_get_married() & self.buildings.has_house(2), + self.relationship.has_hearts("5", 8), # 5 Friends + self.relationship.has_hearts("10", 8), # 10 friends + self.pet.has_hearts(5), # Max Pet + self.can_complete_community_center(), # Community Center Completion + self.can_complete_community_center(), # CC Ceremony first point + self.can_complete_community_center(), # CC Ceremony second point + self.received(Wallet.skull_key), # Skull Key obtained + self.wallet.has_rusty_key(), # Rusty key not expected + ] + return Count(12, rules_worth_a_point) + + def can_win_egg_hunt(self) -> StardewRule: + number_of_movement_buffs: int = self.options[options.NumberOfMovementBuffs] + if self.options[options.FestivalLocations] == options.FestivalLocations.option_hard or number_of_movement_buffs < 2: + return True_() + return self.received(Buff.movement, number_of_movement_buffs // 2) + + def can_succeed_luau_soup(self) -> StardewRule: + if self.options[options.FestivalLocations] != options.FestivalLocations.option_hard: + return True_() + eligible_fish = [Fish.blobfish, Fish.crimsonfish, "Ice Pip", Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish, + Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, "Super Cucumber"] + fish_rule = [self.has(fish) for fish in eligible_fish] + eligible_kegables = [Fruit.ancient_fruit, Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, + Fruit.melon, Fruit.orange, Fruit.peach, Fruit.pineapple, Fruit.pomegranate, Fruit.rhubarb, + Fruit.starfruit, Fruit.strawberry, Forageable.cactus_fruit, + Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, Vegetable.hops, Vegetable.wheat] + keg_rules = [self.artisan.can_keg(kegable) for kegable in eligible_kegables] + aged_rule = [self.artisan.can_age(rule, "Iridium") for rule in keg_rules] + # There are a few other valid items but I don't feel like coding them all + return Or(fish_rule) | Or(aged_rule) + + def can_succeed_grange_display(self) -> StardewRule: + if self.options[options.FestivalLocations] != options.FestivalLocations.option_hard: + return True_() + animal_rule = self.has_animal(Generic.any) + artisan_rule = self.artisan.can_keg(Generic.any) | self.artisan.can_preserves_jar(Generic.any) + cooking_rule = True_() # Salads at the bar are good enough + fish_rule = self.skill.can_fish(50) + forage_rule = True_() # Hazelnut always available since the grange display is in fall + mineral_rule = self.action.can_open_geode(Generic.any) # More than half the minerals are good enough + good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, + Fruit.pomegranate, + Fruit.strawberry, Fruit.melon, Fruit.rhubarb, Fruit.pineapple, Fruit.ancient_fruit, Fruit.starfruit, ] + fruit_rule = Or([self.has(fruit) for fruit in good_fruits]) + good_vegetables = [Vegetable.amaranth, Vegetable.artichoke, Vegetable.beet, Vegetable.cauliflower, Forageable.fiddlehead_fern, Vegetable.kale, + Vegetable.radish, Vegetable.taro_root, Vegetable.yam, Vegetable.red_cabbage, Vegetable.pumpkin] + vegetable_rule = Or([self.has(vegetable) for vegetable in good_vegetables]) + + return animal_rule & artisan_rule & cooking_rule & fish_rule & \ + forage_rule & fruit_rule & mineral_rule & vegetable_rule + + def can_win_fishing_competition(self) -> StardewRule: + return self.skill.can_fish(60) + + def can_buy_animal(self, animal: str) -> StardewRule: + price = 0 + building = "" + if animal == Animal.chicken: + price = 800 + building = Building.coop + elif animal == Animal.cow: + price = 1500 + building = Building.barn + elif animal == Animal.goat: + price = 4000 + building = Building.big_barn + elif animal == Animal.duck: + price = 1200 + building = Building.big_coop + elif animal == Animal.sheep: + price = 8000 + building = Building.deluxe_barn + elif animal == Animal.rabbit: + price = 8000 + building = Building.deluxe_coop + elif animal == Animal.pig: + price = 16000 + building = Building.deluxe_barn + else: + return True_() + return self.money.can_spend_at(Region.ranch, price) & self.buildings.has_building(building) + + def has_animal(self, animal: str) -> StardewRule: + if animal == Generic.any: + return self.has_any_animal() + elif animal == Building.coop: + return self.has_any_coop_animal() + elif animal == Building.barn: + return self.has_any_barn_animal() + return self.has(animal) + + def has_happy_animal(self, animal: str) -> StardewRule: + return self.has_animal(animal) & self.has(Forageable.hay) + + def has_any_animal(self) -> StardewRule: + return self.has_any_coop_animal() | self.has_any_barn_animal() + + def has_any_coop_animal(self) -> StardewRule: + coop_rule = Or([self.has_animal(coop_animal) for coop_animal in coop_animals]) + return coop_rule + + def has_any_barn_animal(self) -> StardewRule: + barn_rule = Or([self.has_animal(barn_animal) for barn_animal in barn_animals]) + return barn_rule + + def has_island_trader(self) -> StardewRule: + if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + return False_() + return self.region.can_reach(Region.island_trader) + + def has_walnut(self, number: int) -> StardewRule: + if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + return False_() + if number <= 0: + return True_() + # https://stardewcommunitywiki.com/Golden_Walnut#Walnut_Locations + reach_south = self.region.can_reach(Region.island_south) + reach_north = self.region.can_reach(Region.island_north) + reach_west = self.region.can_reach(Region.island_west) + reach_hut = self.region.can_reach(Region.leo_hut) + reach_southeast = self.region.can_reach(Region.island_south_east) + reach_pirate_cove = self.region.can_reach(Region.pirate_cove) + reach_outside_areas = And(reach_south, reach_north, reach_west, reach_hut) + reach_volcano_regions = [self.region.can_reach(Region.volcano), + self.region.can_reach(Region.volcano_secret_beach), + self.region.can_reach(Region.volcano_floor_5), + self.region.can_reach(Region.volcano_floor_10)] + reach_volcano = Or(reach_volcano_regions) + reach_all_volcano = And(reach_volcano_regions) + reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano] + reach_caves = And(self.region.can_reach(Region.qi_walnut_room), self.region.can_reach(Region.dig_site), + self.region.can_reach(Region.gourmand_frog_cave), + self.region.can_reach(Region.colored_crystals_cave), + self.region.can_reach(Region.shipwreck), self.has(Weapon.any_slingshot)) + reach_entire_island = And(reach_outside_areas, reach_all_volcano, + reach_caves, reach_southeast, reach_pirate_cove) + if number <= 5: + return Or(reach_south, reach_north, reach_west, reach_volcano) + if number <= 10: + return Count(2, reach_walnut_regions) + if number <= 15: + return Count(3, reach_walnut_regions) + if number <= 20: + return And(reach_walnut_regions) + if number <= 50: + return reach_entire_island + gems = [Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz] + return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ + self.ability.can_fish_perfectly() & self.has(Craftable.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) + + def has_everything(self, all_progression_items: Set[str]) -> StardewRule: + all_regions = [region.name for region in vanilla_regions] + rules = self.received(all_progression_items, len(all_progression_items)) & \ + self.region.can_reach_all(all_regions) + return rules + + def has_prismatic_jelly_reward_access(self) -> StardewRule: + if self.options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_disabled: + return self.special_order.can_complete_special_order("Prismatic Jelly") + return self.received("Monster Musk Recipe") + + def has_all_rarecrows(self) -> StardewRule: + rules = [] + for rarecrow_number in range(1, 9): + rules.append(self.received(f"Rarecrow #{rarecrow_number}")) + return And(rules) + diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py new file mode 100644 index 000000000000..85685d4278e5 --- /dev/null +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -0,0 +1,128 @@ +from .combat_logic import CombatLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .skill_logic import SkillLogic +from .tool_logic import ToolLogic +from .. import options +from ..mods.logic.elevator_logic import ModElevatorLogic +from ..stardew_rule import StardewRule, And, True_ +from ..strings.performance_names import Performance +from ..strings.region_names import Region +from ..strings.skill_names import Skill +from ..strings.tool_names import Tool, ToolMaterial + + +class MineLogic: + player: int + tool_option = int + skill_option = int + elevator_option = int + received: ReceivedLogic + region: RegionLogic + combat: CombatLogic + tool: ToolLogic + skill: SkillLogic + mod_elevator: ModElevatorLogic + + def __init__(self, player: int, tool_option: int, skill_option: int, elevator_option: int, received: ReceivedLogic, region: RegionLogic, + combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): + self.player = player + self.tool_option = tool_option + self.skill_option = skill_option + self.elevator_option = elevator_option + self.received = received + self.region = region + self.combat = combat + self.tool = tool + self.skill = skill + + def set_modded_elevator(self, mod_elevator: ModElevatorLogic): + self.mod_elevator = mod_elevator + + # Regions + def can_mine_in_the_mines_floor_1_40(self) -> StardewRule: + return self.region.can_reach(Region.mines_floor_5) + + def can_mine_in_the_mines_floor_41_80(self) -> StardewRule: + return self.region.can_reach(Region.mines_floor_45) + + def can_mine_in_the_mines_floor_81_120(self) -> StardewRule: + return self.region.can_reach(Region.mines_floor_85) + + def can_mine_in_the_skull_cavern(self) -> StardewRule: + return (self.can_progress_in_the_mines_from_floor(120) & + self.region.can_reach(Region.skull_cavern)) + + def get_weapon_rule_for_floor_tier(self, tier: int): + if tier >= 4: + return self.combat.can_fight_at_level(Performance.galaxy) + if tier >= 3: + return self.combat.can_fight_at_level(Performance.great) + if tier >= 2: + return self.combat.can_fight_at_level(Performance.good) + if tier >= 1: + return self.combat.can_fight_at_level(Performance.decent) + return self.combat.can_fight_at_level(Performance.basic) + + def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: + tier = int(floor / 40) + rules = [] + weapon_rule = self.get_weapon_rule_for_floor_tier(tier) + rules.append(weapon_rule) + if self.tool_option == options.ToolProgression.option_progressive: + rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) + if self.skill_option == options.SkillProgression.option_progressive: + combat_tier = min(10, max(0, tier * 2)) + rules.append(self.skill.has_level(Skill.combat, combat_tier)) + return And(rules) + + def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule: + tier = int(floor / 40) + 1 + rules = [] + weapon_rule = self.get_weapon_rule_for_floor_tier(tier) + rules.append(weapon_rule) + if self.tool_option == options.ToolProgression.option_progressive: + rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) + if self.skill_option == options.SkillProgression.option_progressive: + combat_tier = min(10, max(0, tier * 2)) + rules.append(self.skill.has_level(Skill.combat, combat_tier)) + return And(rules) + + def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: + if self.elevator_option != options.ElevatorProgression.option_vanilla: + return self.received("Progressive Mine Elevator", int(floor / 5)) + return True_() + + def can_mine_to_floor(self, floor: int) -> StardewRule: + previous_elevator = max(floor - 5, 0) + previous_previous_elevator = max(floor - 10, 0) + return ((self.has_mine_elevator_to_floor(previous_elevator) & + self.can_progress_in_the_mines_from_floor(previous_elevator)) | + (self.has_mine_elevator_to_floor(previous_previous_elevator) & + self.can_progress_easily_in_the_mines_from_floor(previous_previous_elevator))) + + def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: + tier = floor // 50 + rules = [] + weapon_rule = self.combat.has_great_weapon() + rules.append(weapon_rule) + if self.tool_option == options.ToolProgression.option_progressive: + rules.append(self.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) + if self.skill_option == options.SkillProgression.option_progressive: + skill_tier = min(10, max(0, tier * 2 + 6)) + rules.extend({self.skill.has_level(Skill.combat, skill_tier), + self.skill.has_level(Skill.mining, skill_tier)}) + return And(rules) + + def can_progress_easily_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: + return self.can_progress_in_the_skull_cavern_from_floor(floor + 50) + + def can_mine_to_skull_cavern_floor(self, floor: int) -> StardewRule: + previous_elevator = max(floor - 25, 0) + previous_previous_elevator = max(floor - 50, 0) + has_mine_elevator = self.has_mine_elevator_to_floor(5) # Skull Cavern Elevator menu needs a normal elevator... + return ((self.mod_elevator.has_skull_cavern_elevator_to_floor(previous_elevator) & + self.can_progress_in_the_skull_cavern_from_floor(previous_elevator)) | + (self.mod_elevator.has_skull_cavern_elevator_to_floor(previous_previous_elevator) & + self.can_progress_easily_in_the_skull_cavern_from_floor(previous_previous_elevator))) & has_mine_elevator + diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py new file mode 100644 index 000000000000..aaff12e2e0f8 --- /dev/null +++ b/worlds/stardew_valley/logic/money_logic.py @@ -0,0 +1,36 @@ +from typing import Iterable + +from .region_logic import RegionLogic +from .time_logic import TimeLogic +from ..stardew_rule import StardewRule, And, Or, Reach, Count, True_ + +MONEY_PER_MONTH = 15000 +DISPOSABLE_INCOME_DIVISOR = 5 + + +class MoneyLogic: + player: int + starting_money_option: int + region: RegionLogic + time: TimeLogic + + def __init__(self, player: int, starting_money_option: int, region: RegionLogic, time: TimeLogic): + self.player = player + self.starting_money_option = starting_money_option + self.region = region + self.time = time + + def can_have_earned_total(self, amount: int) -> StardewRule: + if self.starting_money_option == -1: + return True_() + return self.time.has_lived_months(amount // MONEY_PER_MONTH) + + def can_spend(self, amount: int) -> StardewRule: + if self.starting_money_option == -1: + return True_() + return self.time.has_lived_months(amount // (MONEY_PER_MONTH // DISPOSABLE_INCOME_DIVISOR)) + + def can_spend_at(self, region: str, amount: int) -> StardewRule: + return self.region.can_reach(region) & self.can_spend(amount) + + diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py new file mode 100644 index 000000000000..0720340d1844 --- /dev/null +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -0,0 +1,30 @@ +from .combat_logic import CombatLogic +from .region_logic import RegionLogic +from .time_logic import TimeLogic +from .. import StardewOptions +from ..data.monster_data import StardewMonster +from ..stardew_rule import StardewRule + + +class MonsterLogic: + player: int + options: StardewOptions + region: RegionLogic + time: TimeLogic + combat: CombatLogic + + def __init__(self, player: int, options: StardewOptions, region: RegionLogic, time: TimeLogic, combat: CombatLogic): + self.player = player + self.options: options + self.region = region + self.time = time + self.combat = combat + + def can_kill(self, monster: StardewMonster, amount_tier: int = 0) -> StardewRule: + region_rule = self.region.can_reach_any(monster.locations) + combat_rule = self.combat.can_fight_at_level(monster.difficulty) + if amount_tier <= 0: + amount_tier = 0 + time_rule = self.time.has_lived_months(amount_tier * 2) + return region_rule & combat_rule & time_rule + diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py new file mode 100644 index 000000000000..0d525ec758f9 --- /dev/null +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -0,0 +1,70 @@ +from typing import List + +from .action_logic import ActionLogic +from .has_logic import HasLogic +from .. import options +from ..data.museum_data import MuseumItem, all_museum_items, all_artifact_items +from ..stardew_rule import StardewRule, And, False_, Count +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from ..strings.region_names import Region + + +class MuseumLogic: + player: int + museum_option: int + received = ReceivedLogic + has: HasLogic + region: RegionLogic + action: ActionLogic + + def __init__(self, player: int, museum_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic): + self.player = player + self.museum_option = museum_option + self.received = received + self.has = has + self.region = region + self.action = action + + def can_find_museum_item(self, item: MuseumItem) -> StardewRule: + region_rule = self.region.can_reach_all_except_one(item.locations) + geodes_rule = And([self.action.can_open_geode(geode) for geode in item.geodes]) + # monster_rule = self.can_farm_monster(item.monsters) + # extra_rule = True_() + pan_rule = False_() + if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": + pan_rule = self.action.can_do_panning() + return pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule + + def can_find_museum_artifacts(self, number: int) -> StardewRule: + rules = [] + for donation in all_museum_items: + if donation in all_artifact_items: + rules.append(self.can_find_museum_item(donation)) + + return Count(number, rules) + + def can_find_museum_items(self, number: int) -> StardewRule: + rules = [] + for donation in all_museum_items: + rules.append(self.can_find_museum_item(donation)) + + return Count(number, rules) + + def can_complete_museum(self) -> StardewRule: + rules = [] + + if self.museum_option != options.Museumsanity.option_none: + rules.append(self.received("Traveling Merchant Metal Detector", 4)) + + for donation in all_museum_items: + rules.append(self.can_find_museum_item(donation)) + return And(rules) & self.region.can_reach(Region.museum) + + def can_donate(self, item: str) -> StardewRule: + return self.has(item) & self.region.can_reach(Region.museum) + + def can_donate_many(self, items: List[str], amount: int = -1) -> StardewRule: + if amount <= -1: + amount = len(items) + return self.has(items, amount) & self.region.can_reach(Region.museum) diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py new file mode 100644 index 000000000000..409f36856814 --- /dev/null +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -0,0 +1,63 @@ +import math + +from typing import Union + +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .time_logic import TimeLogic +from .tool_logic import ToolLogic +from .. import options +from ..data.villagers_data import Villager +from ..stardew_rule import StardewRule, True_ +from ..strings.region_names import Region +from ..strings.villager_names import NPC + + +class PetLogic: + player: int + friendsanity_option: int + heart_size_option: int + received: ReceivedLogic + region: RegionLogic + time: TimeLogic + tool: ToolLogic + + def __init__(self, player: int, friendsanity_option: int, heart_size_option: int, received_logic: ReceivedLogic, region: RegionLogic, + time: TimeLogic, tool: ToolLogic): + self.player = player + self.friendsanity_option = friendsanity_option + self.heart_size_option = heart_size_option + self.received = received_logic + self.region = region + self.time = time + self.tool = tool + + def has_hearts(self, hearts: int = 1) -> StardewRule: + if hearts <= 0: + return True_() + if self.friendsanity_option == options.Friendsanity.option_none or self.friendsanity_option == options.Friendsanity.option_bachelors: + return self.can_befriend_pet(hearts) + return self.received_hearts(NPC.pet, hearts) + + def received_hearts(self, npc: Union[str, Villager], hearts: int) -> StardewRule: + if isinstance(npc, Villager): + return self.received_hearts(npc.name, hearts) + return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) + + def can_befriend_pet(self, hearts: int): + if hearts <= 0: + return True_() + points = hearts * 200 + points_per_month = 12 * 14 + points_per_water_month = 18 * 14 + farm_rule = self.region.can_reach(Region.farm) + time_with_water_rule = self.tool.can_water(0) & self.time.has_lived_months(points // points_per_water_month) + time_without_water_rule = self.time.has_lived_months(points // points_per_month) + time_rule = time_with_water_rule | time_without_water_rule + return farm_rule & time_rule + + def heart(self, npc: Union[str, Villager]) -> str: + if isinstance(npc, str): + return f"{npc} <3" + return self.heart(npc.name) + diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py new file mode 100644 index 000000000000..71c81edf0137 --- /dev/null +++ b/worlds/stardew_valley/logic/received_logic.py @@ -0,0 +1,32 @@ +from typing import Iterable, Union, Optional + +from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived + + +class ReceivedLogic: + player: int + + def __init__(self, player: int): + self.player = player + + def __call__(self, *args, **kwargs) -> StardewRule: + count = 1 + if len(args) >= 2: + count = args[1] + return self.received(args[0], count) + + def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: + if count <= 0 or not items: + return True_() + + if isinstance(items, str): + return Received(items, self.player, count) + + if count is None: + return And(self.received(item) for item in items) + + if count == 1: + return Or(self.received(item) for item in items) + + return TotalReceived(count, items, self.player) + diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py new file mode 100644 index 000000000000..938563e8575e --- /dev/null +++ b/worlds/stardew_valley/logic/region_logic.py @@ -0,0 +1,32 @@ +from typing import Iterable + +from ..stardew_rule import StardewRule, And, Or, Reach, Count + + +class RegionLogic: + player: int + + def __init__(self, player: int): + self.player = player + + def can_reach(self, spot: str) -> StardewRule: + return Reach(spot, "Region", self.player) + + def can_reach_any(self, spots: Iterable[str]) -> StardewRule: + return Or(self.can_reach(spot) for spot in spots) + + def can_reach_all(self, spots: Iterable[str]) -> StardewRule: + return And(self.can_reach(spot) for spot in spots) + + def can_reach_all_except_one(self, spots: Iterable[str]) -> StardewRule: + num_required = len(list(spots)) - 1 + if num_required <= 0: + num_required = len(list(spots)) + return Count(num_required, [self.can_reach(spot) for spot in spots]) + + def can_reach_location(self, spot: str) -> StardewRule: + return Reach(spot, "Location", self.player) + + def can_reach_entrance(self, spot: str) -> StardewRule: + return Reach(spot, "Entrance", self.player) + diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py new file mode 100644 index 000000000000..7b1da6b01bba --- /dev/null +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -0,0 +1,159 @@ +import math + +from typing import Iterable, Union + +from .building_logic import BuildingLogic +from .gift_logic import GiftLogic +from .has_logic import HasLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .season_logic import SeasonLogic +from .time_logic import TimeLogic +from .. import options +from ..data.villagers_data import all_villagers_by_name, Villager +from ..stardew_rule import StardewRule, True_, And, Or, Count +from ..strings.generic_names import Generic +from ..strings.gift_names import Gift +from ..strings.villager_names import NPC + + +class RelationshipLogic: + player: int + friendsanity_option: int + heart_size_option: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + time: TimeLogic + season: SeasonLogic + gifts: GiftLogic + buildings: BuildingLogic + mods_option: Iterable[str] + + def __init__(self, player: int, friendsanity_option: int, heart_size_option: int, received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, + time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Iterable[str]): + self.player = player + self.friendsanity_option = friendsanity_option + self.heart_size_option = heart_size_option + self.received = received_logic + self.has = has + self.region = region + self.time = time + self.season = season + self.gifts = gifts + self.buildings = buildings + self.mods_option = mods_option + + def can_get_married(self) -> StardewRule: + return self.has_hearts(Generic.bachelor, 10) & self.has(Gift.mermaid_pendant) + + def has_children(self, number_children: int) -> StardewRule: + if number_children <= 0: + return True_() + possible_kids = ["Cute Baby", "Ugly Baby"] + return self.received(possible_kids, number_children) & self.buildings.has_house(2) + + def can_reproduce(self, number_children: int = 1) -> StardewRule: + if number_children <= 0: + return True_() + return self.can_get_married() & self.buildings.has_house(2) & self.has_hearts(Generic.bachelor, 12) & self.has_children(number_children - 1) + + def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: + if hearts <= 0: + return True_() + if self.friendsanity_option == options.Friendsanity.option_none: + return self.can_earn_relationship(npc, hearts) + if npc not in all_villagers_by_name: + if npc == Generic.any or npc == Generic.bachelor: + possible_friends = [] + for name in all_villagers_by_name: + if not self.npc_is_in_current_slot(name): + continue + if npc == Generic.any or all_villagers_by_name[name].bachelor: + possible_friends.append(self.has_hearts(name, hearts)) + return Or(possible_friends) + if npc == Generic.all: + mandatory_friends = [] + for name in all_villagers_by_name: + if not self.npc_is_in_current_slot(name): + continue + mandatory_friends.append(self.has_hearts(name, hearts)) + return And(mandatory_friends) + if npc.isnumeric(): + possible_friends = [] + for name in all_villagers_by_name: + if not self.npc_is_in_current_slot(name): + continue + possible_friends.append(self.has_hearts(name, hearts)) + return Count(int(npc), possible_friends) + return self.can_earn_relationship(npc, hearts) + + if not self.npc_is_in_current_slot(npc): + return True_() + villager = all_villagers_by_name[npc] + if self.friendsanity_option == options.Friendsanity.option_bachelors and not villager.bachelor: + return self.can_earn_relationship(npc, hearts) + if self.friendsanity_option == options.Friendsanity.option_starting_npcs and not villager.available: + return self.can_earn_relationship(npc, hearts) + if self.friendsanity_option != options.Friendsanity.option_all_with_marriage and villager.bachelor and hearts > 8: + return self.received_hearts(villager, 8) & self.can_earn_relationship(npc, hearts) + return self.received_hearts(villager, hearts) + + def received_hearts(self, npc: Union[str, Villager], hearts: int) -> StardewRule: + if isinstance(npc, Villager): + return self.received_hearts(npc.name, hearts) + return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) + + def can_meet(self, npc: str) -> StardewRule: + if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): + return True_() + villager = all_villagers_by_name[npc] + rules = [self.region.can_reach_any(villager.locations)] + if npc == NPC.kent: + rules.append(self.time.has_year_two()) + + return And(rules) + + def can_give_loved_gifts_to_everyone(self) -> StardewRule: + rules = [] + gift_rule = self.gifts.has_any_universal_love() + for npc in all_villagers_by_name: + if not self.npc_is_in_current_slot(npc): + continue + meet_rule = self.can_meet(npc) + rules.append(meet_rule & gift_rule) + loved_gifts_rules = And(rules) + simplified_rules = loved_gifts_rules.simplify() + return simplified_rules + + def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: + if hearts <= 0: + return True_() + + previous_heart = hearts - self.heart_size_option + previous_heart_rule = self.has_hearts(npc, previous_heart) + + # if npc == NPC.wizard and ModNames.magic in self.options[options.Mods]: + # earn_rule = self.can_meet(npc) & self.time.has_lived_months(hearts) + if npc in all_villagers_by_name: + if not self.npc_is_in_current_slot(npc): + return previous_heart_rule + villager = all_villagers_by_name[npc] + rule_if_birthday = self.season.has(villager.birthday) & self.time.has_lived_months(hearts // 2) + rule_if_not_birthday = self.time.has_lived_months(hearts) + earn_rule = self.can_meet(npc) & (rule_if_birthday | rule_if_not_birthday) + else: + earn_rule = self.time.has_lived_months(min(hearts // 2, 8)) + + return previous_heart_rule & earn_rule + + def npc_is_in_current_slot(self, name: str) -> bool: + npc = all_villagers_by_name[name] + mod = npc.mod_name + return mod is None or mod in self.mods_option + + def heart(self, npc: Union[str, Villager]) -> str: + if isinstance(npc, str): + return f"{npc} <3" + return self.heart(npc.name) + diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py new file mode 100644 index 000000000000..2f1b73b03bd2 --- /dev/null +++ b/worlds/stardew_valley/logic/season_logic.py @@ -0,0 +1,47 @@ +from typing import Iterable + +from .received_logic import ReceivedLogic +from .time_logic import TimeLogic +from .. import options +from ..stardew_rule import StardewRule, True_, And, Or +from ..strings.generic_names import Generic +from ..strings.season_names import Season + + +class SeasonLogic: + player: int + season_option: int + received: ReceivedLogic + time: TimeLogic + + def __init__(self, player: int, season_option: int, received_logic: ReceivedLogic, time: TimeLogic): + self.player = player + self.season_option = season_option + self.received = received_logic + self.time = time + + def has(self, season: str) -> StardewRule: + if season == Generic.any: + return True_() + seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] + if self.season_option == options.SeasonRandomization.option_progressive: + return self.received(Season.progressive, seasons_order.index(season)) + if self.season_option == options.SeasonRandomization.option_disabled: + if season == Season.spring: + return True_() + return self.time.has_lived_months(1) + return self.received(season) + + def has_any(self, seasons: Iterable[str]): + if not seasons: + return True_() + return Or([self.has(season) for season in seasons]) + + def has_any_not_winter(self): + return self.has_any([Season.spring, Season.summer, Season.fall]) + + def has_all(self, seasons: Iterable[str]): + if not seasons: + return True_() + return And([self.has(season) for season in seasons]) + diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py new file mode 100644 index 000000000000..fc1b872d2869 --- /dev/null +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -0,0 +1,165 @@ +from typing import Iterable + +from .combat_logic import CombatLogic +from .crop_logic import CropLogic +from .has_logic import HasLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .season_logic import SeasonLogic +from .time_logic import TimeLogic +from .tool_logic import ToolLogic +from .. import options +from ..data import all_crops +from ..mods.logic.magic_logic import MagicLogic +from ..mods.logic.mod_skills_levels import get_mod_skill_levels +from ..stardew_rule import StardewRule, True_, Or +from ..strings.craftable_names import Craftable +from ..strings.generic_names import Generic +from ..strings.machine_names import Machine +from ..strings.performance_names import Performance +from ..strings.region_names import Region +from ..strings.skill_names import Skill +from ..strings.tool_names import ToolMaterial, Tool + +fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] + + +class SkillLogic: + player: int + skill_option: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + season: SeasonLogic + time: TimeLogic + tool: ToolLogic + combat: CombatLogic + crop: CropLogic + magic: MagicLogic + mods: Iterable[str] + + def __init__(self, player: int, skill_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, + tool: ToolLogic, combat: CombatLogic, crop: CropLogic): + self.player = player + self.skill_option = skill_option + self.received = received + self.has = has + self.region = region + self.season = season + self.time = time + self.tool = tool + self.combat = combat + self.crop = crop + + def set_mod_logic(self, magic: MagicLogic, mods: Iterable[str]): + self.magic = magic + self.mods = mods + + def can_earn_level(self, skill: str, level: int) -> StardewRule: + if level <= 0: + return True_() + + tool_level = (level - 1) // 2 + tool_material = ToolMaterial.tiers[tool_level] + months = max(1, level - 1) + months_rule = self.time.has_lived_months(months) + previous_level_rule = self.has_level(skill, level - 1) + + if skill == Skill.fishing: + xp_rule = self.can_get_fishing_xp() & self.tool.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) + elif skill == Skill.farming: + xp_rule = self.can_get_farming_xp() & self.tool.has_tool(Tool.hoe, tool_material) & self.tool.can_water(tool_level) + elif skill == Skill.foraging: + xp_rule = self.can_get_foraging_xp() & \ + (self.tool.has_tool(Tool.axe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level)) + elif skill == Skill.mining: + xp_rule = self.can_get_mining_xp() & \ + (self.tool.has_tool(Tool.pickaxe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level)) + elif skill == Skill.combat: + combat_tier = Performance.tiers[tool_level] + xp_rule = self.can_get_combat_xp() & self.combat.can_fight_at_level(combat_tier) + else: + raise Exception(f"Unknown skill: {skill}") + + return previous_level_rule & months_rule & xp_rule + + def has_level(self, skill: str, level: int) -> StardewRule: + if level <= 0: + return True_() + + if self.skill_option == options.SkillProgression.option_progressive: + return self.received(f"{skill} Level", level) + + return self.can_earn_level(skill, level) + + def has_farming_level(self, level: int) -> StardewRule: + return self.has_level(Skill.farming, level) + + def has_total_level(self, level: int, allow_modded_skills: bool = False) -> StardewRule: + if level <= 0: + return True_() + + if self.skill_option == options.SkillProgression.option_progressive: + skills_items = ["Farming Level", "Mining Level", "Foraging Level", + "Fishing Level", "Combat Level"] + if allow_modded_skills: + skills_items.extend(get_mod_skill_levels(self.mods)) + return self.received(skills_items, level) + + months_with_4_skills = max(1, (level // 4) - 1) + months_with_5_skills = max(1, (level // 5) - 1) + rule_with_fishing = self.time.has_lived_months(months_with_5_skills) & self.can_get_fishing_xp() + if level > 40: + return rule_with_fishing + return self.time.has_lived_months(months_with_4_skills) | rule_with_fishing + + def can_get_farming_xp(self) -> StardewRule: + crop_rules = [] + for crop in all_crops: + crop_rules.append(self.crop.can_grow(crop)) + return Or(crop_rules) + + def can_get_foraging_xp(self) -> StardewRule: + tool_rule = self.tool.has_tool(Tool.axe) + tree_rule = self.region.can_reach(Region.forest) & self.season.has_any_not_winter() + stump_rule = self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.copper) + return tool_rule & (tree_rule | stump_rule) + + def can_get_mining_xp(self) -> StardewRule: + tool_rule = self.tool.has_tool(Tool.pickaxe) + stone_rule = self.region.can_reach_any([Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5]) + return tool_rule & stone_rule + + def can_get_combat_xp(self) -> StardewRule: + tool_rule = self.combat.has_any_weapon() + enemy_rule = self.region.can_reach_any([Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5]) + return tool_rule & enemy_rule + + def can_get_fishing_xp(self) -> StardewRule: + if self.skill_option == options.SkillProgression.option_progressive: + return self.can_fish() | self.can_crab_pot() + + return self.can_fish() + + def can_fish(self, difficulty: int = 0) -> StardewRule: + skill_required = max(0, int((difficulty / 10) - 1)) + if difficulty <= 40: + skill_required = 0 + skill_rule = self.has_level(Skill.fishing, skill_required) + region_rule = self.region.can_reach_any(fishing_regions) + number_fishing_rod_required = 1 if difficulty < 50 else 2 + return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule + + def can_crab_pot(self, region: str = Generic.any) -> StardewRule: + crab_pot_rule = self.has(Craftable.bait) + if self.skill_option == options.SkillProgression.option_progressive: + crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) + else: + crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp() + + if region != Generic.any: + return crab_pot_rule & self.region.can_reach(region) + + water_region_rules = self.region.can_reach_any(fishing_regions) + return crab_pot_rule & water_region_rules + diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py new file mode 100644 index 000000000000..e405377252bc --- /dev/null +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -0,0 +1,123 @@ +from typing import Dict + +from .ability_logic import AbilityLogic +from .arcade_logic import ArcadeLogic +from .artisan_logic import ArtisanLogic +from .cooking_logic import CookingLogic +from .has_logic import HasLogic +from .mine_logic import MineLogic +from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .relationship_logic import RelationshipLogic +from .season_logic import SeasonLogic +from .skill_logic import SkillLogic +from .time_logic import TimeLogic +from ..stardew_rule import StardewRule, Has +from ..strings.animal_product_names import AnimalProduct +from ..strings.ap_names.transport_names import Transportation +from ..strings.artisan_good_names import ArtisanGood +from ..strings.crop_names import Vegetable, Fruit +from ..strings.fertilizer_names import Fertilizer +from ..strings.fish_names import Fish +from ..strings.forageable_names import Forageable +from ..strings.machine_names import Machine +from ..strings.material_names import Material +from ..strings.metal_names import Mineral +from ..strings.monster_drop_names import Loot +from ..strings.region_names import Region +from ..strings.season_names import Season +from ..strings.special_order_names import SpecialOrder +from ..strings.villager_names import NPC + + +class SpecialOrderLogic: + player: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + season: SeasonLogic + time: TimeLogic + money: MoneyLogic + arcade: ArcadeLogic + artisan: ArtisanLogic + relationship: RelationshipLogic + skill: SkillLogic + mine: MineLogic + cooking: CookingLogic + ability: AbilityLogic + special_order_rules: Dict[str, StardewRule] + + def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, skill: SkillLogic, mine: MineLogic, cooking: CookingLogic, + ability: AbilityLogic): + self.player = player + self.received = received + self.has = has + self.region = region + self.season = season + self.time = time + self.money = money + self.arcade = arcade + self.artisan = artisan + self.relationship = relationship + self.skill = skill + self.mine = mine + self.cooking = cooking + self.ability = ability + self.special_order_rules = dict() + + def initialize_rules(self): + self.special_order_rules.update({ + SpecialOrder.island_ingredients: self.has_island_transport() & self.ability.can_farm_perfectly() & + self.has(Vegetable.taro_root) & self.has(Fruit.pineapple) & self.has(Forageable.ginger), + SpecialOrder.cave_patrol: self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(120), + SpecialOrder.aquatic_overpopulation: self.ability.can_fish_perfectly(), + SpecialOrder.biome_balance: self.ability.can_fish_perfectly(), + SpecialOrder.rock_rejuivenation: self.has(Mineral.ruby) & self.has(Mineral.topaz) & self.has(Mineral.emerald) & + self.has(Mineral.jade) & self.has(Mineral.amethyst) & self.relationship.has_hearts(NPC.emily, 4) & + self.has(ArtisanGood.cloth) & self.region.can_reach(Region.haley_house), + SpecialOrder.gifts_for_george: self.season.has(Season.spring) & self.has(Forageable.leek), + SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.dig_site), + SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), + SpecialOrder.crop_order: self.ability.can_farm_perfectly(), + SpecialOrder.community_cleanup: self.skill.can_crab_pot(), + SpecialOrder.the_strong_stuff: self.artisan.can_keg(Vegetable.potato), + SpecialOrder.pierres_prime_produce: self.ability.can_farm_perfectly(), + SpecialOrder.robins_project: self.ability.can_chop_perfectly() & self.has(Material.hardwood), + SpecialOrder.robins_resource_rush: self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), + SpecialOrder.juicy_bugs_wanted_yum: self.has(Loot.bug_meat), + SpecialOrder.tropical_fish: self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), + SpecialOrder.a_curious_substance: self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), + SpecialOrder.prismatic_jelly: self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(40), + SpecialOrder.qis_crop: self.ability.can_farm_perfectly() & self.region.can_reach(Region.greenhouse) & + self.region.can_reach(Region.island_west) & self.skill.has_total_level(50) & + self.has(Machine.seed_maker), + SpecialOrder.lets_play_a_game: self.arcade.has_junimo_kart_max_level(), + SpecialOrder.four_precious_stones: self.time.has_lived_max_months() & self.has("Prismatic Shard") & + self.ability.can_mine_perfectly_in_the_skull_cavern(), + SpecialOrder.qis_hungry_challenge: self.ability.can_mine_perfectly_in_the_skull_cavern() & self.ability.has_max_buffs(), + SpecialOrder.qis_cuisine: self.cooking.can_cook() & ( + self.money.can_spend_at(Region.saloon, 205000) | self.money.can_spend_at(Region.pierre_store, 170000)), + SpecialOrder.qis_kindness: self.relationship.can_give_loved_gifts_to_everyone(), + SpecialOrder.extended_family: self.ability.can_fish_perfectly() & self.has(Fish.angler) & self.has(Fish.glacierfish) & + self.has(Fish.crimsonfish) & self.has(Fish.mutant_carp) & self.has(Fish.legend), + SpecialOrder.danger_in_the_deep: self.ability.can_mine_perfectly() & self.mine.has_mine_elevator_to_floor(120), + SpecialOrder.skull_cavern_invasion: self.ability.can_mine_perfectly_in_the_skull_cavern() & self.ability.has_max_buffs(), + SpecialOrder.qis_prismatic_grange: self.has(Loot.bug_meat) & # 100 Bug Meat + self.money.can_spend_at(Region.saloon, 24000) & # 100 Spaghetti + self.money.can_spend_at(Region.blacksmith, 15000) & # 100 Copper Ore + self.money.can_spend_at(Region.ranch, 5000) & # 100 Hay + self.money.can_spend_at(Region.saloon, 22000) & # 100 Salads + self.money.can_spend_at(Region.saloon, 7500) & # 100 Joja Cola + self.money.can_spend(80000), # I need this extra rule because money rules aren't additive... + }) + + def update_rules(self, new_rules: Dict[str, StardewRule]): + self.special_order_rules.update(new_rules) + + def can_complete_special_order(self, special_order: str) -> StardewRule: + return Has(special_order, self.special_order_rules) + + def has_island_transport(self) -> StardewRule: + return self.received(Transportation.island_obelisk) | self.received(Transportation.boat_repair) diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py new file mode 100644 index 000000000000..e72871fb7b80 --- /dev/null +++ b/worlds/stardew_valley/logic/time_logic.py @@ -0,0 +1,27 @@ +from .received_logic import ReceivedLogic +from ..stardew_rule import StardewRule + +MAX_MONTHS = 12 + + +class TimeLogic: + player: int + received: ReceivedLogic + + def __init__(self, player: int, received_logic: ReceivedLogic): + self.player = player + self.received = received_logic + + def has_lived_months(self, number: int) -> StardewRule: + number = max(0, min(number, MAX_MONTHS)) + return self.received("Month End", number) + + def has_lived_max_months(self) -> StardewRule: + return self.has_lived_months(MAX_MONTHS) + + def has_year_two(self) -> StardewRule: + return self.has_lived_months(4) + + def has_year_three(self) -> StardewRule: + return self.has_lived_months(8) + diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py new file mode 100644 index 000000000000..634bfcbb20de --- /dev/null +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -0,0 +1,83 @@ +from .has_logic import HasLogic +from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .season_logic import SeasonLogic +from .. import options +from ..mods.logic.magic_logic import MagicLogic +from ..stardew_rule import StardewRule, True_ +from ..strings.region_names import Region +from ..strings.skill_names import ModSkill +from ..strings.spells import MagicSpell +from ..strings.tool_names import ToolMaterial, Tool + + +tool_materials = { + ToolMaterial.copper: 1, + ToolMaterial.iron: 2, + ToolMaterial.gold: 3, + ToolMaterial.iridium: 4 +} + +tool_upgrade_prices = { + ToolMaterial.copper: 2000, + ToolMaterial.iron: 5000, + ToolMaterial.gold: 10000, + ToolMaterial.iridium: 25000 +} + + +class ToolLogic: + player: int + tool_option = int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + season: SeasonLogic + money: MoneyLogic + magic: MagicLogic + + def __init__(self, player: int, tool_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + season: SeasonLogic, money: MoneyLogic): + self.player = player + self.tool_option = tool_option + self.received = received + self.has = has + self.region = region + self.season = season + self.money = money + + def set_magic(self, magic: MagicLogic): + self.magic = magic + + def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: + if material == ToolMaterial.basic or tool == Tool.scythe: + return True_() + + if self.tool_option == options.ToolProgression.option_progressive: + return self.received(f"Progressive {tool}", tool_materials[material]) + + return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) + + def has_fishing_rod(self, level: int) -> StardewRule: + if self.tool_option == options.ToolProgression.option_progressive: + return self.received(f"Progressive {Tool.fishing_rod}", level) + + if level <= 1: + return self.region.can_reach(Region.beach) + prices = {2: 500, 3: 1800, 4: 7500} + level = min(level, 4) + return self.money.can_spend_at(Region.fish_shop, prices[level]) + + def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: + season_rule = self.season.has(season) + region_rule = self.region.can_reach(region) + if need_hoe: + return season_rule & region_rule & self.has_tool(Tool.hoe) + return season_rule & region_rule + + def can_water(self, level: int) -> StardewRule: + tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) + spell_rule = self.received(MagicSpell.water) & self.magic.can_use_altar() & self.received(f"{ModSkill.magic} Level", level) + return tool_rule | spell_rule + diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py new file mode 100644 index 000000000000..77a1b769229c --- /dev/null +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -0,0 +1,28 @@ +from .museum_logic import MuseumLogic +from .. import options +from ..data.museum_data import dwarf_scrolls, all_museum_items +from ..stardew_rule import StardewRule +from .received_logic import ReceivedLogic +from ..strings.wallet_item_names import Wallet + + +class WalletLogic: + player: int + received = ReceivedLogic + museum: MuseumLogic + + def __init__(self, player: int, received: ReceivedLogic, museum: MuseumLogic): + self.player = player + self.received = received + self.museum = museum + + def can_speak_dwarf(self) -> StardewRule: + if self.museum.museum_option == options.Museumsanity.option_none: + return self.museum.can_donate_many([item.name for item in dwarf_scrolls]) + return self.received("Dwarvish Translation Guide") + + def has_rusty_key(self) -> StardewRule: + if self.museum.museum_option == options.Museumsanity.option_none: + required_donations = 80 # It's 60, but without a metal detector I'd rather overshoot so players don't get screwed by RNG + return self.museum.can_donate_many([item.name for item in all_museum_items], required_donations) + return self.received(Wallet.rusty_key) diff --git a/worlds/stardew_valley/mods/logic/buildings.py b/worlds/stardew_valley/mods/logic/buildings.py deleted file mode 100644 index 5ca4bf32d785..000000000000 --- a/worlds/stardew_valley/mods/logic/buildings.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union - -from ...strings.artisan_good_names import ArtisanGood -from ...strings.building_names import ModBuilding -from ..mod_data import ModNames -from ...strings.metal_names import MetalBar -from ...strings.region_names import Region - - -def get_modded_building_rules(vanilla_logic, active_mods): - buildings = {} - if ModNames.tractor in active_mods: - buildings.update({ - ModBuilding.tractor_garage: vanilla_logic.can_spend_money_at(Region.carpenter, 150000) & vanilla_logic.has(MetalBar.iron) & - vanilla_logic.has(MetalBar.iridium) & vanilla_logic.has(ArtisanGood.battery_pack)}) - return buildings diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py new file mode 100644 index 000000000000..41ce810eb269 --- /dev/null +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -0,0 +1,29 @@ +from typing import Iterable + +from ...logic.has_logic import HasLogic +from ...logic.money_logic import MoneyLogic +from ...strings.artisan_good_names import ArtisanGood +from ...strings.building_names import ModBuilding +from ..mod_data import ModNames +from ...strings.metal_names import MetalBar +from ...strings.region_names import Region + + +class ModBuildingLogic: + player: int + has: HasLogic + money: MoneyLogic + mods_option: Iterable[str] + + def __init__(self, player: int, has: HasLogic, money: MoneyLogic, mods_option: Iterable[str]): + self.player = player + self.has = has + self.money = money + self.mods_option = mods_option + + def get_modded_building_rules(self): + buildings = {} + if ModNames.tractor in self.mods_option: + tractor_rule = self.money.can_spend_at(Region.carpenter, 150000) & self.has(MetalBar.iron) & self.has(MetalBar.iridium) & self.has(ArtisanGood.battery_pack) + buildings.update({ModBuilding.tractor_garage: tractor_rule}) + return buildings diff --git a/worlds/stardew_valley/mods/logic/deepwoods.py b/worlds/stardew_valley/mods/logic/deepwoods.py deleted file mode 100644 index 2aa90e5b76b6..000000000000 --- a/worlds/stardew_valley/mods/logic/deepwoods.py +++ /dev/null @@ -1,35 +0,0 @@ -from ...strings.craftable_names import Craftable -from ...strings.performance_names import Performance -from ...strings.skill_names import Skill -from ...strings.tool_names import Tool, ToolMaterial -from ...strings.ap_names.transport_names import ModTransportation -from ...stardew_rule import StardewRule, True_, And -from ... import options - - -def can_reach_woods_depth(vanilla_logic, depth: int) -> StardewRule: - tier = int(depth / 25) + 1 - rules = [] - if depth > 10: - rules.append(vanilla_logic.has(Craftable.bomb) | vanilla_logic.has_tool(Tool.axe, ToolMaterial.iridium)) - if depth > 30: - rules.append(vanilla_logic.received(ModTransportation.woods_obelisk)) - if depth > 50: - rules.append(vanilla_logic.can_do_combat_at_level(Performance.great) & vanilla_logic.can_cook() & - vanilla_logic.received(ModTransportation.woods_obelisk)) - if vanilla_logic.options.skill_progression == options.SkillProgression.option_progressive: - combat_tier = min(10, max(0, tier + 5)) - rules.append(vanilla_logic.has_skill_level(Skill.combat, combat_tier)) - return And(rules) - - -def has_woods_rune_to_depth(vanilla_logic, floor: int) -> StardewRule: - if vanilla_logic.options.elevator_progression == options.ElevatorProgression.option_vanilla: - return True_() - return vanilla_logic.received("Progressive Woods Obelisk Sigils", count=int(floor / 10)) - - -def can_chop_to_depth(vanilla_logic, floor: int) -> StardewRule: - previous_elevator = max(floor - 10, 0) - return (has_woods_rune_to_depth(vanilla_logic, previous_elevator) & - can_reach_woods_depth(vanilla_logic, previous_elevator)) diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py new file mode 100644 index 000000000000..cf3379bdeba9 --- /dev/null +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -0,0 +1,62 @@ +from ...logic.combat_logic import CombatLogic +from ...logic.cooking_logic import CookingLogic +from ...logic.has_logic import HasLogic +from ...logic.received_logic import ReceivedLogic +from ...logic.skill_logic import SkillLogic +from ...logic.tool_logic import ToolLogic +from ...strings.craftable_names import Craftable +from ...strings.performance_names import Performance +from ...strings.skill_names import Skill +from ...strings.tool_names import Tool, ToolMaterial +from ...strings.ap_names.transport_names import ModTransportation +from ...stardew_rule import StardewRule, True_, And +from ... import options + + +class DeepWoodsLogic: + player: int + skill_option: int + elevator_option: int + received: ReceivedLogic + has: HasLogic + combat: CombatLogic + tool: ToolLogic + skill: SkillLogic + cooking: CookingLogic + + def __init__(self, player: int, skill_option: int, elevator_option: int, received: ReceivedLogic, has: HasLogic, combat: CombatLogic, tool: ToolLogic, + skill: SkillLogic, cooking: CookingLogic): + self.player = player + self.skill_option = skill_option + self.elevator_option = elevator_option + self.received = received + self.has = has + self.combat = combat + self.tool = tool + self.skill = skill + self.cooking = cooking + + def can_reach_woods_depth(self, depth: int) -> StardewRule: + tier = int(depth / 25) + 1 + rules = [] + if depth > 10: + rules.append(self.has(Craftable.bomb) | self.tool.has_tool(Tool.axe, ToolMaterial.iridium)) + if depth > 30: + rules.append(self.received(ModTransportation.woods_obelisk)) + if depth > 50: + rules.append(self.combat.can_fight_at_level(Performance.great) & self.cooking.can_cook() & + self.received(ModTransportation.woods_obelisk)) + if self.skill_option == options.SkillProgression.option_progressive: + combat_tier = min(10, max(0, tier + 5)) + rules.append(self.skill.has_level(Skill.combat, combat_tier)) + return And(rules) + + def has_woods_rune_to_depth(self, floor: int) -> StardewRule: + if self.elevator_option == options.ElevatorProgression.option_vanilla: + return True_() + return self.received("Progressive Woods Obelisk Sigils", int(floor / 10)) + + def can_chop_to_depth(self, floor: int) -> StardewRule: + previous_elevator = max(floor - 10, 0) + return (self.has_woods_rune_to_depth(previous_elevator) & + self.can_reach_woods_depth(previous_elevator)) diff --git a/worlds/stardew_valley/mods/logic/elevator_logic.py b/worlds/stardew_valley/mods/logic/elevator_logic.py new file mode 100644 index 000000000000..e9d3730be21f --- /dev/null +++ b/worlds/stardew_valley/mods/logic/elevator_logic.py @@ -0,0 +1,24 @@ +from typing import Iterable + +from ...logic.received_logic import ReceivedLogic +from ...stardew_rule import StardewRule, True_ +from ...mods.mod_data import ModNames +from ... import options + + +class ModElevatorLogic: + player: int + elevator_option: int + mods: Iterable[str] + received: ReceivedLogic + + def __init__(self, player: int, elevator_option: int, mods: Iterable[str], received: ReceivedLogic): + self.player = player + self.elevator_option = elevator_option + self.mods = mods + self.received = received + + def has_skull_cavern_elevator_to_floor(self, floor: int) -> StardewRule: + if self.elevator_option != options.ElevatorProgression.option_vanilla and ModNames.skull_cavern_elevator in self.mods: + return self.received("Progressive Skull Cavern Elevator", floor // 25) + return True_() diff --git a/worlds/stardew_valley/mods/logic/magic.py b/worlds/stardew_valley/mods/logic/magic.py deleted file mode 100644 index 709376399c87..000000000000 --- a/worlds/stardew_valley/mods/logic/magic.py +++ /dev/null @@ -1,80 +0,0 @@ -from ...strings.region_names import MagicRegion -from ...mods.mod_data import ModNames -from ...strings.spells import MagicSpell -from ...strings.ap_names.skill_level_names import ModSkillLevel -from ...stardew_rule import Count, StardewRule, False_ -from ... import options - - -def can_use_clear_debris_instead_of_tool_level(vanilla_logic, level: int) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - return vanilla_logic.received(MagicSpell.clear_debris) & can_use_altar(vanilla_logic) & vanilla_logic.received(ModSkillLevel.magic_level, level) - - -def can_use_altar(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - return vanilla_logic.can_reach_region(MagicRegion.altar) - - -def has_any_spell(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - return can_use_altar(vanilla_logic) - - -def has_attack_spell_count(vanilla_logic, count: int) -> StardewRule: - attack_spell_rule = [vanilla_logic.received(MagicSpell.fireball), vanilla_logic.received( - MagicSpell.frostbite), vanilla_logic.received(MagicSpell.shockwave), vanilla_logic.received(MagicSpell.spirit), - vanilla_logic.received(MagicSpell.meteor) - ] - return Count(count, attack_spell_rule) - - -def has_support_spell_count(vanilla_logic, count: int) -> StardewRule: - support_spell_rule = [can_use_altar(vanilla_logic), vanilla_logic.received(ModSkillLevel.magic_level, 2), - vanilla_logic.received(MagicSpell.descend), vanilla_logic.received(MagicSpell.heal), - vanilla_logic.received(MagicSpell.tendrils)] - return Count(count, support_spell_rule) - - -def has_decent_spells(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - magic_resource_rule = can_use_altar(vanilla_logic) & vanilla_logic.received(ModSkillLevel.magic_level, 2) - magic_attack_options_rule = has_attack_spell_count(vanilla_logic, 1) - return magic_resource_rule & magic_attack_options_rule - - -def has_good_spells(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - magic_resource_rule = can_use_altar(vanilla_logic) & vanilla_logic.received(ModSkillLevel.magic_level, 4) - magic_attack_options_rule = has_attack_spell_count(vanilla_logic, 2) - magic_support_options_rule = has_support_spell_count(vanilla_logic, 1) - return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule - - -def has_great_spells(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - magic_resource_rule = can_use_altar(vanilla_logic) & vanilla_logic.received(ModSkillLevel.magic_level, 6) - magic_attack_options_rule = has_attack_spell_count(vanilla_logic, 3) - magic_support_options_rule = has_support_spell_count(vanilla_logic, 1) - return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule - - -def has_amazing_spells(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - magic_resource_rule = can_use_altar(vanilla_logic) & vanilla_logic.received(ModSkillLevel.magic_level, 8) - magic_attack_options_rule = has_attack_spell_count(vanilla_logic, 4) - magic_support_options_rule = has_support_spell_count(vanilla_logic, 2) - return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule - - -def can_blink(vanilla_logic) -> StardewRule: - if ModNames.magic not in vanilla_logic.options.mods: - return False_() - return vanilla_logic.received(MagicSpell.blink) & can_use_altar(vanilla_logic) diff --git a/worlds/stardew_valley/mods/logic/magic_logic.py b/worlds/stardew_valley/mods/logic/magic_logic.py new file mode 100644 index 000000000000..e9f517baa016 --- /dev/null +++ b/worlds/stardew_valley/mods/logic/magic_logic.py @@ -0,0 +1,84 @@ +from typing import Iterable + +from ...logic.received_logic import ReceivedLogic +from ...logic.region_logic import RegionLogic +from ...strings.region_names import MagicRegion +from ...mods.mod_data import ModNames +from ...strings.spells import MagicSpell +from ...strings.ap_names.skill_level_names import ModSkillLevel +from ...stardew_rule import Count, StardewRule, False_ + + +class MagicLogic: + player: int + mods: Iterable[str] + received: ReceivedLogic + region: RegionLogic + + def __init__(self, player: int, mods: Iterable[str], received: ReceivedLogic, region: RegionLogic): + self.player = player + self.mods = mods + self.received = received + self.region = region + + def can_use_clear_debris_instead_of_tool_level(self, level: int) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + return self.received(MagicSpell.clear_debris) & self.can_use_altar() & self.received(ModSkillLevel.magic_level, level) + + def can_use_altar(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + return self.region.can_reach(MagicRegion.altar) + + def has_any_spell(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + return self.can_use_altar() + + def has_attack_spell_count(self, count: int) -> StardewRule: + attack_spell_rule = [self.received(MagicSpell.fireball), self.received(MagicSpell.frostbite), self.received(MagicSpell.shockwave), + self.received(MagicSpell.spirit), self.received(MagicSpell.meteor)] + return Count(count, attack_spell_rule) + + def has_support_spell_count(self, count: int) -> StardewRule: + support_spell_rule = [self.can_use_altar(), self.received(ModSkillLevel.magic_level, 2), + self.received(MagicSpell.descend), self.received(MagicSpell.heal), + self.received(MagicSpell.tendrils)] + return Count(count, support_spell_rule) + + def has_decent_spells(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 2) + magic_attack_options_rule = self.has_attack_spell_count(1) + return magic_resource_rule & magic_attack_options_rule + + def has_good_spells(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 4) + magic_attack_options_rule = self.has_attack_spell_count(2) + magic_support_options_rule = self.has_support_spell_count(1) + return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule + + def has_great_spells(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 6) + magic_attack_options_rule = self.has_attack_spell_count(3) + magic_support_options_rule = self.has_support_spell_count(1) + return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule + + def has_amazing_spells(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 8) + magic_attack_options_rule = self.has_attack_spell_count(4) + magic_support_options_rule = self.has_support_spell_count(2) + return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule + + def can_blink(self) -> StardewRule: + if ModNames.magic not in self.mods: + return False_() + return self.received(MagicSpell.blink) & self.can_use_altar() diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py new file mode 100644 index 000000000000..a5218eded1e5 --- /dev/null +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -0,0 +1,51 @@ +from typing import List, Iterable + +from .buildings_logic import ModBuildingLogic +from .deepwoods_logic import DeepWoodsLogic +from .elevator_logic import ModElevatorLogic +from .magic_logic import MagicLogic +from .quests_logic import QuestLogic +from .skills_logic import ModSkillLogic +from .special_orders_logic import ModSpecialOrderLogic +from ...logic.ability_logic import AbilityLogic +from ...logic.action_logic import ActionLogic +from ...logic.building_logic import BuildingLogic +from ...logic.combat_logic import CombatLogic +from ...logic.cooking_logic import CookingLogic +from ...logic.fishing_logic import FishingLogic +from ...logic.has_logic import HasLogic +from ...logic.mine_logic import MineLogic +from ...logic.money_logic import MoneyLogic +from ...logic.received_logic import ReceivedLogic +from ...logic.region_logic import RegionLogic +from ...logic.relationship_logic import RelationshipLogic +from ...logic.season_logic import SeasonLogic +from ...logic.skill_logic import SkillLogic +from ...logic.tool_logic import ToolLogic +from ...logic.wallet_logic import WalletLogic + + +class ModLogic: + quests: QuestLogic + magic: MagicLogic + buildings: ModBuildingLogic + special_orders: ModSpecialOrderLogic + elevator: ModElevatorLogic + deepwoods: DeepWoodsLogic + skill: ModSkillLogic + + def __init__(self, player: int, skill_option: int, elevator_option: int, mods: Iterable[str], received: ReceivedLogic, has: HasLogic, region: RegionLogic, + action: ActionLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, + combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic): + self.magic = MagicLogic(player, mods, received, region) + self.quests = QuestLogic(mods, has, region, season, relationship) + self.buildings = ModBuildingLogic(player, has, money, mods) + self.special_orders = ModSpecialOrderLogic(player, has, region, relationship, wallet, mods) + self.elevator = ModElevatorLogic(player, elevator_option, mods, received) + self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) + self.skill = ModSkillLogic(player, skill_option, received, has, region, action, relationship, building, tool, fishing, cooking, self.magic, mods) + combat.set_magic(self.magic) + tool.set_magic(self.magic) + ability.set_magic(self.magic, self.skill) + skill.set_mod_logic(self.magic, mods) + mine.set_modded_elevator(self.elevator) diff --git a/worlds/stardew_valley/mods/logic/mod_skills_levels.py b/worlds/stardew_valley/mods/logic/mod_skills_levels.py new file mode 100644 index 000000000000..4ad99f8d4787 --- /dev/null +++ b/worlds/stardew_valley/mods/logic/mod_skills_levels.py @@ -0,0 +1,19 @@ +from typing import List, Iterable +from ...mods.mod_data import ModNames + + +def get_mod_skill_levels(mods: Iterable[str]) -> List[str]: + skills_items = [] + if ModNames.luck_skill in mods: + skills_items.append("Luck Level") + if ModNames.socializing_skill in mods: + skills_items.append("Socializing Level") + if ModNames.magic in mods: + skills_items.append("Magic Level") + if ModNames.archaeology in mods: + skills_items.append("Archaeology Level") + if ModNames.binning_skill in mods: + skills_items.append("Binning Level") + if ModNames.cooking_skill in mods: + skills_items.append("Cooking Level") + return skills_items diff --git a/worlds/stardew_valley/mods/logic/quests.py b/worlds/stardew_valley/mods/logic/quests.py deleted file mode 100644 index f543d4262e44..000000000000 --- a/worlds/stardew_valley/mods/logic/quests.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Union -from ...strings.quest_names import ModQuest -from ..mod_data import ModNames -from ...strings.food_names import Meal, Beverage -from ...strings.monster_drop_names import Loot -from ...strings.villager_names import ModNPC -from ...strings.season_names import Season -from ...strings.region_names import Region - - -def get_modded_quest_rules(vanilla_logic, active_mods): - quests = {} - if ModNames.juna in active_mods: - quests.update({ - ModQuest.JunaCola: vanilla_logic.has_relationship(ModNPC.juna, 3) & vanilla_logic.has(Beverage.joja_cola), - ModQuest.JunaSpaghetti: vanilla_logic.has_relationship(ModNPC.juna, 6) & vanilla_logic.has(Meal.spaghetti) - }) - - if ModNames.ginger in active_mods: - quests.update({ - ModQuest.MrGinger: vanilla_logic.has_relationship(ModNPC.mr_ginger, 6) & vanilla_logic.has(Loot.void_essence) - }) - - if ModNames.ayeisha in active_mods: - quests.update({ - ModQuest.AyeishaEnvelope: vanilla_logic.has_season(Season.spring) | vanilla_logic.has_season(Season.fall), - ModQuest.AyeishaRing: vanilla_logic.has_season(Season.winter) - }) - - return quests diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py new file mode 100644 index 000000000000..8493e5211d8c --- /dev/null +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -0,0 +1,50 @@ +from typing import Iterable, Dict + +from ...logic.has_logic import HasLogic +from ...logic.region_logic import RegionLogic +from ...logic.relationship_logic import RelationshipLogic +from ...logic.season_logic import SeasonLogic +from ...strings.quest_names import ModQuest +from ..mod_data import ModNames +from ...strings.food_names import Meal, Beverage +from ...strings.monster_drop_names import Loot +from ...strings.villager_names import ModNPC +from ...strings.season_names import Season +from ...strings.region_names import Region +from ...stardew_rule import StardewRule + + +class QuestLogic: + mods: Iterable[str] + has: HasLogic + region: RegionLogic + season: SeasonLogic + relationship: RelationshipLogic + + def __init__(self, mods: Iterable[str], has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic): + self.mods = mods + self.has = has + self.region = region + self.season = season + self.relationship = relationship + + def get_modded_quest_rules(self) -> Dict[str, StardewRule]: + quests = {} + if ModNames.juna in self.mods: + quests.update({ + ModQuest.JunaCola: self.relationship.has_hearts(ModNPC.juna, 3) & self.has(Beverage.joja_cola), + ModQuest.JunaSpaghetti: self.relationship.has_hearts(ModNPC.juna, 6) & self.has(Meal.spaghetti) + }) + + if ModNames.ginger in self.mods: + quests.update({ + ModQuest.MrGinger: self.relationship.has_hearts(ModNPC.mr_ginger, 6) & self.has(Loot.void_essence) + }) + + if ModNames.ayeisha in self.mods: + quests.update({ + ModQuest.AyeishaEnvelope: (self.season.has(Season.spring) | self.season.has(Season.fall)) & self.region.can_reach(Region.mountain), + ModQuest.AyeishaRing: self.season.has(Season.winter) & self.region.can_reach(Region.forest) + }) + + return quests diff --git a/worlds/stardew_valley/mods/logic/skills.py b/worlds/stardew_valley/mods/logic/skills.py deleted file mode 100644 index fd8f2f2ad41c..000000000000 --- a/worlds/stardew_valley/mods/logic/skills.py +++ /dev/null @@ -1,92 +0,0 @@ -from typing import List, Union -from . import magic -from ...strings.building_names import Building -from ...strings.geode_names import Geode -from ...strings.region_names import Region -from ...strings.skill_names import ModSkill -from ...strings.spells import MagicSpell -from ...strings.machine_names import Machine -from ...strings.tool_names import Tool, ToolMaterial -from ...mods.mod_data import ModNames -from ...data.villagers_data import all_villagers -from ...stardew_rule import Count, StardewRule, False_, True_ -from ... import options - - -def append_mod_skill_level(skills_items: List[str], active_mods): - if ModNames.luck_skill in active_mods: - skills_items.append("Luck Level") - if ModNames.socializing_skill in active_mods: - skills_items.append("Socializing Level") - if ModNames.magic in active_mods: - skills_items.append("Magic Level") - if ModNames.archaeology in active_mods: - skills_items.append("Archaeology Level") - if ModNames.binning_skill in active_mods: - skills_items.append("Binning Level") - if ModNames.cooking_skill in active_mods: - skills_items.append("Cooking Level") - - -def can_earn_mod_skill_level(logic, skill: str, level: int) -> StardewRule: - if ModNames.luck_skill in logic.options.mods and skill == ModSkill.luck: - return can_earn_luck_skill_level(logic, level) - if ModNames.magic in logic.options.mods and skill == ModSkill.magic: - return can_earn_magic_skill_level(logic, level) - if ModNames.socializing_skill in logic.options.mods and skill == ModSkill.socializing: - return can_earn_socializing_skill_level(logic, level) - if ModNames.archaeology in logic.options.mods and skill == ModSkill.archaeology: - return can_earn_archaeology_skill_level(logic, level) - if ModNames.cooking_skill in logic.options.mods and skill == ModSkill.cooking: - return can_earn_cooking_skill_level(logic, level) - if ModNames.binning_skill in logic.options.mods and skill == ModSkill.binning: - return can_earn_binning_skill_level(logic, level) - return False_() - - -def can_earn_luck_skill_level(vanilla_logic, level: int) -> StardewRule: - if level >= 6: - return vanilla_logic.can_fish_chests() | vanilla_logic.can_open_geode(Geode.magma) - else: - return vanilla_logic.can_fish_chests() | vanilla_logic.can_open_geode(Geode.geode) - - -def can_earn_magic_skill_level(vanilla_logic, level: int) -> StardewRule: - spell_count = [vanilla_logic.received(MagicSpell.clear_debris), vanilla_logic.received(MagicSpell.water), - vanilla_logic.received(MagicSpell.blink), vanilla_logic.received(MagicSpell.fireball), - vanilla_logic.received(MagicSpell.frostbite), - vanilla_logic.received(MagicSpell.descend), vanilla_logic.received(MagicSpell.tendrils), - vanilla_logic.received(MagicSpell.shockwave), - vanilla_logic.received(MagicSpell.meteor), - vanilla_logic.received(MagicSpell.spirit)] - return Count(level, spell_count) - - -def can_earn_socializing_skill_level(vanilla_logic, level: int) -> StardewRule: - villager_count = [] - for villager in all_villagers: - if villager.mod_name in vanilla_logic.options.mods or villager.mod_name is None: - villager_count.append(vanilla_logic.can_earn_relationship(villager.name, level)) - return Count(level * 2, villager_count) - - -def can_earn_archaeology_skill_level(vanilla_logic, level: int) -> StardewRule: - if level >= 6: - return vanilla_logic.can_do_panning() | vanilla_logic.has_tool(Tool.hoe, ToolMaterial.gold) - else: - return vanilla_logic.can_do_panning() | vanilla_logic.has_tool(Tool.hoe, ToolMaterial.basic) - - -def can_earn_cooking_skill_level(vanilla_logic, level: int) -> StardewRule: - if level >= 6: - return vanilla_logic.can_cook() & vanilla_logic.can_fish() & vanilla_logic.can_reach_region(Region.saloon) & \ - vanilla_logic.has_building(Building.coop) & vanilla_logic.has_building(Building.barn) - else: - return vanilla_logic.can_cook() - - -def can_earn_binning_skill_level(vanilla_logic, level: int) -> StardewRule: - if level >= 6: - return vanilla_logic.has(Machine.recycling_machine) & (vanilla_logic.can_fish() | vanilla_logic.can_crab_pot()) - else: - return True_() # You can always earn levels 1-5 with trash cans diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py new file mode 100644 index 000000000000..801e5705e3df --- /dev/null +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -0,0 +1,121 @@ +from typing import Iterable +from .magic_logic import MagicLogic +from ... import options +from ...logic.action_logic import ActionLogic +from ...logic.building_logic import BuildingLogic +from ...logic.cooking_logic import CookingLogic +from ...logic.fishing_logic import FishingLogic +from ...logic.has_logic import HasLogic +from ...logic.received_logic import ReceivedLogic +from ...logic.region_logic import RegionLogic +from ...logic.relationship_logic import RelationshipLogic +from ...logic.tool_logic import ToolLogic +from ...strings.building_names import Building +from ...strings.geode_names import Geode +from ...strings.region_names import Region +from ...strings.skill_names import ModSkill +from ...strings.spells import MagicSpell +from ...strings.machine_names import Machine +from ...strings.tool_names import Tool, ToolMaterial +from ...mods.mod_data import ModNames +from ...data.villagers_data import all_villagers +from ...stardew_rule import Count, StardewRule, False_, True_ + + +class ModSkillLogic: + player: int + skill_option: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + action: ActionLogic + relationship: RelationshipLogic + building: BuildingLogic + tool: ToolLogic + fishing: FishingLogic + cooking: CookingLogic + magic: MagicLogic + mods_option: Iterable[str] + + def __init__(self, player: int, skill_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, + relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + magic: MagicLogic, mods_option: Iterable[str]): + self.player = player + self.skill_option = skill_option + self.received = received + self.has = has + self.region = region + self.action = action + self.relationship = relationship + self.building = building + self.tool = tool + self.fishing = fishing + self.cooking = cooking + self.magic = magic + self.mods_option = mods_option + + def has_mod_level(self, skill: str, level: int) -> StardewRule: + if level <= 0: + return True_() + + if self.skill_option == options.SkillProgression.option_progressive: + return self.received(f"{skill} Level", level) + + return self.can_earn_mod_skill_level(skill, level) + + def can_earn_mod_skill_level(self, skill: str, level: int) -> StardewRule: + if ModNames.luck_skill in self.mods_option and skill == ModSkill.luck: + return self.can_earn_luck_skill_level(level) + if ModNames.magic in self.mods_option and skill == ModSkill.magic: + return self.can_earn_magic_skill_level(level) + if ModNames.socializing_skill in self.mods_option and skill == ModSkill.socializing: + return self.can_earn_socializing_skill_level(level) + if ModNames.archaeology in self.mods_option and skill == ModSkill.archaeology: + return self.can_earn_archaeology_skill_level(level) + if ModNames.cooking_skill in self.mods_option and skill == ModSkill.cooking: + return self.can_earn_cooking_skill_level(level) + if ModNames.binning_skill in self.mods_option and skill == ModSkill.binning: + return self.can_earn_binning_skill_level(level) + return False_() + + def can_earn_luck_skill_level(self, level: int) -> StardewRule: + if level >= 6: + return self.fishing.can_fish_chests() | self.action.can_open_geode(Geode.magma) + else: + return self.fishing.can_fish_chests() | self.action.can_open_geode(Geode.geode) + + def can_earn_magic_skill_level(self, level: int) -> StardewRule: + spell_count = [self.received(MagicSpell.clear_debris), self.received(MagicSpell.water), + self.received(MagicSpell.blink), self.received(MagicSpell.fireball), + self.received(MagicSpell.frostbite), + self.received(MagicSpell.descend), self.received(MagicSpell.tendrils), + self.received(MagicSpell.shockwave), + self.received(MagicSpell.meteor), + self.received(MagicSpell.spirit)] + return self.magic.can_use_altar() & Count(level, spell_count) + + def can_earn_socializing_skill_level(self, level: int) -> StardewRule: + villager_count = [] + for villager in all_villagers: + if villager.mod_name in self.mods_option or villager.mod_name is None: + villager_count.append(self.relationship.can_earn_relationship(villager.name, level)) + return Count(level * 2, villager_count) + + def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: + if level >= 6: + return self.action.can_do_panning() | self.tool.has_tool(Tool.hoe, ToolMaterial.gold) + else: + return self.action.can_do_panning() | self.tool.has_tool(Tool.hoe, ToolMaterial.basic) + + def can_earn_cooking_skill_level(self, level: int) -> StardewRule: + if level >= 6: + return self.cooking.can_cook() & self.region.can_reach(Region.saloon) & \ + self.building.has_building(Building.coop) & self.building.has_building(Building.barn) + else: + return self.cooking.can_cook() + + def can_earn_binning_skill_level(self, level: int) -> StardewRule: + if level >= 6: + return self.region.can_reach(Region.town) & self.has(Machine.recycling_machine) + else: + return self.region.can_reach(Region.town) | self.has(Machine.recycling_machine) diff --git a/worlds/stardew_valley/mods/logic/skullcavernelevator.py b/worlds/stardew_valley/mods/logic/skullcavernelevator.py deleted file mode 100644 index fd540e05abee..000000000000 --- a/worlds/stardew_valley/mods/logic/skullcavernelevator.py +++ /dev/null @@ -1,10 +0,0 @@ -from ...stardew_rule import Count, StardewRule, True_ -from ...mods.mod_data import ModNames -from ... import options - - -def has_skull_cavern_elevator_to_floor(logic, floor: int) -> StardewRule: - if logic.options.elevator_progression != options.ElevatorProgression.option_vanilla and \ - ModNames.skull_cavern_elevator in logic.options.mods: - return logic.received("Progressive Skull Cavern Elevator", floor // 25) - return True_() diff --git a/worlds/stardew_valley/mods/logic/special_orders.py b/worlds/stardew_valley/mods/logic/special_orders.py deleted file mode 100644 index 45d5d572dc05..000000000000 --- a/worlds/stardew_valley/mods/logic/special_orders.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union -from ...strings.craftable_names import Craftable -from ...strings.food_names import Meal -from ...strings.material_names import Material -from ...strings.monster_drop_names import Loot -from ...strings.region_names import Region -from ...strings.special_order_names import SpecialOrder, ModSpecialOrder -from ...strings.villager_names import ModNPC -from ..mod_data import ModNames - - -def get_modded_special_orders_rules(vanilla_logic, active_mods): - special_orders = {} - if ModNames.juna in active_mods: - special_orders.update({ - ModSpecialOrder.junas_monster_mash: vanilla_logic.has_relationship(ModNPC.juna, 4) & - vanilla_logic.can_complete_special_order(SpecialOrder.a_curious_substance) & - vanilla_logic.has_rusty_key() & - vanilla_logic.can_reach_region(Region.forest) & vanilla_logic.has(Craftable.monster_musk) & - vanilla_logic.has("Energy Tonic") & vanilla_logic.has(Material.sap) & vanilla_logic.has(Loot.bug_meat) & - vanilla_logic.has(Craftable.oil_of_garlic) & vanilla_logic.has(Meal.strange_bun) - }) - - return special_orders diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py new file mode 100644 index 000000000000..d1ecdca1f057 --- /dev/null +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -0,0 +1,45 @@ +from typing import Iterable + +from ...logic.has_logic import HasLogic +from ...logic.region_logic import RegionLogic +from ...logic.relationship_logic import RelationshipLogic +from ...logic.wallet_logic import WalletLogic +from ...strings.craftable_names import Craftable +from ...strings.food_names import Meal +from ...strings.material_names import Material +from ...strings.monster_drop_names import Loot +from ...strings.region_names import Region +from ...strings.special_order_names import SpecialOrder, ModSpecialOrder +from ...strings.villager_names import ModNPC +from ..mod_data import ModNames + + +class ModSpecialOrderLogic: + player: int + has: HasLogic + region: RegionLogic + relationship: RelationshipLogic + wallet: WalletLogic + mods_option: Iterable[str] + + def __init__(self, player: int, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, wallet: WalletLogic, mods_option: Iterable[str]): + self.player = player + self.has = has + self.region = region + self.relationship = relationship + self.wallet = wallet + self.mods_option = mods_option + + def get_modded_special_orders_rules(self, vanilla_rules): + special_orders = {} + if ModNames.juna in self.mods_option: + special_orders.update({ + ModSpecialOrder.junas_monster_mash: self.relationship.has_hearts(ModNPC.juna, 4) & + vanilla_rules[SpecialOrder.a_curious_substance] & + self.wallet.has_rusty_key() & + self.region.can_reach(Region.forest) & self.has(Craftable.monster_musk) & + self.has("Energy Tonic") & self.has(Material.sap) & self.has(Loot.bug_meat) & + self.has(Craftable.oil_of_garlic) & self.has(Meal.strange_bun) + }) + + return special_orders diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 0d22bfaf3901..595fb91e91ba 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -344,37 +344,6 @@ class Museumsanity(Choice): option_all = 3 -class Friendsanity(Choice): - """Shuffle Friendships? - None: Friendship hearts are earned normally - Bachelors: Hearts with bachelors are shuffled - Starting NPCs: Hearts for NPCs available immediately are checks - All: Hearts for all npcs are checks, including Leo, Kent, Sandy, etc - All With Marriage: Hearts for all npcs are checks, including romance hearts up to 14 when applicable - """ - internal_name = "friendsanity" - display_name = "Friendsanity" - default = 0 - option_none = 0 - # option_marry_one_person = 1 - option_bachelors = 2 - option_starting_npcs = 3 - option_all = 4 - option_all_with_marriage = 5 - - -# Conditional Setting - Friendsanity not None -class FriendsanityHeartSize(Range): - """If using friendsanity, how many hearts are received per heart item, and how many hearts must be earned to send a check - A higher value will lead to fewer heart items in the item pool, reducing bloat""" - internal_name = "friendsanity_heart_size" - display_name = "Friendsanity Heart Size" - range_start = 1 - range_end = 8 - default = 4 - # step = 1 - - class Monstersanity(Choice): """Locations for slaying monsters? None: There are no checks for slaying monsters @@ -429,6 +398,37 @@ class Shipsanity(Choice): option_quality_everything = 10 +class Friendsanity(Choice): + """Shuffle Friendships? + None: Friendship hearts are earned normally + Bachelors: Hearts with bachelors are shuffled + Starting NPCs: Hearts for NPCs available immediately are checks + All: Hearts for all npcs are checks, including Leo, Kent, Sandy, etc + All With Marriage: Hearts for all npcs are checks, including romance hearts up to 14 when applicable + """ + internal_name = "friendsanity" + display_name = "Friendsanity" + default = 0 + option_none = 0 + # option_marry_one_person = 1 + option_bachelors = 2 + option_starting_npcs = 3 + option_all = 4 + option_all_with_marriage = 5 + + +# Conditional Setting - Friendsanity not None +class FriendsanityHeartSize(Range): + """If using friendsanity, how many hearts are received per heart item, and how many hearts must be earned to send a check + A higher value will lead to fewer heart items in the item pool, reducing bloat""" + internal_name = "friendsanity_heart_size" + display_name = "Friendsanity Heart Size" + range_start = 1 + range_end = 8 + default = 4 + # step = 1 + + class NumberOfMovementBuffs(Range): """Number of movement speed buffs to the player that exist as items in the pool. Each movement speed buff is a +25% multiplier that stacks additively""" @@ -609,6 +609,8 @@ class StardewValleyOptions(PerGameCommonOptions): help_wanted_locations: HelpWantedLocations fishsanity: Fishsanity museumsanity: Museumsanity + Monstersanity, + Shipsanity, friendsanity: Friendsanity friendsanity_heart_size: FriendsanityHeartSize movement_buff_number: NumberOfMovementBuffs diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 3766be51bebb..df96ac851f03 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -6,16 +6,16 @@ from .mods.logic.skullcavernelevator import has_skull_cavern_elevator_to_floor from .options import StardewValleyOptions, ToolProgression, BuildingProgression, SkillProgression, ExcludeGingerIsland, Cropsanity, SpecialOrderLocations, Museumsanity, \ BackpackProgression, ArcadeMachineLocations -from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, \ - DeepWoodsEntrance, AlecEntrance, MagicEntrance -from .data.museum_data import all_museum_items, all_museum_minerals, all_museum_artifacts, \ - dwarf_scrolls, skeleton_front, \ - skeleton_middle, skeleton_back, all_museum_items_by_name, Artifact +from .data.monster_data import all_monsters_by_category +from .logic.logic import StardewLogic +from .logic.tool_logic import tool_upgrade_prices +from .stardew_rule import And +from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance +from .data.museum_data import all_museum_items, all_mineral_items, all_artifact_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name +from .strings.performance_names import Performance from .strings.region_names import Region from .mods.mod_data import ModNames -from .mods.logic import magic, deepwoods from .locations import LocationTags, locations_by_tag -from .logic import StardewLogic, And, tool_upgrade_prices from .strings.ap_names.transport_names import Transportation from .strings.artisan_good_names import ArtisanGood from .strings.calendar_names import Weekday @@ -42,44 +42,10 @@ def set_rules(world): set_ginger_island_rules(logic, multiworld, player, world_options) - set_tools_rules(logic, multiworld, player, world_options) - + set_tool_rules(logic, multiworld, player, world_options) set_skills_rules(logic, multiworld, player, world_options) - - # Bundles - for bundle in current_bundles.values(): - location = multiworld.get_location(bundle.get_name_with_bundle(), player) - rules = logic.can_complete_bundle(bundle.requirements, bundle.number_required) - simplified_rules = rules.simplify() - MultiWorldRules.set_rule(location, simplified_rules) - MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), - And(logic.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), - And(logic.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.PANTRY_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), - And(logic.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.FISH_TANK_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), - And(logic.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), - And(logic.can_reach_location(bundle.name) - for bundle - in locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), - And(logic.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.VAULT_BUNDLE]).simplify()) - - # Buildings - if world_options.building_progression != BuildingProgression.option_vanilla: - for building in locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: - if building.mod_name is not None and building.mod_name not in world_options.mods: - continue - MultiWorldRules.set_rule(multiworld.get_location(building.name, player), - logic.building_rules[building.name.replace(" Blueprint", "")].simplify()) - + set_bundle_rules(current_bundles, logic, multiworld, player) + set_building_rules(logic, multiworld, player, world_options) set_cropsanity_rules(all_location_names, logic, multiworld, player, world_options) set_story_quests_rules(all_location_names, logic, multiworld, player, world_options) set_special_order_rules(all_location_names, logic, multiworld, player, world_options) @@ -90,72 +56,129 @@ def set_rules(world): set_backpack_rules(logic, multiworld, player, world_options) set_festival_rules(all_location_names, logic, multiworld, player) + set_monstersanity_rules(all_location_names, logic, multiworld, player) + + set_isolated_locations_rules(logic, multiworld, player) + set_traveling_merchant_rules(logic, multiworld, player) + set_arcade_machine_rules(logic, multiworld, player, world_options) + set_deepwoods_rules(logic, multiworld, player, world_options) + set_magic_spell_rules(logic, multiworld, player, world_options) + + +def set_isolated_locations_rules(logic: StardewLogic,multiworld, player): MultiWorldRules.add_rule(multiworld.get_location("Old Master Cannoli", player), logic.has("Sweet Gem Berry").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Galaxy Sword Shrine", player), logic.has("Prismatic Shard").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Have a Baby", player), - logic.can_reproduce(1).simplify()) + logic.relationship.can_reproduce(1).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Have Another Baby", player), - logic.can_reproduce(2).simplify()) - - set_arcade_machine_rules(logic, multiworld, player, world_options) - set_deepwoods_rules(logic, multiworld, player, world_options) - set_magic_spell_rules(logic, multiworld, player, world_options) + logic.relationship.can_reproduce(2).simplify()) -def set_tools_rules(logic, multiworld, player, world_options): +def set_tool_rules(logic: StardewLogic, multiworld, player, world_options): # Those checks do not exist if ToolProgression is vanilla if world_options.tool_progression == ToolProgression.option_vanilla: return MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), - (logic.has_skill_level(Skill.fishing, 2) & logic.can_spend_money(1800)).simplify()) + (logic.skill.has_level(Skill.fishing, 2) & logic.money.can_spend(1800)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Purchase Iridium Rod", player), - (logic.has_skill_level(Skill.fishing, 6) & logic.can_spend_money(7500)).simplify()) + (logic.skill.has_level(Skill.fishing, 6) & logic.money.can_spend(7500)).simplify()) materials = [None, "Copper", "Iron", "Gold", "Iridium"] - tool = [Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.trash_can] + tool = [Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.watering_can, Tool.trash_can] for (previous, material), tool in itertools.product(zip(materials[:4], materials[1:]), tool): if previous is None: continue tool_upgrade_location = multiworld.get_location(f"{material} {tool} Upgrade", player) - MultiWorldRules.add_rule(tool_upgrade_location, logic.has_tool(tool, previous).simplify()) - - -def set_skills_rules(logic, multiworld, player, world_options): - # Skills - if world_options.skill_progression != SkillProgression.option_vanilla: - for i in range(1, 11): - set_skill_rule(logic, multiworld, player, Skill.farming, i) - set_skill_rule(logic, multiworld, player, Skill.fishing, i) - set_skill_rule(logic, multiworld, player, Skill.foraging, i) - set_skill_rule(logic, multiworld, player, Skill.mining, i) - set_skill_rule(logic, multiworld, player, Skill.combat, i) - - # Modded Skills - if ModNames.luck_skill in world_options.mods: - set_skill_rule(logic, multiworld, player, ModSkill.luck, i) - if ModNames.magic in world_options.mods: - set_skill_rule(logic, multiworld, player, ModSkill.magic, i) - if ModNames.binning_skill in world_options.mods: - set_skill_rule(logic, multiworld, player, ModSkill.binning, i) - if ModNames.cooking_skill in world_options.mods: - set_skill_rule(logic, multiworld, player, ModSkill.cooking, i) - if ModNames.socializing_skill in world_options.mods: - set_skill_rule(logic, multiworld, player, ModSkill.socializing, i) - if ModNames.archaeology in world_options.mods: - set_skill_rule(logic, multiworld, player, ModSkill.archaeology, i) - - -def set_skill_rule(logic, multiworld, player, skill: str, level: int): + MultiWorldRules.set_rule(tool_upgrade_location, logic.has_tool(tool, previous).simplify()) + + +def set_building_rules(logic: StardewLogic, multi_world, player, world_options): + if world_options[options.BuildingProgression] != options.BuildingProgression.option_vanilla: + for building in locations.locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: + if building.mod_name is not None and building.mod_name not in world_options[options.Mods]: + continue + MultiWorldRules.set_rule(multi_world.get_location(building.name, player), + logic.buildings.building_rules[building.name.replace(" Blueprint", "")].simplify()) + + +def set_bundle_rules(current_bundles, logic: StardewLogic, multi_world, player): + for bundle in current_bundles.values(): + location = multiworld.get_location(bundle.get_name_with_bundle(), player) + rules = logic.can_complete_bundle(bundle.requirements, bundle.number_required) + simplified_rules = rules.simplify() + MultiWorldRules.set_rule(location, simplified_rules) + MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), + And(logic.region.can_reach_location(bundle.name) + for bundle in locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), + And(logic.region.can_reach_location(bundle.name) + for bundle in locations_by_tag[LocationTags.PANTRY_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), + And(logic.region.can_reach_location(bundle.name) + for bundle in locations_by_tag[LocationTags.FISH_TANK_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), + And(logic.region.can_reach_location(bundle.name) + for bundle in locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), + And(logic.region.can_reach_location(bundle.name) + for bundle + in locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), + And(logic.region.can_reach_location(bundle.name) + for bundle in locations_by_tag[LocationTags.VAULT_BUNDLE]).simplify()) + + +def set_skills_rules(logic: StardewLogic, multi_world, player, world_options): + mods = world_options[options.Mods] + if world_options[options.SkillProgression] == options.SkillProgression.option_vanilla: + return + for i in range(1, 11): + set_vanilla_skill_rule_for_level(logic, multi_world, player, i) + set_modded_skill_rule_for_level(logic, multi_world, player, mods, i) + + +def set_vanilla_skill_rule_for_level(logic: StardewLogic, multi_world, player, level: int): + set_vanilla_skill_rule(logic, multi_world, player, Skill.farming, level) + set_vanilla_skill_rule(logic, multi_world, player, Skill.fishing, level) + set_vanilla_skill_rule(logic, multi_world, player, Skill.foraging, level) + set_vanilla_skill_rule(logic, multi_world, player, Skill.mining, level) + set_vanilla_skill_rule(logic, multi_world, player, Skill.combat, level) + + +def set_modded_skill_rule_for_level(logic: StardewLogic, multi_world, player, mods, level: int): + if ModNames.luck_skill in mods: + set_modded_skill_rule(logic, multi_world, player, ModSkill.luck, level) + if ModNames.magic in mods: + set_modded_skill_rule(logic, multi_world, player, ModSkill.magic, level) + if ModNames.binning_skill in mods: + set_modded_skill_rule(logic, multi_world, player, ModSkill.binning, level) + if ModNames.cooking_skill in mods: + set_modded_skill_rule(logic, multi_world, player, ModSkill.cooking, level) + if ModNames.socializing_skill in mods: + set_modded_skill_rule(logic, multi_world, player, ModSkill.socializing, level) + if ModNames.archaeology in mods: + set_modded_skill_rule(logic, multi_world, player, ModSkill.archaeology, level) + + +def get_skill_level_location(multi_world, player, skill: str, level: int): location_name = f"Level {level} {skill}" - location = multiworld.get_location(location_name, player) - rule = logic.can_earn_skill_level(skill, level).simplify() - MultiWorldRules.set_rule(location, rule) + return multi_world.get_location(location_name, player) + + +def set_vanilla_skill_rule(logic: StardewLogic, multi_world, player, skill: str, level: int): + rule = logic.skill.can_earn_level(skill, level).simplify() + MultiWorldRules.set_rule(get_skill_level_location(multi_world, player, skill, level), rule.simplify()) + +def set_modded_skill_rule(logic: StardewLogic, multi_world, player, skill: str, level: int): + rule = logic.mod.skill.can_earn_mod_skill_level(skill, level).simplify() + MultiWorldRules.set_rule(get_skill_level_location(multi_world, player, skill, level), rule.simplify()) -def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): + +def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: StardewOptions): set_mines_floor_entrance_rules(logic, multiworld, player) set_skull_cavern_floor_entrance_rules(logic, multiworld, player) set_blacksmith_entrance_rules(logic, multiworld, player) @@ -163,21 +186,21 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp set_traveling_merchant_day_rules(logic, multiworld, player) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), - logic.received("Beach Bridge") | (magic.can_blink(logic)).simplify()) + logic.received("Beach Bridge") | (logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), - logic.received("Bridge Repair") | (magic.can_blink(logic)).simplify()) + logic.received("Bridge Repair") | (logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), - logic.has_tool(Tool.axe, "Iron") | (magic.can_blink(logic)).simplify()) + logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), - logic.has_rusty_key().simplify()) + logic.wallet.has_rusty_key().simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), - logic.has_rusty_key().simplify()) + logic.wallet.has_rusty_key().simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.take_bus_to_desert, player), logic.received("Bus Repair").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_skull_cavern, player), logic.received(Wallet.skull_key).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), - logic.can_speak_dwarf() & logic.has_tool(Tool.pickaxe, ToolMaterial.iron)) + logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.received(Transportation.desert_obelisk).simplify()) @@ -192,38 +215,38 @@ def set_entrance_rules(logic, multiworld, player, world_options: StardewValleyOp MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player), logic.received("Adventurer's Guild")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), - logic.has_lived_months(2)) + logic.time.has_lived_months(2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), - logic.received(Wallet.dark_talisman) | (magic.can_blink(logic)).simplify()) + logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), - (logic.has(ArtisanGood.void_mayonnaise) | magic.can_blink(logic)).simplify()) + (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), - ((logic.has_rusty_key() & logic.can_reach_region(Region.railroad) & - logic.can_meet(NPC.krobus) | magic.can_blink(logic)).simplify())) + ((logic.wallet.has_rusty_key() & logic.region.can_reach(Region.railroad) & + logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()).simplify())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), logic.received("Club Card")) set_festival_entrance_rules(logic, multiworld, player) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), - logic.has_relationship(NPC.harvey, 2)) + logic.relationship.has_hearts(NPC.harvey, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_maru_room, player), - logic.has_relationship(NPC.maru, 2)) + logic.relationship.has_hearts(NPC.maru, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), - (logic.has_relationship(NPC.sebastian, 2) | magic.can_blink(logic)).simplify()) + (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_leah_cottage, player), - logic.has_relationship(NPC.leah, 2)) + logic.relationship.has_hearts(NPC.leah, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_elliott_house, player), - logic.has_relationship(NPC.elliott, 2)) + logic.relationship.has_hearts(NPC.elliott, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sunroom, player), - logic.has_relationship(NPC.caroline, 2)) + logic.relationship.has_hearts(NPC.caroline, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_wizard_basement, player), - logic.has_relationship(NPC.wizard, 4)) + logic.relationship.has_hearts(NPC.wizard, 4)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) if ModNames.alec in world_options.mods: MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), - (logic.has_relationship(ModNPC.alec, 2) | magic.can_blink(logic)).simplify()) + (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) def set_mines_floor_entrance_rules(logic, multiworld, player): @@ -328,16 +351,16 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_qi_walnut_room, player), logic.received("Qi Walnut Room").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_volcano, player), - (logic.can_water(0) | logic.received("Volcano Bridge") | - magic.can_blink(logic)).simplify()) + (logic.tool.can_water(0) | logic.received("Volcano Bridge") | + logic.mod.magic.can_blink()).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.volcano_to_secret_beach, player), - logic.can_water(2).simplify()) + logic.tool.can_water(2).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), - (logic.can_mine_perfectly() & logic.can_water(1)).simplify()) + (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), - logic.can_speak_dwarf()) + logic.wallet.can_speak_dwarf()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), - (logic.can_mine_perfectly() & logic.can_water(1) & logic.received("Volcano Exit Shortcut")).simplify()) + (logic.ability.can_mine_perfectly() & logic.tool.can_water(1) & logic.received("Volcano Exit Shortcut")).simplify()) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_docks_to_dig_site, Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_volcano_to_dig_site, @@ -374,7 +397,7 @@ def set_island_parrot_rules(logic: StardewLogic, multiworld, player): has_10_walnut & logic.received("Island Farmhouse")) MultiWorldRules.add_rule(multiworld.get_location("Volcano Bridge", player), has_5_walnut & logic.received("Island West Turtle") & - logic.can_reach_region(Region.volcano_floor_10)) + logic.region.can_reach(Region.volcano_floor_10)) MultiWorldRules.add_rule(multiworld.get_location("Volcano Exit Shortcut", player), has_5_walnut & logic.received("Island West Turtle")) MultiWorldRules.add_rule(multiworld.get_location("Island Resort", player), @@ -396,10 +419,10 @@ def set_cropsanity_rules(all_location_names: List[str], logic, multiworld, playe logic.has(crop_name).simplify()) -def set_story_quests_rules(all_location_names: List[str], logic, multiworld, player, world_options: StardewValleyOptions): - for quest in locations_by_tag[LocationTags.QUEST]: - if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options.mods): - MultiWorldRules.set_rule(multiworld.get_location(quest.name, player), +def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options: StardewOptions): + for quest in locations.locations_by_tag[LocationTags.QUEST]: + if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options[options.Mods]): + MultiWorldRules.set_rule(multi_world.get_location(quest.name, player), logic.quest_rules[quest.name].simplify()) @@ -407,20 +430,20 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, world_options: StardewValleyOptions): if world_options.special_order_locations == SpecialOrderLocations.option_disabled: return - board_rule = logic.received("Special Order Board") & logic.has_lived_months(4) + board_rule = logic.received("Special Order Board") & logic.time.has_lived_months(4) for board_order in locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD]: if board_order.name in all_location_names: - order_rule = board_rule & logic.special_order_rules[board_order.name] + order_rule = board_rule & logic.special_order.special_order_rules[board_order.name] MultiWorldRules.set_rule(multiworld.get_location(board_order.name, player), order_rule.simplify()) if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return if world_options.special_order_locations == SpecialOrderLocations.option_board_only: return - qi_rule = logic.can_reach_region(Region.qi_walnut_room) & logic.has_lived_months(8) + qi_rule = logic.region.can_reach(Region.qi_walnut_room) & logic.time.has_lived_months(8) for qi_order in locations_by_tag[LocationTags.SPECIAL_ORDER_QI]: if qi_order.name in all_location_names: - order_rule = qi_rule & logic.special_order_rules[qi_order.name] + order_rule = qi_rule & logic.special_order.special_order_rules[qi_order.name] MultiWorldRules.set_rule(multiworld.get_location(qi_order.name, player), order_rule.simplify()) @@ -435,7 +458,7 @@ def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_ help_wanted_number = world_options.help_wanted_locations for i in range(0, help_wanted_number): set_number = i // 7 - month_rule = logic.has_lived_months(set_number).simplify() + month_rule = logic.time.has_lived_months(set_number).simplify() quest_number = set_number + 1 quest_number_in_set = i % 7 if quest_number_in_set < 4: @@ -544,12 +567,12 @@ def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, acce def set_backpack_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if world_options.backpack_progression != BackpackProgression.option_vanilla: MultiWorldRules.set_rule(multiworld.get_location("Large Pack", player), - logic.can_spend_money(2000).simplify()) + logic.money.can_spend(2000).simplify()) MultiWorldRules.set_rule(multiworld.get_location("Deluxe Pack", player), - (logic.can_spend_money(10000) & logic.received("Progressive Backpack")).simplify()) + (logic.money.can_spend(10000) & logic.received("Progressive Backpack")).simplify()) if ModNames.big_backpack in world_options.mods: MultiWorldRules.set_rule(multiworld.get_location("Premium Pack", player), - (logic.can_spend_money(150000) & + (logic.money.can_spend(150000) & logic.received("Progressive Backpack", 2)).simplify()) @@ -563,6 +586,23 @@ def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multi logic.festival_rules[festival.name].simplify()) +def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player): + monstersanity_locations = [] + monstersanity_locations.extend(locations.locations_by_tag[LocationTags.MONSTERSANITY]) + monster_eradication_prefix = "Monster Eradication: " + for location in monstersanity_locations: + if location.name not in all_location_names or not location.name.startswith(monster_eradication_prefix): + continue + # what_to_slay = location.name[len(monster_eradication_prefix):] + # first_word = what_to_slay[what_to_slay.index(" "):] + #if what_to_slay in all_monsters_by_category: + # set_monstersanity_category_rule(what_to_slay) + # continue + #if not first_word.isdigit(): + # set_monstersanity__rules() + # MultiWorldRules.set_rule(multi_world.get_location(location.name, player), logic.festival_rules[location.name].simplify()) + + def set_traveling_merchant_day_rules(logic: StardewLogic, multiworld: MultiWorld, player: int): for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" @@ -606,20 +646,20 @@ def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, m friend_name = friend_location_trimmed[:split_index] num_hearts = int(friend_location_trimmed[split_index + 1:]) MultiWorldRules.set_rule(multiworld.get_location(friend_location.name, player), - logic.can_earn_relationship(friend_name, num_hearts).simplify()) + logic.relationship.can_earn_relationship(friend_name, num_hearts).simplify()) def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.deepwoods in world_options.mods: MultiWorldRules.add_rule(multiworld.get_location("Breaking Up Deep Woods Gingerbread House", player), - logic.has_tool(Tool.axe, "Gold") & deepwoods.can_reach_woods_depth(logic, 50).simplify()) + logic.tool.has_tool(Tool.axe, "Gold") & logic.mod.deepwoods.can_reach_woods_depth(50).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Chop Down a Deep Woods Iridium Tree", player), - logic.has_tool(Tool.axe, "Iridium").simplify()) + logic.tool.has_tool(Tool.axe, "Iridium").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), logic.received("Woods Obelisk").simplify()) for depth in range(10, 100 + 10, 10): MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), - deepwoods.can_chop_to_depth(logic, depth).simplify()) + logic.mod.deepwoods.can_chop_to_depth(depth).simplify()) def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): @@ -627,58 +667,58 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i return MultiWorldRules.set_rule(multiworld.get_entrance(MagicEntrance.store_to_altar, player), - (logic.has_relationship(NPC.wizard, 3) & - logic.can_reach_region(Region.wizard_tower)).simplify()) + (logic.relationship.has_hearts(NPC.wizard, 3) & + logic.region.can_reach(Region.wizard_tower)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Clear Debris", player), - (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic")).simplify()) + (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Till", player), - logic.has_tool("Hoe", "Basic").simplify()) + logic.tool.has_tool("Hoe", "Basic").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Water", player), - logic.has_tool("Watering Can", "Basic").simplify()) + logic.tool.has_tool("Watering Can", "Basic").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Toil School Locations", player), - (logic.has_tool("Watering Can", "Basic") & logic.has_tool("Hoe", "Basic") - & (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic"))).simplify()) + (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") + & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic"))).simplify()) # Do I *want* to add boots into logic when you get them even in vanilla without effort? idk MultiWorldRules.add_rule(multiworld.get_location("Analyze: Evac", player), - logic.can_mine_perfectly().simplify()) + logic.ability.can_mine_perfectly().simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Haste", player), logic.has("Coffee").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Heal", player), logic.has("Life Elixir").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Life School Locations", player), (logic.has("Coffee") & logic.has("Life Elixir") - & logic.can_mine_perfectly()).simplify()) + & logic.ability.can_mine_perfectly()).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Descend", player), - logic.can_reach_region(Region.mines).simplify()) + logic.region.can_reach(Region.mines).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), logic.has("Fire Quartz").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.can_reach_region(Region.mines_floor_60) & logic.can_fish(85)).simplify()) + (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(85)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), - (logic.has("Fire Quartz") & logic.can_reach_region(Region.mines_floor_60) & logic.can_fish(85)).simplify()) + (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(85)).simplify()) # MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player),) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Tendrils", player), - logic.can_reach_region(Region.farm).simplify()) + logic.region.can_reach(Region.farm).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Shockwave", player), logic.has("Earth Crystal").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Nature School Locations", player), - (logic.has("Earth Crystal") & logic.can_reach_region("Farm")).simplify()), + (logic.has("Earth Crystal") & logic.region.can_reach("Farm")).simplify()), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Meteor", player), - (logic.can_reach_region(Region.farm) & logic.has_lived_months(12)).simplify()), + (logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lucksteal", player), - logic.can_reach_region(Region.witch_hut).simplify()) + logic.region.can_reach(Region.witch_hut).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Bloodmana", player), - logic.can_reach_region(Region.mines_floor_100).simplify()) + logic.region.can_reach(Region.mines_floor_100).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Eldritch School Locations", player), - (logic.can_reach_region(Region.witch_hut) & - logic.can_reach_region(Region.mines_floor_100) & - logic.can_reach_region(Region.farm) & logic.has_lived_months(12)).simplify()) + (logic.region.can_reach(Region.witch_hut) & + logic.region.can_reach(Region.mines_floor_100) & + logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze Every Magic School Location", player), - (logic.has_tool("Watering Can", "Basic") & logic.has_tool("Hoe", "Basic") - & (logic.has_tool("Axe", "Basic") | logic.has_tool("Pickaxe", "Basic")) & + (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") + & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & logic.has("Coffee") & logic.has("Life Elixir") - & logic.can_mine_perfectly() & logic.has("Earth Crystal") & - logic.has("Fire Quartz") & logic.can_fish(85) & - logic.can_reach_region(Region.witch_hut) & - logic.can_reach_region(Region.mines_floor_100) & - logic.can_reach_region(Region.farm) & logic.has_lived_months(12)).simplify()) + & logic.ability.can_mine_perfectly() & logic.has("Earth Crystal") & + logic.has("Fire Quartz") & logic.skill.can_fish(85) & + logic.region.can_reach(Region.witch_hut) & + logic.region.can_reach(Region.mines_floor_100) & + logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 7965d05b57be..e175c354ca1e 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -32,9 +32,9 @@ def test_given_item_rule_then_can_be_resolved(self): self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve item rule for {item} {rule}") def test_given_building_rule_then_can_be_resolved(self): - for building in logic.building_rules.keys(): + for building in logic.buildings.building_rules.keys(): with self.subTest(msg=building): - rule = logic.building_rules[building] + rule = logic.buildings.building_rules[building] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve building rule for {building} {rule}") @@ -46,9 +46,9 @@ def test_given_quest_rule_then_can_be_resolved(self): self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve quest rule for {quest} {rule}") def test_given_special_order_rule_then_can_be_resolved(self): - for special_order in logic.special_order_rules.keys(): + for special_order in logic.special_order.special_order_rules.keys(): with self.subTest(msg=special_order): - rule = logic.special_order_rules[special_order] + rule = logic.special_order.special_order_rules[special_order] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve special order rule for {special_order} {rule}") diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index 3f02643b83dc..0bb819f0d7c0 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -1,6 +1,5 @@ import unittest -from .. import True_ -from ..logic import Received, Has, False_, And, Or +from ..stardew_rule import Received, Has, False_, And, Or, True_ class TestSimplification(unittest.TestCase): diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 0749b1a8f153..b25fb9291a66 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -64,34 +64,34 @@ def test_old_master_cannoli(self): self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=True) self.multiworld.state.collect(self.world.create_item("Summer"), event=True) - self.assertFalse(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) fall = self.world.create_item("Fall") self.multiworld.state.collect(fall, event=True) - self.assertFalse(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) tuesday = self.world.create_item("Traveling Merchant: Tuesday") self.multiworld.state.collect(tuesday, event=True) - self.assertFalse(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) rare_seed = self.world.create_item("Rare Seed") self.multiworld.state.collect(rare_seed, event=True) - self.assertTrue(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) self.remove(fall) - self.assertFalse(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) self.remove(tuesday) green_house = self.world.create_item("Greenhouse") self.multiworld.state.collect(green_house, event=True) - self.assertFalse(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) friday = self.world.create_item("Traveling Merchant: Friday") self.multiworld.state.collect(friday, event=True) self.assertTrue(self.multiworld.get_location("Old Master Cannoli", 1).access_rule(self.multiworld.state)) self.remove(green_house) - self.assertFalse(self.world.logic.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) self.remove(friday) @@ -100,7 +100,7 @@ class TestBundlesLogic(SVTestBase): } def test_vault_2500g_bundle(self): - self.assertTrue(self.world.logic.can_reach_location("2,500g Bundle")(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location("2,500g Bundle")(self.multiworld.state)) class TestBuildingLogic(SVTestBase): @@ -109,27 +109,27 @@ class TestBuildingLogic(SVTestBase): } def test_coop_blueprint(self): - self.assertFalse(self.world.logic.can_reach_location("Coop Blueprint")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Coop Blueprint")(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.assertTrue(self.world.logic.can_reach_location("Coop Blueprint")(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location("Coop Blueprint")(self.multiworld.state)) def test_big_coop_blueprint(self): - self.assertFalse(self.world.logic.can_reach_location("Big Coop Blueprint")(self.multiworld.state), + self.assertFalse(self.world.logic.region.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.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.assertFalse(self.world.logic.can_reach_location("Big Coop Blueprint")(self.multiworld.state), + self.assertFalse(self.world.logic.region.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.world.create_item("Progressive Coop"), event=True) - self.assertTrue(self.world.logic.can_reach_location("Big Coop Blueprint")(self.multiworld.state), + self.assertTrue(self.world.logic.region.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_coop_blueprint(self): - self.assertFalse(self.world.logic.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) @@ -138,16 +138,16 @@ def test_deluxe_coop_blueprint(self): self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.assertFalse(self.world.logic.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) + 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.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) + 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.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) def test_big_shed_blueprint(self): - self.assertFalse(self.world.logic.can_reach_location("Big Shed Blueprint")(self.multiworld.state), + self.assertFalse(self.world.logic.region.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.world.create_item("Month End"), event=True) @@ -156,11 +156,11 @@ def test_big_shed_blueprint(self): self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.assertFalse(self.world.logic.can_reach_location("Big Shed Blueprint")(self.multiworld.state), + self.assertFalse(self.world.logic.region.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.world.create_item("Progressive Shed"), event=True) - self.assertTrue(self.world.logic.can_reach_location("Big Shed Blueprint")(self.multiworld.state), + self.assertTrue(self.world.logic.region.can_reach_location("Big Shed Blueprint")(self.multiworld.state), f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}") @@ -170,10 +170,10 @@ class TestArcadeMachinesLogic(SVTestBase): } def test_prairie_king(self): - self.assertFalse(self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)) + 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") @@ -183,19 +183,19 @@ def test_prairie_king(self): self.multiworld.state.collect(boots, event=True) self.multiworld.state.collect(gun, event=True) - self.assertTrue(self.world.logic.can_reach_region("JotPK World 1")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)) + 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.can_reach_region("JotPK World 1")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)) + 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) @@ -203,10 +203,10 @@ def test_prairie_king(self): 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.can_reach_region("JotPK World 1")(self.multiworld.state)) - self.assertTrue(self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)) + 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) @@ -219,10 +219,10 @@ def test_prairie_king(self): 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.can_reach_region("JotPK World 1")(self.multiworld.state)) - self.assertTrue(self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)) - self.assertTrue(self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)) - self.assertFalse(self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)) + 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) @@ -242,10 +242,10 @@ def test_prairie_king(self): 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.can_reach_region("JotPK World 1")(self.multiworld.state)) - self.assertTrue(self.world.logic.can_reach_region("JotPK World 2")(self.multiworld.state)) - self.assertTrue(self.world.logic.can_reach_region("JotPK World 3")(self.multiworld.state)) - self.assertTrue(self.world.logic.can_reach_location("Journey of the Prairie King Victory")(self.multiworld.state)) + 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) @@ -298,29 +298,29 @@ 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: - self.assertTrue(self.world.logic.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)) + self.assertTrue(self.world.logic.mine.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)) else: - self.assertFalse(self.world.logic.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)) + self.assertFalse(self.world.logic.mine.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)) if reachable_level > 1: - self.assertTrue(self.world.logic.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)) + self.assertTrue(self.world.logic.mine.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)) else: - self.assertFalse(self.world.logic.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)) + self.assertFalse(self.world.logic.mine.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)) if reachable_level > 2: - self.assertTrue(self.world.logic.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)) + self.assertTrue(self.world.logic.mine.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)) else: - self.assertFalse(self.world.logic.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)) + self.assertFalse(self.world.logic.mine.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)) if reachable_level > 3: - self.assertTrue(self.world.logic.can_mine_in_the_skull_cavern()(self.multiworld.state)) + self.assertTrue(self.world.logic.mine.can_mine_in_the_skull_cavern()(self.multiworld.state)) else: - self.assertFalse(self.world.logic.can_mine_in_the_skull_cavern()(self.multiworld.state)) + self.assertFalse(self.world.logic.mine.can_mine_in_the_skull_cavern()(self.multiworld.state)) if reachable_level > 4: - self.assertTrue(self.world.logic.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) + self.assertTrue(self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) else: - self.assertFalse(self.world.logic.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) + self.assertFalse(self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) self.remove(item) From 55a16b0ee4090f3f4d55af4d18fbf37b7262fa01 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 6 Aug 2023 18:13:14 -0400 Subject: [PATCH 027/482] - Added monstersanity logic --- worlds/stardew_valley/data/items.csv | 32 +- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/items.py | 2 + worlds/stardew_valley/logic/combat_logic.py | 25 +- worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/regions.py | 25 +- worlds/stardew_valley/rules.py | 430 ++++++++++-------- .../stardew_valley/strings/entrance_names.py | 12 + .../stardew_valley/strings/monster_names.py | 2 +- worlds/stardew_valley/strings/region_names.py | 5 +- worlds/stardew_valley/test/TestRules.py | 24 + 11 files changed, 356 insertions(+), 205 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 3c4ddb84156b..9042f1abb8aa 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -63,22 +63,22 @@ id,name,classification,groups,mod_name 75,Foraging Level,progression,SKILL_LEVEL_UP, 76,Mining Level,progression,SKILL_LEVEL_UP, 77,Combat Level,progression,SKILL_LEVEL_UP, -78,Earth Obelisk,progression,, -79,Water Obelisk,progression,, -80,Desert Obelisk,progression,, -81,Island Obelisk,progression,GINGER_ISLAND, -82,Junimo Hut,useful,, -83,Gold Clock,progression,, -84,Progressive Coop,progression,, -85,Progressive Barn,progression,, -86,Well,useful,, -87,Silo,progression,, -88,Mill,progression,, -89,Progressive Shed,progression,, -90,Fish Pond,progression,, -91,Stable,useful,, -92,Slime Hutch,useful,, -93,Shipping Bin,progression,, +78,Earth Obelisk,progression,WIZARD_BUILDING, +79,Water Obelisk,progression,WIZARD_BUILDING, +80,Desert Obelisk,progression,WIZARD_BUILDING, +81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", +82,Junimo Hut,useful,WIZARD_BUILDING, +83,Gold Clock,progression,WIZARD_BUILDING, +84,Progressive Coop,progression,BUILDING, +85,Progressive Barn,progression,BUILDING, +86,Well,useful,BUILDING, +87,Silo,progression,BUILDING, +88,Mill,progression,BUILDING, +89,Progressive Shed,progression,BUILDING, +90,Fish Pond,progression,BUILDING, +91,Stable,useful,BUILDING, +92,Slime Hutch,progression,BUILDING, +93,Shipping Bin,progression,BUILDING, 94,Beach Bridge,progression,, 95,Adventurer's Guild,progression,, 96,Club Card,progression,, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 24ed689902db..6d73a6ee0445 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1039,7 +1039,7 @@ id,region,name,tags,mod_name 2347,Farming,Harvest Coffee Bean,"CROPSANITY", 2500,Farm,PLACEHOLDER Shipsanity start,"SHIPSANITY" 3000,Farm,PLACEHOLDER Shipsanity end,"SHIPSANITY" -3001,Adventurer's Guild,Monster Eradication: Slime,"MONSTERSANITY,MONSTERSANITY_GOALS", +3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", 3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", 3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", 3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 1f0735f4aebc..53d5c3c859fd 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -38,6 +38,8 @@ class Group(enum.Enum): WEAPON = enum.auto() PROGRESSIVE_TOOLS = enum.auto() SKILL_LEVEL_UP = enum.auto() + BUILDING = enum.auto() + WIZARD_BUILDING = enum.auto() ARCADE_MACHINE_BUFFS = enum.auto() GALAXY_WEAPONS = enum.auto() BASE_RESOURCE = enum.auto() diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index b4c0ce22be0c..904532f22d31 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,6 +1,10 @@ +from typing import Iterable + from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from ..data.monster_data import StardewMonster from ..mods.logic.magic_logic import MagicLogic -from ..stardew_rule import StardewRule +from ..stardew_rule import StardewRule, Or, And from ..strings.performance_names import Performance from ..items import all_items, Group @@ -8,10 +12,12 @@ class CombatLogic: player: int received: ReceivedLogic + region: RegionLogic magic: MagicLogic - def __init__(self, player: int, received: ReceivedLogic): + def __init__(self, player: int, received: ReceivedLogic, region: RegionLogic): self.player = player + self.region = region self.received = received def set_magic(self, magic: MagicLogic): @@ -28,6 +34,8 @@ def can_fight_at_level(self, level: str) -> StardewRule: return self.has_great_weapon() | self.magic.has_great_spells() if level == Performance.galaxy: return self.has_galaxy_weapon() | self.magic.has_amazing_spells() + if level == Performance.maximum: + return self.has_galaxy_weapon() | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP def has_any_weapon(self) -> StardewRule: higher_weapon_rule = self.has_decent_weapon() @@ -55,3 +63,16 @@ def has_galaxy_weapon(self) -> StardewRule: this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) return this_weapon_rule & self.received("Adventurer's Guild") + def can_kill_monster(self, monster: StardewMonster) -> StardewRule: + region_rule = self.region.can_reach_any(monster.locations) + combat_rule = self.can_fight_at_level(monster.difficulty) + return region_rule & combat_rule + + def can_kill_any_monster(self, monsters: Iterable[StardewMonster]) -> StardewRule: + rules = [self.can_kill_monster(monster) for monster in monsters] + return Or(rules) + + def can_kill_all_monsters(self, monsters: Iterable[StardewMonster]) -> StardewRule: + rules = [self.can_kill_monster(monster) for monster in monsters] + return And(rules) + diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index ac5aa109acb7..023e15227918 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -113,7 +113,7 @@ def __post_init__(self): self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.options[options.Museumsanity], self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) - self.combat = CombatLogic(self.player, self.received) + self.combat = CombatLogic(self.player, self.received, self.region) self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) self.crop = CropLogic(self.player, self.has, self.region, self.season, self.tool) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 4768abca874a..1ea6f535295d 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -22,7 +22,9 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.farm, [Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse, - Entrance.use_desert_obelisk, Entrance.use_island_obelisk, Entrance.farming]), + Entrance.use_desert_obelisk, Entrance.use_island_obelisk, + Entrance.enter_coop, Entrance.enter_barn, + Entrance.enter_shed, Entrance.enter_slime_hutch, Entrance.farming]), RegionData(Region.farming), RegionData(Region.backwoods, [Entrance.backwoods_to_mountain]), RegionData(Region.bus_stop, @@ -141,8 +143,10 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.skull_cavern_100, [Entrance.mine_to_skull_cavern_floor_125]), RegionData(Region.skull_cavern_125, [Entrance.mine_to_skull_cavern_floor_150]), RegionData(Region.skull_cavern_150, [Entrance.mine_to_skull_cavern_floor_175]), - RegionData(Region.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200]), + RegionData(Region.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200, + Entrance.enter_dangerous_skull_cavern]), RegionData(Region.skull_cavern_200), + RegionData(Region.dangerous_skull_cavern), RegionData(Region.island_south, [Entrance.island_south_to_west, Entrance.island_south_to_north, Entrance.island_south_to_east, Entrance.island_south_to_southeast, Entrance.use_island_resort, @@ -208,7 +212,14 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.mines_floor_105, [Entrance.dig_to_mines_floor_110]), RegionData(Region.mines_floor_110, [Entrance.dig_to_mines_floor_115]), RegionData(Region.mines_floor_115, [Entrance.dig_to_mines_floor_120]), - RegionData(Region.mines_floor_120), + RegionData(Region.mines_floor_120, [Entrance.dig_to_dangerous_mines_20, Entrance.dig_to_dangerous_mines_60, Entrance.dig_to_dangerous_mines_100]), + RegionData(Region.dangerous_mines_20), + RegionData(Region.dangerous_mines_60), + RegionData(Region.dangerous_mines_100), + RegionData(Region.coop), + RegionData(Region.barn), + RegionData(Region.shed), + RegionData(Region.slime_hutch), RegionData(Region.egg_festival), RegionData(Region.flower_dance), RegionData(Region.luau), @@ -232,6 +243,10 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.farm_to_farmcave, Region.farm_cave, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(Entrance.farming, Region.farming), ConnectionData(Entrance.enter_greenhouse, Region.greenhouse), + ConnectionData(Entrance.enter_coop, Region.coop), + ConnectionData(Entrance.enter_barn, Region.barn), + ConnectionData(Entrance.enter_shed, Region.shed), + ConnectionData(Entrance.enter_slime_hutch, Region.slime_hutch), ConnectionData(Entrance.use_desert_obelisk, Region.desert), ConnectionData(Entrance.use_island_obelisk, Region.island_south), ConnectionData(Entrance.use_farm_obelisk, Region.farm), @@ -356,6 +371,9 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.dig_to_mines_floor_110, Region.mines_floor_110), ConnectionData(Entrance.dig_to_mines_floor_115, Region.mines_floor_115), ConnectionData(Entrance.dig_to_mines_floor_120, Region.mines_floor_120), + ConnectionData(Entrance.dig_to_dangerous_mines_20, Region.dangerous_mines_20), + ConnectionData(Entrance.dig_to_dangerous_mines_60, Region.dangerous_mines_60), + ConnectionData(Entrance.dig_to_dangerous_mines_100, Region.dangerous_mines_100), ConnectionData(Entrance.enter_skull_cavern_entrance, Region.skull_cavern_entrance, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.enter_oasis, Region.oasis, @@ -370,6 +388,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.mine_to_skull_cavern_floor_150, Region.skull_cavern_150), ConnectionData(Entrance.mine_to_skull_cavern_floor_175, Region.skull_cavern_175), ConnectionData(Entrance.mine_to_skull_cavern_floor_200, Region.skull_cavern_200), + ConnectionData(Entrance.enter_dangerous_skull_cavern, Region.dangerous_skull_cavern), ConnectionData(Entrance.enter_witch_warp_cave, Region.witch_warp_cave, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.enter_witch_swamp, Region.witch_swamp, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.enter_witch_hut, Region.witch_hut, flag=RandomizationFlag.BUILDINGS), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index df96ac851f03..96afd58ae060 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -1,21 +1,23 @@ import itertools -from typing import List +from typing import Dict, List from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules -from .mods.logic.skullcavernelevator import has_skull_cavern_elevator_to_floor -from .options import StardewValleyOptions, ToolProgression, BuildingProgression, SkillProgression, ExcludeGingerIsland, Cropsanity, SpecialOrderLocations, Museumsanity, \ - BackpackProgression, ArcadeMachineLocations -from .data.monster_data import all_monsters_by_category +from . import options, locations +from .bundles import Bundle +from .data.monster_data import all_monsters_by_category, all_monsters, all_monsters_by_name from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices from .stardew_rule import And +from .strings.building_names import Building from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance -from .data.museum_data import all_museum_items, all_mineral_items, all_artifact_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name +from .data.museum_data import all_museum_items, all_mineral_items, all_artifact_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, \ + all_museum_items_by_name from .strings.performance_names import Performance from .strings.region_names import Region from .mods.mod_data import ModNames -from .locations import LocationTags, locations_by_tag +from .locations import LocationTags +from .options import StardewOptions from .strings.ap_names.transport_names import Transportation from .strings.artisan_good_names import ArtisanGood from .strings.calendar_names import Weekday @@ -29,18 +31,13 @@ from .strings.wallet_item_names import Wallet -def set_rules(world): - multiworld = world.multiworld - world_options = world.options - player = world.player - logic = world.logic - current_bundles = world.modified_bundles - - all_location_names = list(location.name for location in multiworld.get_locations(player)) +def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOptions, logic: StardewLogic, + current_bundles: Dict[str, Bundle]): + all_location_names = list(location.name for location in multi_world.get_locations(player)) - set_entrance_rules(logic, multiworld, player, world_options) + set_entrance_rules(logic, multi_world, player, world_options) - set_ginger_island_rules(logic, multiworld, player, world_options) + set_ginger_island_rules(logic, multi_world, player, world_options) set_tool_rules(logic, multiworld, player, world_options) set_skills_rules(logic, multiworld, player, world_options) @@ -56,7 +53,7 @@ def set_rules(world): set_backpack_rules(logic, multiworld, player, world_options) set_festival_rules(all_location_names, logic, multiworld, player) - set_monstersanity_rules(all_location_names, logic, multiworld, player) + set_monstersanity_rules(all_location_names, logic, multiworld, player, world_options) set_isolated_locations_rules(logic, multiworld, player) set_traveling_merchant_rules(logic, multiworld, player) @@ -65,7 +62,7 @@ def set_rules(world): set_magic_spell_rules(logic, multiworld, player, world_options) -def set_isolated_locations_rules(logic: StardewLogic,multiworld, player): +def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.add_rule(multiworld.get_location("Old Master Cannoli", player), logic.has("Sweet Gem Berry").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Galaxy Sword Shrine", player), @@ -106,29 +103,29 @@ def set_building_rules(logic: StardewLogic, multi_world, player, world_options): def set_bundle_rules(current_bundles, logic: StardewLogic, multi_world, player): for bundle in current_bundles.values(): - location = multiworld.get_location(bundle.get_name_with_bundle(), player) + location = multi_world.get_location(bundle.get_name_with_bundle(), player) rules = logic.can_complete_bundle(bundle.requirements, bundle.number_required) simplified_rules = rules.simplify() MultiWorldRules.set_rule(location, simplified_rules) - MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), + MultiWorldRules.add_rule(multi_world.get_location("Complete Crafts Room", player), And(logic.region.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), + for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multi_world.get_location("Complete Pantry", player), And(logic.region.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.PANTRY_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), + for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multi_world.get_location("Complete Fish Tank", player), And(logic.region.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.FISH_TANK_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), + for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multi_world.get_location("Complete Boiler Room", player), And(logic.region.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), + for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multi_world.get_location("Complete Bulletin Board", player), And(logic.region.can_reach_location(bundle.name) for bundle - in locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), + in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]).simplify()) + MultiWorldRules.add_rule(multi_world.get_location("Complete Vault", player), And(logic.region.can_reach_location(bundle.name) - for bundle in locations_by_tag[LocationTags.VAULT_BUNDLE]).simplify()) + for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]).simplify()) def set_skills_rules(logic: StardewLogic, multi_world, player, world_options): @@ -185,42 +182,62 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: set_skill_entrance_rules(logic, multiworld, player) set_traveling_merchant_day_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), + dangerous_mine_rule = logic.mine.has_mine_elevator_to_floor(120) & logic.region.can_reach(Region.qi_walnut_room) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_to_dangerous_mines_20, player), + dangerous_mine_rule.simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_to_dangerous_mines_60, player), + dangerous_mine_rule.simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_to_dangerous_mines_100, player), + dangerous_mine_rule.simplify()) + + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_tide_pools, player), logic.received("Beach Bridge") | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_quarry, player), logic.received("Bridge Repair") | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_secret_woods, player), logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.forest_to_sewer, player), logic.wallet.has_rusty_key().simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.town_to_sewer, player), logic.wallet.has_rusty_key().simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.take_bus_to_desert, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.take_bus_to_desert, player), logic.received("Bus Repair").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_skull_cavern, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_skull_cavern, player), logic.received(Wallet.skull_key).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_dangerous_skull_cavern, player), + (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room)).simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_mines_dwarf, player), logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_desert_obelisk, player), logic.received(Transportation.desert_obelisk).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_obelisk, player), logic.received(Transportation.island_obelisk).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_farm_obelisk, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_farm_obelisk, player), logic.received(Transportation.farm_obelisk).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.buy_from_traveling_merchant, player), logic.has_traveling_merchant()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_greenhouse, player), + + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_coop, player), + logic.buildings.has_building(Building.coop)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_barn, player), + logic.buildings.has_building(Building.barn)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_shed, player), + logic.buildings.has_building(Building.shed)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_slime_hutch, player), + logic.buildings.has_building(Building.slime_hutch)) + + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_adventurer_guild, player), logic.received("Adventurer's Guild")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_railroad, player), logic.time.has_lived_months(2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_witch_warp_cave, player), logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_witch_hut, player), (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_mutant_bug_lair, player), ((logic.wallet.has_rusty_key() & logic.region.can_reach(Region.railroad) & logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()).simplify())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), @@ -230,22 +247,22 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_maru_room, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_leah_cottage, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_elliott_house, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sunroom, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_wizard_basement, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_leo_treehouse, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) - if ModNames.alec in world_options.mods: - MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), + if ModNames.alec in world_options[options.Mods]: + MultiWorldRules.set_rule(multi_world.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) @@ -307,59 +324,59 @@ def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_optio if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return - set_boat_repair_rules(logic, multiworld, player) - set_island_parrot_rules(logic, multiworld, player) - MultiWorldRules.add_rule(multiworld.get_location("Open Professor Snail Cave", player), + set_boat_repair_rules(logic, multi_world, player) + set_island_parrot_rules(logic, multi_world, player) + MultiWorldRules.add_rule(multi_world.get_location("Open Professor Snail Cave", player), logic.has(Craftable.cherry_bomb).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Complete Island Field Office", player), + MultiWorldRules.add_rule(multi_world.get_location("Complete Island Field Office", player), logic.can_complete_field_office().simplify()) -def set_boat_repair_rules(logic: StardewLogic, multiworld, player): - MultiWorldRules.add_rule(multiworld.get_location("Repair Boat Hull", player), +def set_boat_repair_rules(logic: StardewLogic, multi_world, player): + MultiWorldRules.add_rule(multi_world.get_location("Repair Boat Hull", player), logic.has(Material.hardwood).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Repair Boat Anchor", player), + MultiWorldRules.add_rule(multi_world.get_location("Repair Boat Anchor", player), logic.has(MetalBar.iridium).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Repair Ticket Machine", player), + MultiWorldRules.add_rule(multi_world.get_location("Repair Ticket Machine", player), logic.has(ArtisanGood.battery_pack).simplify()) -def set_island_entrances_rules(logic: StardewLogic, multiworld, player): +def set_island_entrances_rules(logic: StardewLogic, multi_world, player): boat_repaired = logic.received(Transportation.boat_repair).simplify() - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fish_shop_to_boat_tunnel, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.fish_shop_to_boat_tunnel, player), boat_repaired) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.boat_to_ginger_island, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.boat_to_ginger_island, player), boat_repaired) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_west, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_south_to_west, player), logic.received("Island West Turtle").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_north, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_south_to_north, player), logic.received("Island North Turtle").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_islandfarmhouse, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_west_to_islandfarmhouse, player), logic.received("Island Farmhouse").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_gourmand_cave, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_west_to_gourmand_cave, player), logic.received("Island Farmhouse").simplify()) dig_site_rule = logic.received("Dig Site Bridge").simplify() MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_dig_site, player), dig_site_rule) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), logic.received("Open Professor Snail Cave").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_island_trader, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_island_trader, player), logic.received("Island Trader").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_southeast, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_south_to_southeast, player), logic.received("Island Resort").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_resort, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_resort, player), logic.received("Island Resort").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_qi_walnut_room, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_west_to_qi_walnut_room, player), logic.received("Qi Walnut Room").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_volcano, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_north_to_volcano, player), (logic.tool.can_water(0) | logic.received("Volcano Bridge") | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.volcano_to_secret_beach, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.volcano_to_secret_beach, player), logic.tool.can_water(2).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.climb_to_volcano_5, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_volcano_dwarf, player), logic.wallet.can_speak_dwarf()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.climb_to_volcano_10, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1) & logic.received("Volcano Exit Shortcut")).simplify()) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_docks_to_dig_site, @@ -376,46 +393,46 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), parrot_express_rule) -def set_island_parrot_rules(logic: StardewLogic, multiworld, player): +def set_island_parrot_rules(logic: StardewLogic, multi_world, player): has_walnut = logic.has_walnut(1).simplify() has_5_walnut = logic.has_walnut(5).simplify() has_10_walnut = logic.has_walnut(10).simplify() has_20_walnut = logic.has_walnut(20).simplify() - MultiWorldRules.add_rule(multiworld.get_location("Leo's Parrot", player), + MultiWorldRules.add_rule(multi_world.get_location("Leo's Parrot", player), has_walnut) - MultiWorldRules.add_rule(multiworld.get_location("Island West Turtle", player), + MultiWorldRules.add_rule(multi_world.get_location("Island West Turtle", player), has_10_walnut & logic.received("Island North Turtle")) - MultiWorldRules.add_rule(multiworld.get_location("Island Farmhouse", player), + MultiWorldRules.add_rule(multi_world.get_location("Island Farmhouse", player), has_20_walnut) - MultiWorldRules.add_rule(multiworld.get_location("Island Mailbox", player), + MultiWorldRules.add_rule(multi_world.get_location("Island Mailbox", player), has_5_walnut & logic.received("Island Farmhouse")) - MultiWorldRules.add_rule(multiworld.get_location(Transportation.farm_obelisk, player), + MultiWorldRules.add_rule(multi_world.get_location(Transportation.farm_obelisk, player), has_20_walnut & logic.received("Island Mailbox")) - MultiWorldRules.add_rule(multiworld.get_location("Dig Site Bridge", player), + MultiWorldRules.add_rule(multi_world.get_location("Dig Site Bridge", player), has_10_walnut & logic.received("Island West Turtle")) - MultiWorldRules.add_rule(multiworld.get_location("Island Trader", player), + MultiWorldRules.add_rule(multi_world.get_location("Island Trader", player), has_10_walnut & logic.received("Island Farmhouse")) - MultiWorldRules.add_rule(multiworld.get_location("Volcano Bridge", player), + MultiWorldRules.add_rule(multi_world.get_location("Volcano Bridge", player), has_5_walnut & logic.received("Island West Turtle") & logic.region.can_reach(Region.volcano_floor_10)) - MultiWorldRules.add_rule(multiworld.get_location("Volcano Exit Shortcut", player), + MultiWorldRules.add_rule(multi_world.get_location("Volcano Exit Shortcut", player), has_5_walnut & logic.received("Island West Turtle")) - MultiWorldRules.add_rule(multiworld.get_location("Island Resort", player), + MultiWorldRules.add_rule(multi_world.get_location("Island Resort", player), has_20_walnut & logic.received("Island Farmhouse")) - MultiWorldRules.add_rule(multiworld.get_location(Transportation.parrot_express, player), + MultiWorldRules.add_rule(multi_world.get_location(Transportation.parrot_express, player), has_10_walnut) -def set_cropsanity_rules(all_location_names: List[str], logic, multiworld, player, world_options: StardewValleyOptions): - if world_options.cropsanity == Cropsanity.option_disabled: +def set_cropsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options: StardewOptions): + if world_options[options.Cropsanity] == options.Cropsanity.option_disabled: return harvest_prefix = "Harvest " harvest_prefix_length = len(harvest_prefix) - for harvest_location in locations_by_tag[LocationTags.CROPSANITY]: - if harvest_location.name in all_location_names and (harvest_location.mod_name is None or harvest_location.mod_name in world_options.mods): + for harvest_location in locations.locations_by_tag[LocationTags.CROPSANITY]: + if harvest_location.name in all_location_names and (harvest_location.mod_name is None or harvest_location.mod_name in world_options[options.Mods]): crop_name = harvest_location.name[harvest_prefix_length:] - MultiWorldRules.set_rule(multiworld.get_location(harvest_location.name, player), + MultiWorldRules.set_rule(multi_world.get_location(harvest_location.name, player), logic.has(crop_name).simplify()) @@ -426,25 +443,25 @@ def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, m logic.quest_rules[quest.name].simplify()) -def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, - world_options: StardewValleyOptions): - if world_options.special_order_locations == SpecialOrderLocations.option_disabled: +def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, + world_options: StardewOptions): + if world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_disabled: return board_rule = logic.received("Special Order Board") & logic.time.has_lived_months(4) - for board_order in locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD]: + for board_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD]: if board_order.name in all_location_names: order_rule = board_rule & logic.special_order.special_order_rules[board_order.name] - MultiWorldRules.set_rule(multiworld.get_location(board_order.name, player), order_rule.simplify()) + MultiWorldRules.set_rule(multi_world.get_location(board_order.name, player), order_rule.simplify()) - if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: + if world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: return - if world_options.special_order_locations == SpecialOrderLocations.option_board_only: + if world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_only: return qi_rule = logic.region.can_reach(Region.qi_walnut_room) & logic.time.has_lived_months(8) - for qi_order in locations_by_tag[LocationTags.SPECIAL_ORDER_QI]: + for qi_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_QI]: if qi_order.name in all_location_names: order_rule = qi_rule & logic.special_order.special_order_rules[qi_order.name] - MultiWorldRules.set_rule(multiworld.get_location(qi_order.name, player), order_rule.simplify()) + MultiWorldRules.set_rule(multi_world.get_location(qi_order.name, player), order_rule.simplify()) help_wanted_prefix = "Help Wanted:" @@ -454,8 +471,8 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, slay_monsters = "Slay Monsters" -def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - help_wanted_number = world_options.help_wanted_locations +def set_help_wanted_quests_rules(logic: StardewLogic, multi_world, player, world_options): + help_wanted_number = world_options[options.HelpWantedLocations] for i in range(0, help_wanted_number): set_number = i // 7 month_rule = logic.time.has_lived_months(set_number).simplify() @@ -463,23 +480,23 @@ def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_ quest_number_in_set = i % 7 if quest_number_in_set < 4: quest_number = set_number * 4 + quest_number_in_set + 1 - set_help_wanted_delivery_rule(multiworld, player, month_rule, quest_number) + set_help_wanted_delivery_rule(multi_world, player, month_rule, quest_number) elif quest_number_in_set == 4: set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 5: set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 6: - set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number) + set_help_wanted_gathering_rule(multi_world, player, month_rule, quest_number) -def set_help_wanted_delivery_rule(multiworld, player, month_rule, quest_number): +def set_help_wanted_delivery_rule(multi_world, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {item_delivery} {quest_number}" - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) + MultiWorldRules.set_rule(multi_world.get_location(location_name, player), month_rule) -def set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number): +def set_help_wanted_gathering_rule(multi_world, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {gathering} {quest_number}" - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) + MultiWorldRules.set_rule(multi_world.get_location(location_name, player), month_rule) def set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number): @@ -492,27 +509,27 @@ def set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_num MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule.simplify()) -def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): +def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world: MultiWorld, player: int): fish_prefix = "Fishsanity: " - for fish_location in locations_by_tag[LocationTags.FISHSANITY]: + for fish_location in locations.locations_by_tag[LocationTags.FISHSANITY]: if fish_location.name in all_location_names: fish_name = fish_location.name[len(fish_prefix):] - MultiWorldRules.set_rule(multiworld.get_location(fish_location.name, player), + MultiWorldRules.set_rule(multi_world.get_location(fish_location.name, player), logic.has(fish_name).simplify()) -def set_museumsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int, - world_options: StardewValleyOptions): +def set_museumsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world: MultiWorld, player: int, + world_options: StardewOptions): museum_prefix = "Museumsanity: " - if world_options.museumsanity == Museumsanity.option_milestones: - for museum_milestone in locations_by_tag[LocationTags.MUSEUM_MILESTONES]: - set_museum_milestone_rule(logic, multiworld, museum_milestone, museum_prefix, player) - elif world_options.museumsanity != Museumsanity.option_none: - set_museum_individual_donations_rules(all_location_names, logic, multiworld, museum_prefix, player) + if world_options[options.Museumsanity] == options.Museumsanity.option_milestones: + for museum_milestone in locations.locations_by_tag[LocationTags.MUSEUM_MILESTONES]: + set_museum_milestone_rule(logic, multi_world, museum_milestone, museum_prefix, player) + elif world_options[options.Museumsanity] != options.Museumsanity.option_none: + set_museum_individual_donations_rules(all_location_names, logic, multi_world, museum_prefix, player) -def set_museum_individual_donations_rules(all_location_names, logic: StardewLogic, multiworld, museum_prefix, player): - all_donations = sorted(locations_by_tag[LocationTags.MUSEUM_DONATIONS], +def set_museum_individual_donations_rules(all_location_names, logic: StardewLogic, multi_world, museum_prefix, player): + all_donations = sorted(locations.locations_by_tag[LocationTags.MUSEUM_DONATIONS], key=lambda x: all_museum_items_by_name[x.name[len(museum_prefix):]].difficulty, reverse=True) counter = 0 number_donations = len(all_donations) @@ -527,7 +544,7 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi counter += 1 -def set_museum_milestone_rule(logic: StardewLogic, multiworld: MultiWorld, museum_milestone, museum_prefix: str, +def set_museum_milestone_rule(logic: StardewLogic, multi_world: MultiWorld, museum_milestone, museum_prefix: str, player: int): milestone_name = museum_milestone.name[len(museum_prefix):] donations_suffix = " Donations" @@ -553,7 +570,7 @@ def set_museum_milestone_rule(logic: StardewLogic, multiworld: MultiWorld, museu rule = logic.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) if rule is None: return - MultiWorldRules.set_rule(multiworld.get_location(museum_milestone.name, player), rule.simplify()) + MultiWorldRules.set_rule(multi_world.get_location(museum_milestone.name, player), rule.simplify()) def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, accepted_items, donation_func): @@ -564,106 +581,159 @@ def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, acce return rule -def set_backpack_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): - if world_options.backpack_progression != BackpackProgression.option_vanilla: - MultiWorldRules.set_rule(multiworld.get_location("Large Pack", player), +def set_backpack_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options): + if world_options[options.BackpackProgression] != options.BackpackProgression.option_vanilla: + MultiWorldRules.set_rule(multi_world.get_location("Large Pack", player), logic.money.can_spend(2000).simplify()) - MultiWorldRules.set_rule(multiworld.get_location("Deluxe Pack", player), + MultiWorldRules.set_rule(multi_world.get_location("Deluxe Pack", player), (logic.money.can_spend(10000) & logic.received("Progressive Backpack")).simplify()) - if ModNames.big_backpack in world_options.mods: - MultiWorldRules.set_rule(multiworld.get_location("Premium Pack", player), + if ModNames.big_backpack in world_options[options.Mods]: + MultiWorldRules.set_rule(multi_world.get_location("Premium Pack", player), (logic.money.can_spend(150000) & logic.received("Progressive Backpack", 2)).simplify()) -def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): +def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player): festival_locations = [] - festival_locations.extend(locations_by_tag[LocationTags.FESTIVAL]) - festival_locations.extend(locations_by_tag[LocationTags.FESTIVAL_HARD]) + festival_locations.extend(locations.locations_by_tag[LocationTags.FESTIVAL]) + festival_locations.extend(locations.locations_by_tag[LocationTags.FESTIVAL_HARD]) for festival in festival_locations: if festival.name in all_location_names: - MultiWorldRules.set_rule(multiworld.get_location(festival.name, player), + MultiWorldRules.set_rule(multi_world.get_location(festival.name, player), logic.festival_rules[festival.name].simplify()) -def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player): - monstersanity_locations = [] - monstersanity_locations.extend(locations.locations_by_tag[LocationTags.MONSTERSANITY]) - monster_eradication_prefix = "Monster Eradication: " - for location in monstersanity_locations: - if location.name not in all_location_names or not location.name.startswith(monster_eradication_prefix): +monster_eradication_prefix = "Monster Eradication: " + + +def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): + monstersanity_option = world_options[options.Monstersanity] + if monstersanity_option == options.Monstersanity.option_none: + return + + if monstersanity_option == options.Monstersanity.option_one_per_monster or monstersanity_option == options.Monstersanity.option_split_goals: + set_monstersanity_monster_rules(all_location_names, logic, multi_world, player, monstersanity_option) + return + + if monstersanity_option == options.Monstersanity.option_progressive_goals: + set_monstersanity_progressive_category_rules(all_location_names, logic, multi_world, player, monstersanity_option) + return + + set_monstersanity_category_rules(all_location_names, logic, multi_world, player, monstersanity_option) + + +def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monstersanity_option): + for monster_name in all_monsters_by_name: + location_name = f"{monster_eradication_prefix}{monster_name}" + if location_name not in all_location_names: continue - # what_to_slay = location.name[len(monster_eradication_prefix):] - # first_word = what_to_slay[what_to_slay.index(" "):] - #if what_to_slay in all_monsters_by_category: - # set_monstersanity_category_rule(what_to_slay) - # continue - #if not first_word.isdigit(): - # set_monstersanity__rules() - # MultiWorldRules.set_rule(multi_world.get_location(location.name, player), logic.festival_rules[location.name].simplify()) + location = multi_world.get_location(location_name, player) + rule = logic.combat.can_kill_monster(all_monsters_by_name[monster_name]) + if monstersanity_option == options.Monstersanity.option_split_goals: + rule = rule & logic.time.has_lived_max_months() + MultiWorldRules.set_rule(location, rule.simplify()) + + +def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monstersanity_option): + for monster_category in all_monsters_by_category: + location_names = [name for name in all_location_names if name.startswith(monster_eradication_prefix) and name.endswith(monster_category)] + if not location_names: + continue + location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) + for i in range(5): + location_name = location_names[i] + if location_name not in all_location_names: + continue + location = multi_world.get_location(location_name, player) + if i < 3: + rule = logic.combat.can_kill_any_monster(all_monsters_by_category[monster_category]) & logic.time.has_lived_months((i+1) * 2) + else: + rule = logic.combat.can_kill_all_monsters(all_monsters_by_category[monster_category]) & logic.time.has_lived_months(i * 3) + MultiWorldRules.set_rule(location, rule.simplify()) + + +def get_monster_eradication_number(location_name, monster_category) -> int: + number = location_name[len(monster_eradication_prefix):-len(monster_category)] + number = number.strip() + if number.isdigit(): + return int(number) + return 1000 + + +def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monstersanity_option): + for monster_category in all_monsters_by_category: + location_name = f"{monster_eradication_prefix}{monster_category}" + if location_name not in all_location_names: + continue + location = multi_world.get_location(location_name, player) + if monstersanity_option == options.Monstersanity.option_one_per_category: + rule = logic.combat.can_kill_any_monster(all_monsters_by_category[monster_category]) + else: + rule = logic.combat.can_kill_all_monsters(all_monsters_by_category[monster_category]) & logic.time.has_lived_max_months() + MultiWorldRules.set_rule(location, rule.simplify()) -def set_traveling_merchant_day_rules(logic: StardewLogic, multiworld: MultiWorld, player: int): +def set_traveling_merchant_day_rules(logic: StardewLogic, multi_world: MultiWorld, player: int): for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" entrance_name = f"Buy from Traveling Merchant {day}" MultiWorldRules.set_rule(multiworld.get_entrance(entrance_name, player), logic.received(item_for_day)) -def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_junimo_kart, player), +def set_arcade_machine_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options): + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.play_junimo_kart, player), logic.received(Wallet.skull_key).simplify()) - if world_options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: + if world_options[options.ArcadeMachineLocations] != options.ArcadeMachineLocations.option_full_shuffling: return - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_junimo_kart, player), + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.play_junimo_kart, player), logic.has("Junimo Kart Small Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_junimo_kart_2, player), + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_junimo_kart_2, player), logic.has("Junimo Kart Medium Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_junimo_kart_3, player), + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_junimo_kart_3, player), logic.has("Junimo Kart Big Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Junimo Kart: Sunset Speedway (Victory)", player), + MultiWorldRules.add_rule(multi_world.get_location("Junimo Kart: Sunset Speedway (Victory)", player), logic.has("Junimo Kart Max Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_journey_of_the_prairie_king, player), + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.play_journey_of_the_prairie_king, player), logic.has("JotPK Small Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_jotpk_world_2, player), + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_jotpk_world_2, player), logic.has("JotPK Medium Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_jotpk_world_3, player), + MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_jotpk_world_3, player), logic.has("JotPK Big Buff").simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Journey of the Prairie King Victory", player), + MultiWorldRules.add_rule(multi_world.get_location("Journey of the Prairie King Victory", player), logic.has("JotPK Max Buff").simplify()) -def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): +def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world: MultiWorld, player: int): friend_prefix = "Friendsanity: " friend_suffix = " <3" - for friend_location in locations_by_tag[LocationTags.FRIENDSANITY]: - if friend_location.name not in all_location_names: + for friend_location in locations.locations_by_tag[LocationTags.FRIENDSANITY]: + if not friend_location.name in all_location_names: continue friend_location_without_prefix = friend_location.name[len(friend_prefix):] friend_location_trimmed = friend_location_without_prefix[:friend_location_without_prefix.index(friend_suffix)] split_index = friend_location_trimmed.rindex(" ") friend_name = friend_location_trimmed[:split_index] num_hearts = int(friend_location_trimmed[split_index + 1:]) - MultiWorldRules.set_rule(multiworld.get_location(friend_location.name, player), + MultiWorldRules.set_rule(multi_world.get_location(friend_location.name, player), logic.relationship.can_earn_relationship(friend_name, num_hearts).simplify()) -def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): - if ModNames.deepwoods in world_options.mods: - MultiWorldRules.add_rule(multiworld.get_location("Breaking Up Deep Woods Gingerbread House", player), +def set_deepwoods_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options: StardewOptions): + if ModNames.deepwoods in world_options[options.Mods]: + MultiWorldRules.add_rule(multi_world.get_location("Breaking Up Deep Woods Gingerbread House", player), logic.tool.has_tool(Tool.axe, "Gold") & logic.mod.deepwoods.can_reach_woods_depth(50).simplify()) - MultiWorldRules.add_rule(multiworld.get_location("Chop Down a Deep Woods Iridium Tree", player), + MultiWorldRules.add_rule(multi_world.get_location("Chop Down a Deep Woods Iridium Tree", player), logic.tool.has_tool(Tool.axe, "Iridium").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), + MultiWorldRules.set_rule(multi_world.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), logic.received("Woods Obelisk").simplify()) for depth in range(10, 100 + 10, 10): - MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), + MultiWorldRules.set_rule(multi_world.get_entrance(move_to_woods_depth(depth), player), logic.mod.deepwoods.can_chop_to_depth(depth).simplify()) -def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): - if ModNames.magic not in world_options.mods: +def set_magic_spell_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options: StardewOptions): + if ModNames.magic not in world_options[options.Mods]: return MultiWorldRules.set_rule(multiworld.get_entrance(MagicEntrance.store_to_altar, player), diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 1c1f0bc9ea2c..3913da73550c 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -2,6 +2,10 @@ def dig_to_mines_floor(floor: int) -> str: return f"Dig to The Mines - Floor {floor}" +def dig_to_dangerous_mines_floor(floor: int) -> str: + return f"Dig to the Dangerous Mines - Floor {floor}" + + def dig_to_skull_floor(floor: int) -> str: return f"Mine to Skull Cavern Floor {floor}" @@ -22,6 +26,10 @@ class Entrance: farm_to_forest = "Farm to Forest" farm_to_farmcave = "Farm to Farmcave" enter_greenhouse = "Farm to Greenhouse" + enter_coop = "Farm to Coop" + enter_barn = "Farm to Barn" + enter_shed = "Farm to Shed" + enter_slime_hutch = "Farm to Slime Hutch" use_desert_obelisk = "Use Desert Obelisk" use_island_obelisk = "Use Island Obelisk" use_farm_obelisk = "Use Farm Obelisk" @@ -108,6 +116,7 @@ class Entrance: mine_to_skull_cavern_floor_150 = dig_to_skull_floor(150) mine_to_skull_cavern_floor_175 = dig_to_skull_floor(175) mine_to_skull_cavern_floor_200 = dig_to_skull_floor(200) + enter_dangerous_skull_cavern = "Enter the Dangerous Skull Cavern" talk_to_mines_dwarf = "Talk to Mines Dwarf" dig_to_mines_floor_5 = dig_to_mines_floor(5) dig_to_mines_floor_10 = dig_to_mines_floor(10) @@ -133,6 +142,9 @@ class Entrance: dig_to_mines_floor_110 = dig_to_mines_floor(110) dig_to_mines_floor_115 = dig_to_mines_floor(115) dig_to_mines_floor_120 = dig_to_mines_floor(120) + dig_to_dangerous_mines_20 = dig_to_dangerous_mines_floor(20) + dig_to_dangerous_mines_60 = dig_to_dangerous_mines_floor(60) + dig_to_dangerous_mines_100 = dig_to_dangerous_mines_floor(100) island_south_to_west = "Island South to West" island_south_to_north = "Island South to North" island_south_to_east = "Island South to East" diff --git a/worlds/stardew_valley/strings/monster_names.py b/worlds/stardew_valley/strings/monster_names.py index e28d70b7bfe1..00faef8efb16 100644 --- a/worlds/stardew_valley/strings/monster_names.py +++ b/worlds/stardew_valley/strings/monster_names.py @@ -52,7 +52,7 @@ class Monster: class MonsterCategory: - slime = "Slime" + slime = "Slimes" void_spirits = "Void Spirits" bats = "Bats" skeletons = "Skeletons" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 159c6a56a9fb..13fe8cc74cd0 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -4,6 +4,10 @@ class Region: farm_house = "Farmhouse" cellar = "Cellar" farm = "Farm" + coop = "Coop" + barn = "Barn" + shed = "Shed" + slime_hutch = "Slime Hutch" town = "Town" beach = "Beach" mountain = "Mountain" @@ -108,7 +112,6 @@ class Region: bathhouse_entrance = "Bathhouse Entrance" locker_room = "Locker Room" public_bath = "Public Bath" - slime_hutch = "Slime Hutch" jotpk_world_1 = "JotPK World 1" jotpk_world_2 = "JotPK World 2" jotpk_world_3 = "JotPK World 3" diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index b25fb9291a66..143c6dd0cc97 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -325,6 +325,30 @@ def GiveItemAndCheckReachableMine(self, item_name: str, reachable_level: int): self.remove(item) +class TestMonstersanityProgressiveRules(SVTestBase): + options = { + options.Monstersanity.internal_name: options.Monstersanity.option_progressive_goals, + } + + def test_has_rules(self): + for location in self.multiworld.get_locations(self.player): + if "Monster Eradication: " not in location.name: + continue + self.assertFalse(self.world.logic.region.can_reach_location(location)(self.multiworld.state)) + + +class TestMonstersanitySplitRules(SVTestBase): + options = { + options.Monstersanity.internal_name: options.Monstersanity.option_split_goals, + } + + def test_has_rules(self): + for location in self.multiworld.get_locations(self.player): + if "Monster Eradication: " not in location.name: + continue + self.assertFalse(self.world.logic.region.can_reach_location(location)(self.multiworld.state)) + + class TestRecipeLogic(SVTestBase): options = { options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, From d84fea1914a9bbfdbf975ef81249d425ad03b8ab Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 6 Aug 2023 18:22:28 -0400 Subject: [PATCH 028/482] - Update allsanity options to include monstersanity - Updated expected locations counts in the allsanity tests --- worlds/stardew_valley/test/TestGeneration.py | 10 ++++++---- worlds/stardew_valley/test/__init__.py | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index ab1739e41587..5f7e001913f8 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -187,10 +187,11 @@ def test_minimal_location_maximal_items_still_valid(self): self.assertGreaterEqual(len(valid_locations), len(multiworld.itempool)) def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 994 + expected_locations = 1053 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) - number_locations = len(get_real_locations(self, multiworld)) + real_locations = get_real_locations(self, multiworld) + number_locations = len(real_locations) self.assertGreaterEqual(number_locations, expected_locations) print(f"Stardew Valley - Allsanity Locations without mods: {number_locations}") if number_locations != expected_locations: @@ -200,10 +201,11 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 1246 + expected_locations = 1305 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) - number_locations = len(get_real_locations(self, multiworld)) + real_locations = get_real_locations(self, multiworld) + number_locations = len(real_locations) self.assertGreaterEqual(number_locations, expected_locations) print(f"\nStardew Valley - Allsanity Locations with all mods: {number_locations}") if number_locations != expected_locations: diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 1926a64c0ee9..bb45b8736c9c 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -98,6 +98,7 @@ def allsanity_options_without_mods(): HelpWantedLocations.internal_name: 56, Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, + Monstersanity.internal_name: Monstersanity.option_progressive_goals, Friendsanity.internal_name: Friendsanity.option_all_with_marriage, FriendsanityHeartSize.internal_name: 1, NumberOfMovementBuffs.internal_name: 12, From 426941e7ed3e801283c24060cb65a67f3cafb77e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 7 Aug 2023 11:46:51 -0400 Subject: [PATCH 029/482] - Add Protector of the valley goal # Conflicts: # worlds/stardew_valley/options.py --- worlds/stardew_valley/options.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 595fb91e91ba..def373a6cf32 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -8,13 +8,14 @@ class Goal(Choice): """What's your goal with this play-through? Community Center: Complete the Community Center. - Grandpa's Evaluation: Succeed grandpa's evaluation with 4 lit candles. + Grandpa's Evaluation: Succeed Grandpa's evaluation with 4 lit candles. Bottom of the Mines: Reach level 120 in the mineshaft. Cryptic Note: Complete the quest "Cryptic Note" where Mr Qi asks you to reach floor 100 in the Skull Cavern. Master Angler: Catch every fish in the game. Pairs well with Fishsanity. Complete Collection: Complete the museum by donating every possible item. Pairs well with Museumsanity. Full House: Get married and have two children. Pairs well with Friendsanity. Greatest Walnut Hunter: Find all 130 Golden Walnuts + Protector of the Valley: Complete all the monster slayer goals. Pairs well with Monstersanity Perfection: Attain Perfection, based on the vanilla definition. """ internal_name = "goal" @@ -28,12 +29,12 @@ class Goal(Choice): option_complete_collection = 5 option_full_house = 6 option_greatest_walnut_hunter = 7 + option_protector_of_the_valley = 8 # option_junimo_kart = # option_prairie_king = # option_fector_challenge = # option_craft_master = # option_mystery_of_the_stardrops = - # option_protector_of_the_valley = # option_full_shipment = # option_legend = # option_beloved_farmer = From 4f2436ebf0dd6a10f3c566dc2ab6dff0c7a5179b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 7 Aug 2023 12:44:36 -0400 Subject: [PATCH 030/482] -Added logic on the protector goal --- worlds/stardew_valley/__init__.py | 8 ++++++-- worlds/stardew_valley/locations.py | 1 + worlds/stardew_valley/logic/logic.py | 8 ++++++++ worlds/stardew_valley/strings/goal_names.py | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 2f82ff141013..5c0533782666 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -210,8 +210,12 @@ def setup_victory(self): self.create_event_location(location_table[GoalName.greatest_walnut_hunter], self.logic.has_walnut(130).simplify(), "Victory") - elif self.options.goal == Goal.option_perfection: - self.create_event_location(location_table[GoalName.perfection], + elif self.options[options.Goal] == options.Goal.option_protector_of_the_valley: + self.create_event_location(location_table[Goal.protector_of_the_valley], + self.logic.can_complete_all_monster_slaying_goals.simplify(), + "Victory") + elif self.options[options.Goal] == options.Goal.option_perfection: + self.create_event_location(location_table[Goal.perfection], self.logic.has_everything(self.all_progression_items).simplify(), "Victory") diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 1d7a19b82f78..7250023f0e68 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -122,6 +122,7 @@ def load_location_csv() -> List[LocationData]: LocationData(None, Region.museum, Goal.complete_museum), LocationData(None, Region.farm_house, Goal.full_house), LocationData(None, Region.island_west, Goal.greatest_walnut_hunter), + LocationData(None, Region.adventurer_guild, Goal.protector_of_the_valley), LocationData(None, Region.qi_walnut_room, Goal.perfection), ] diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 023e15227918..53293b3e274a 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -27,6 +27,7 @@ from .time_logic import TimeLogic from .tool_logic import ToolLogic from .wallet_logic import WalletLogic +from ..data.monster_data import all_monsters_by_category from ..mods.logic.mod_logic import ModLogic from .. import options from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops @@ -646,6 +647,13 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: ] return Count(12, rules_worth_a_point) + def can_complete_all_monster_slaying_goals(self) -> StardewRule: + rules = [self.time.has_lived_max_months()] + for category in all_monsters_by_category: + rules.append(self.combat.can_kill_all_monsters(all_monsters_by_category[category])) + + return And(rules) + def can_win_egg_hunt(self) -> StardewRule: number_of_movement_buffs: int = self.options[options.NumberOfMovementBuffs] if self.options[options.FestivalLocations] == options.FestivalLocations.option_hard or number_of_movement_buffs < 2: diff --git a/worlds/stardew_valley/strings/goal_names.py b/worlds/stardew_valley/strings/goal_names.py index da8b7d847006..0356c3ccdabe 100644 --- a/worlds/stardew_valley/strings/goal_names.py +++ b/worlds/stardew_valley/strings/goal_names.py @@ -7,4 +7,5 @@ class Goal: complete_museum = "Complete the Museum Collection" full_house = "Full House" greatest_walnut_hunter = "Greatest Walnut Hunter" + protector_of_the_valley = "Protector of the Valley" perfection = "Perfection" From 3e9ac2ae4a3d4a1d4f04b2253e3c86e59df24d27 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 8 Aug 2023 11:05:40 -0400 Subject: [PATCH 031/482] - Added caching on some of the rules --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/logic/combat_logic.py | 56 ++++++++++++++------- worlds/stardew_valley/logic/logic.py | 6 ++- worlds/stardew_valley/logic/season_logic.py | 35 +++++++++---- worlds/stardew_valley/rules.py | 11 ++-- worlds/stardew_valley/stardew_rule.py | 3 +- 6 files changed, 78 insertions(+), 35 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 5c0533782666..d95f97b05d93 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -212,7 +212,7 @@ def setup_victory(self): "Victory") elif self.options[options.Goal] == options.Goal.option_protector_of_the_valley: self.create_event_location(location_table[Goal.protector_of_the_valley], - self.logic.can_complete_all_monster_slaying_goals.simplify(), + self.logic.can_complete_all_monster_slaying_goals().simplify(), "Victory") elif self.options[options.Goal] == options.Goal.option_perfection: self.create_event_location(location_table[Goal.perfection], diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 904532f22d31..f0a0d558d5b5 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -7,6 +7,7 @@ from ..stardew_rule import StardewRule, Or, And from ..strings.performance_names import Performance from ..items import all_items, Group +from ..strings.region_names import Region class CombatLogic: @@ -19,6 +20,11 @@ def __init__(self, player: int, received: ReceivedLogic, region: RegionLogic): self.player = player self.region = region self.received = received + self.has_any_weapon_rule = self.can_buy_weapon(self.has_received_any_weapon()) + self.has_decent_weapon_rule = self.can_buy_weapon(self.has_received_decent_weapon()) + self.has_good_weapon_rule = self.can_buy_weapon(self.has_received_good_weapon()) + self.has_great_weapon_rule = self.can_buy_weapon(self.has_received_great_weapon()) + self.has_galaxy_weapon_rule = self.can_buy_weapon(self.has_received_galaxy_weapon()) def set_magic(self, magic: MagicLogic): self.magic = magic @@ -35,33 +41,48 @@ def can_fight_at_level(self, level: str) -> StardewRule: if level == Performance.galaxy: return self.has_galaxy_weapon() | self.magic.has_amazing_spells() if level == Performance.maximum: - return self.has_galaxy_weapon() | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP + return self.has_galaxy_weapon() | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP def has_any_weapon(self) -> StardewRule: - higher_weapon_rule = self.has_decent_weapon() - this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups) - return higher_weapon_rule | this_weapon_rule + return self.has_any_weapon_rule def has_decent_weapon(self) -> StardewRule: - higher_weapon_rule = self.has_good_weapon() - this_weapon_rule = self.received(item.name for item in all_items - if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) - return (higher_weapon_rule | this_weapon_rule) & self.received("Adventurer's Guild") + return self.has_decent_weapon_rule def has_good_weapon(self) -> StardewRule: - higher_weapon_rule = self.has_great_weapon() - this_weapon_rule = self.received(item.name for item in all_items - if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) - return (higher_weapon_rule | this_weapon_rule) & self.received("Adventurer's Guild") + return self.has_good_weapon_rule def has_great_weapon(self) -> StardewRule: - higher_weapon_rule = self.has_galaxy_weapon() - this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) - return (higher_weapon_rule | this_weapon_rule) & self.received("Adventurer's Guild") + return self.has_great_weapon_rule def has_galaxy_weapon(self) -> StardewRule: - this_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) - return this_weapon_rule & self.received("Adventurer's Guild") + return self.has_galaxy_weapon_rule + + def has_received_any_weapon(self) -> StardewRule: + return self.received(item.name for item in all_items if Group.WEAPON in item.groups) + + def has_received_decent_weapon(self) -> StardewRule: + decent_weapon_rule = self.received(item.name for item in all_items + if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) + return decent_weapon_rule | self.has_received_good_weapon() + + def has_received_good_weapon(self) -> StardewRule: + good_weapon_rule = self.received(item.name for item in all_items + if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) + return good_weapon_rule | self.has_received_great_weapon() + + def has_received_great_weapon(self) -> StardewRule: + great_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) + return great_weapon_rule | self.has_received_galaxy_weapon() + + def has_received_galaxy_weapon(self) -> StardewRule: + return self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) + + def can_buy_weapon(self, weapon_rule: StardewRule = None) -> StardewRule: + adventure_guild_rule = self.region.can_reach(Region.adventurer_guild) + if weapon_rule is None: + return adventure_guild_rule + return adventure_guild_rule & weapon_rule def can_kill_monster(self, monster: StardewMonster) -> StardewRule: region_rule = self.region.can_reach_any(monster.locations) @@ -75,4 +96,3 @@ def can_kill_any_monster(self, monsters: Iterable[StardewMonster]) -> StardewRul def can_kill_all_monsters(self, monsters: Iterable[StardewMonster]) -> StardewRule: rules = [self.can_kill_monster(monster) for monster in monsters] return And(rules) - diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 53293b3e274a..75d16f40dd10 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -649,8 +649,12 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: def can_complete_all_monster_slaying_goals(self) -> StardewRule: rules = [self.time.has_lived_max_months()] + exclude_island = self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true + island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west] for category in all_monsters_by_category: - rules.append(self.combat.can_kill_all_monsters(all_monsters_by_category[category])) + if exclude_island and all(monster.locations[0] in island_regions for monster in all_monsters_by_category[category]): + continue + rules.append(self.combat.can_kill_any_monster(all_monsters_by_category[category])) return And(rules) diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 2f1b73b03bd2..0a4d91422f3a 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -19,29 +19,44 @@ def __init__(self, player: int, season_option: int, received_logic: ReceivedLogi self.season_option = season_option self.received = received_logic self.time = time + self.has_season_rules = { + Generic.any: True_() + } + self.has_any_season_rules = {} + self.has_all_season_rules = {} + self.has_any_not_winter_rule = self.has_any([Season.spring, Season.summer, Season.fall]) def has(self, season: str) -> StardewRule: - if season == Generic.any: - return True_() + if season in self.has_season_rules: + return self.has_season_rules[season] seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] if self.season_option == options.SeasonRandomization.option_progressive: - return self.received(Season.progressive, seasons_order.index(season)) - if self.season_option == options.SeasonRandomization.option_disabled: + self.has_season_rules[season] = self.received(Season.progressive, seasons_order.index(season)) + elif self.season_option == options.SeasonRandomization.option_disabled: if season == Season.spring: - return True_() - return self.time.has_lived_months(1) - return self.received(season) + self.has_season_rules[season] = True_() + else: + self.has_season_rules[season] = self.time.has_lived_months(1) + else: + self.has_season_rules[season] = self.received(season) + return self.has_season_rules[season] def has_any(self, seasons: Iterable[str]): if not seasons: return True_() - return Or([self.has(season) for season in seasons]) + key = ",".join(seasons) + if key not in self.has_any_season_rules: + self.has_any_season_rules[key] = Or([self.has(season) for season in seasons]) + return self.has_any_season_rules[key] def has_any_not_winter(self): - return self.has_any([Season.spring, Season.summer, Season.fall]) + return self.has_any_not_winter_rule def has_all(self, seasons: Iterable[str]): if not seasons: return True_() - return And([self.has(season) for season in seasons]) + key = ",".join(seasons) + if key not in self.has_all_season_rules: + self.has_all_season_rules[key] = And([self.has(season) for season in seasons]) + return self.has_all_season_rules[key] diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 96afd58ae060..1eac0984a094 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -34,10 +34,11 @@ def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOptions, logic: StardewLogic, current_bundles: Dict[str, Bundle]): all_location_names = list(location.name for location in multi_world.get_locations(player)) - + # 22.756 - 23.789 set_entrance_rules(logic, multi_world, player, world_options) - + # 34.761 - 35.568 set_ginger_island_rules(logic, multi_world, player, world_options) + # 36.281 - 38.453 set_tool_rules(logic, multiworld, player, world_options) set_skills_rules(logic, multiworld, player, world_options) @@ -52,14 +53,16 @@ def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOption set_friendsanity_rules(all_location_names, logic, multiworld, player) set_backpack_rules(logic, multiworld, player, world_options) set_festival_rules(all_location_names, logic, multiworld, player) - set_monstersanity_rules(all_location_names, logic, multiworld, player, world_options) - set_isolated_locations_rules(logic, multiworld, player) set_traveling_merchant_rules(logic, multiworld, player) set_arcade_machine_rules(logic, multiworld, player, world_options) set_deepwoods_rules(logic, multiworld, player, world_options) set_magic_spell_rules(logic, multiworld, player, world_options) + # 1min52 - 1min53 # These times are for TestOptions + # 1min36 - 1min38 # After the combat not duplicating a bunch of stuff + # 1min28 - 1min30 # with the caching of combat rules + # 1min25 - 1min26 # after caching seasons def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 9c96de00d333..119794ceab89 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -190,7 +190,8 @@ def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: Star self._simplified = False def __call__(self, state: CollectionState) -> bool: - return all(rule(state) for rule in self.rules) + result = all(rule(state) for rule in self.rules) + return result def __repr__(self): return f"({' & '.join(repr(rule) for rule in self.rules)})" From 6c96eb513c299fcd4afe6d8abacdc09c2a96d34a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 8 Aug 2023 19:22:40 -0400 Subject: [PATCH 032/482] -commit for historic reason on flatten rules --- worlds/stardew_valley/stardew_rule.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 119794ceab89..3dad59cfb214 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -8,6 +8,11 @@ MISSING_ITEM = "THIS ITEM IS MISSING" +should_do_complex_flatten_init = False +should_do_simple_flatten_init = True +should_do_complex_flatten_simplify = False +should_do_simple_flatten_simplify = False + class StardewRule: def __call__(self, state: CollectionState) -> bool: @@ -293,7 +298,7 @@ def __init__(self, count: int, items: Union[str, Iterable[str]], player: int): assert items_list, "Can't create a Total Received conditions without items" for item in items_list: assert item_table[item].classification & ItemClassification.progression, \ - "Item has to be progression to be used in logic" + f"Item [{item_table[item].name}] has to be progression to be used in logic" self.player = player self.items = items_list From a58e26c8b1d56b857534fa54338213603de165d9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 11:02:32 -0400 Subject: [PATCH 033/482] - Changed many items from progression to useful - Fix rules issue with volcano exit shortcut and island south - Disabled simplifying the rules as it apparently improves performance --- worlds/stardew_valley/__init__.py | 9 +- worlds/stardew_valley/data/items.csv | 28 +-- worlds/stardew_valley/items.py | 209 ++++++++++++------ worlds/stardew_valley/logic/logic.py | 2 +- .../logic/relationship_logic.py | 3 +- worlds/stardew_valley/rules.py | 6 +- worlds/stardew_valley/stardew_rule.py | 13 +- 7 files changed, 177 insertions(+), 93 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index d95f97b05d93..03b3d4e0b5bd 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -221,13 +221,16 @@ def setup_victory(self): self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player) - def create_item(self, item: Union[str, ItemData]) -> StardewItem: + def create_item(self, item: Union[str, ItemData], override_classification: ItemClassification = None) -> StardewItem: if isinstance(item, str): item = item_table[item] - if item.classification == ItemClassification.progression: + if override_classification is None: + override_classification = item.classification + + if override_classification == ItemClassification.progression: self.all_progression_items.add(item.name) - return StardewItem(item.name, item.classification, item.code, self.player) + return StardewItem(item.name, override_classification, item.code, self.player) def create_event_location(self, location_data: LocationData, rule: StardewRule = None, item: Optional[str] = None): if rule is None: diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 9042f1abb8aa..de3cbf812ba6 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -81,10 +81,10 @@ id,name,classification,groups,mod_name 93,Shipping Bin,progression,BUILDING, 94,Beach Bridge,progression,, 95,Adventurer's Guild,progression,, -96,Club Card,progression,, +96,Club Card,useful,, 97,Magnifying Glass,progression,, -98,Bear's Knowledge,progression,, -99,Iridium Snake Milk,progression,, +98,Bear's Knowledge,useful,, +99,Iridium Snake Milk,useful,, 100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, 101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, 102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, @@ -105,8 +105,8 @@ id,name,classification,groups,mod_name 117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, 118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, 119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, -120,Traveling Merchant Stock Size,progression,, -121,Traveling Merchant Discount,progression,, +120,Traveling Merchant Stock Size,useful,, +121,Traveling Merchant Discount,useful,, 122,Return Scepter,useful,, 123,Progressive Season,progression,, 124,Spring,progression,SEASON, @@ -223,18 +223,18 @@ id,name,classification,groups,mod_name 235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, 236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, 237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, -239,Sewing Machine,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +244,10 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", 251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", @@ -254,7 +254,7 @@ id,name,classification,groups,mod_name 267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -270,Volcano Exit Shortcut,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", 271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 53d5c3c859fd..7d7b665d8d5e 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -92,7 +92,7 @@ def has_any_group(self, *group: Group) -> bool: class StardewItemFactory(Protocol): - def __call__(self, name: Union[str, ItemData]) -> Item: + def __call__(self, name: Union[str, ItemData], override_classification: ItemClassification = None) -> Item: raise NotImplementedError @@ -149,7 +149,8 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t if item in unique_items: unique_items.remove(item) - assert len(unique_items) <= locations_count, f"There should be at least as many locations [{locations_count}] as there are mandatory items [{len(unique_items)}]" + assert len( + unique_items) <= locations_count, f"There should be at least as many locations [{locations_count}] as there are mandatory items [{len(unique_items)}]" items += unique_items logger.debug(f"Created {len(unique_items)} unique items") @@ -187,10 +188,10 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_player_buffs(item_factory, options, items) create_traveling_merchant_items(item_factory, items) items.append(item_factory("Return Scepter")) - create_seasons(item_factory, options, items) - create_seeds(item_factory, options, items) - create_friendsanity_items(item_factory, options, items) - create_festival_rewards(item_factory, options, items) + create_seasons(item_factory, world_options, items) + create_seeds(item_factory, world_options, items) + create_friendsanity_items(item_factory, world_options, items, random) + create_festival_rewards(item_factory, world_options, items) create_babies(item_factory, items, random) create_special_order_board_rewards(item_factory, options, items) create_special_order_qi_rewards(item_factory, options, items) @@ -235,53 +236,68 @@ def create_elevators(item_factory: StardewItemFactory, options: StardewValleyOpt def create_tools(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): if options.tool_progression == ToolProgression.option_progressive: - items.extend(item_factory(item) for item in items_by_group[Group.PROGRESSIVE_TOOLS] * 4) + for item_data in items_by_group[Group.PROGRESSIVE_TOOLS]: + name = item_data.name + if "Trash Can" in name: + items.extend([item_factory(item) for item in [item_data] * 3]) + items.append(item_factory(item_data, ItemClassification.useful)) + else: + items.extend([item_factory(item) for item in [item_data] * 4]) items.append(item_factory("Golden Scythe")) -def create_skills(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if options.skill_progression == SkillProgression.option_progressive: +def create_skills(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + needs_level_10 = world_is_perfection(world_options) or world_options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_disabled + if world_options[options.SkillProgression] == options.SkillProgression.option_progressive: for item in items_by_group[Group.SKILL_LEVEL_UP]: if item.mod_name not in options.mods and item.mod_name is not None: continue - items.extend(item_factory(item) for item in [item.name] * 10) + level_progression = 10 if needs_level_10 else 9 + level_useful = 10 - level_progression + items.extend(item_factory(item) for item in [item.name] * level_progression) + items.extend(item_factory(item, ItemClassification.useful) for item in [item.name] * level_useful) def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - items.append(item_factory("Earth Obelisk")) - items.append(item_factory("Water Obelisk")) + useless_buildings_classification = ItemClassification.progression_skip_balancing if world_is_perfection(world_options) else ItemClassification.useful + items.append(item_factory("Earth Obelisk", useless_buildings_classification)) + items.append(item_factory("Water Obelisk", useless_buildings_classification)) items.append(item_factory("Desert Obelisk")) items.append(item_factory("Junimo Hut")) - items.append(item_factory("Gold Clock")) + items.append(item_factory("Gold Clock", useless_buildings_classification)) if options.exclude_ginger_island == ExcludeGingerIsland.option_false: items.append(item_factory("Island Obelisk")) if ModNames.deepwoods in options.mods: items.append(item_factory("Woods Obelisk")) -def create_carpenter_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if options.building_progression in {BuildingProgression.option_progressive, - BuildingProgression.option_progressive_early_shipping_bin}: - items.append(item_factory("Progressive Coop")) - items.append(item_factory("Progressive Coop")) - items.append(item_factory("Progressive Coop")) - items.append(item_factory("Progressive Barn")) - items.append(item_factory("Progressive Barn")) - items.append(item_factory("Progressive Barn")) - items.append(item_factory("Well")) - items.append(item_factory("Silo")) - items.append(item_factory("Mill")) - items.append(item_factory("Progressive Shed")) - items.append(item_factory("Progressive Shed")) - items.append(item_factory("Fish Pond")) - items.append(item_factory("Stable")) - items.append(item_factory("Slime Hutch")) - items.append(item_factory("Shipping Bin")) - items.append(item_factory("Progressive House")) - items.append(item_factory("Progressive House")) - items.append(item_factory("Progressive House")) - if ModNames.tractor in options.mods: - items.append(item_factory("Tractor Garage")) +def create_carpenter_buildings(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + building_option = world_options[options.BuildingProgression] + if building_option == options.BuildingProgression.option_vanilla: + return + items.append(item_factory("Progressive Coop")) + items.append(item_factory("Progressive Coop")) + items.append(item_factory("Progressive Coop")) + items.append(item_factory("Progressive Barn")) + items.append(item_factory("Progressive Barn")) + items.append(item_factory("Progressive Barn")) + items.append(item_factory("Well")) + items.append(item_factory("Silo")) + items.append(item_factory("Mill")) + items.append(item_factory("Progressive Shed")) + items.append(item_factory("Progressive Shed", ItemClassification.useful)) + items.append(item_factory("Fish Pond")) + items.append(item_factory("Stable")) + items.append(item_factory("Slime Hutch")) + needs_early_bin = building_option == options.BuildingProgression.option_progressive_early_shipping_bin + has_shipsanity = world_options[options.Shipsanity] != options.Shipsanity.option_none + need_shipping = needs_early_bin or has_shipsanity or world_is_perfection(world_options) + items.append(item_factory("Shipping Bin", ItemClassification.progression if need_shipping else ItemClassification.useful)) + items.append(item_factory("Progressive House")) + items.append(item_factory("Progressive House")) + items.append(item_factory("Progressive House")) + if ModNames.tractor in world_options[options.Mods]: + items.append(item_factory("Tractor Garage")) def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[Item]): @@ -293,12 +309,13 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[I def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - items.append(item_factory("Stardrop")) # The Mines level 100 - items.append(item_factory("Stardrop")) # Old Master Cannoli + stardrops_classification = get_stardrop_classification(world_options) + items.append(item_factory("Stardrop", stardrops_classification)) # The Mines level 100 + items.append(item_factory("Stardrop", stardrops_classification)) # Old Master Cannoli if options.fishsanity != Fishsanity.option_none: - items.append(item_factory("Stardrop")) #Master Angler Stardrop + items.append(item_factory("Stardrop", stardrops_classification)) # Master Angler Stardrop if ModNames.deepwoods in options.mods: - items.append(item_factory("Stardrop")) # Petting the Unicorn + items.append(item_factory("Stardrop", stardrops_classification)) # Petting the Unicorn def create_museum_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -310,20 +327,25 @@ def create_museum_items(item_factory: StardewItemFactory, options: StardewValley items.extend(item_factory(item) for item in ["Magic Rock Candy"] * 10) items.extend(item_factory(item) for item in ["Ancient Seeds"] * 5) items.extend(item_factory(item) for item in ["Traveling Merchant Metal Detector"] * 4) - items.append(item_factory("Stardrop")) + items.append(item_factory("Stardrop", get_stardrop_classification(world_options))) -def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if options.friendsanity == Friendsanity.option_none: +def create_friendsanity_items(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item], random): + if world_options[options.Friendsanity] == options.Friendsanity.option_none: return - exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors - exclude_locked_villagers = options.friendsanity == Friendsanity.option_starting_npcs or \ - options.friendsanity == Friendsanity.option_bachelors - include_post_marriage_hearts = options.friendsanity == Friendsanity.option_all_with_marriage - exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true - heart_size = options.friendsanity_heart_size + exclude_non_bachelors = world_options[options.Friendsanity] == options.Friendsanity.option_bachelors + exclude_locked_villagers = world_options[options.Friendsanity] == options.Friendsanity.option_starting_npcs or \ + world_options[options.Friendsanity] == options.Friendsanity.option_bachelors + include_post_marriage_hearts = world_options[options.Friendsanity] == options.Friendsanity.option_all_with_marriage + exclude_ginger_island = world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true + mods = world_options[options.Mods] + heart_size = world_options[options.FriendsanityHeartSize] + need_all_hearts_up_to_date = world_is_perfection(world_options) + government_assigned_bachelor = random.choice([villager.name for villager in all_villagers if villager.bachelor and + (villager.mod_name is None or villager.mod_name in mods)]) + need_recipes = world_options[options.Shipsanity] == options.Shipsanity.option_everything or world_options[options.Shipsanity] == options.Shipsanity.option_quality_everything for villager in all_villagers: - if villager.mod_name not in options.mods and villager.mod_name is not None: + if villager.mod_name not in mods and villager.mod_name is not None: continue if not villager.available and exclude_locked_villagers: continue @@ -334,15 +356,35 @@ def create_friendsanity_items(item_factory: StardewItemFactory, options: Stardew heart_cap = 8 if villager.bachelor else 10 if include_post_marriage_hearts and villager.bachelor: heart_cap = 14 + classification = ItemClassification.progression for heart in range(1, 15): if heart > heart_cap: break if heart % heart_size == 0 or heart == heart_cap: - items.append(item_factory(f"{villager.name} <3")) + items.append(item_factory(f"{villager.name} <3", classification)) + if should_next_hearts_be_useful(need_all_hearts_up_to_date, government_assigned_bachelor, need_recipes, + villager, heart, heart_size, heart_cap): + classification = ItemClassification.useful if not exclude_non_bachelors: + need_pet = world_options[options.Goal] == options.Goal.option_grandpa_evaluation for heart in range(1, 6): if heart % heart_size == 0 or heart == 5: - items.append(item_factory(f"Pet <3")) + items.append(item_factory(f"Pet <3", ItemClassification.progression_skip_balancing if need_pet else ItemClassification.useful)) + + +def should_next_hearts_be_useful(need_all_hearts_up_to_date: bool, government_assigned_bachelor: str, need_recipes: bool, villager, heart: int, + heart_size: int, heart_cap: int) -> bool: + if heart + heart_size < heart_cap: # If the next heart isn't the last one, it has to be progression + return False + if villager.name == government_assigned_bachelor: + return False + if need_all_hearts_up_to_date and (heart <= 8 or (heart <= 10 and not villager.bachelor)): + return False + if need_recipes and heart <= 7: + return False + if need_recipes and villager.name == "Willy": + return False + return True def create_babies(item_factory: StardewItemFactory, items: List[Item], random: Random): @@ -369,9 +411,20 @@ def create_arcade_machine_items(item_factory: StardewItemFactory, options: Stard items.extend(item_factory(item) for item in ["Junimo Kart: Extra Life"] * 8) -def create_player_buffs(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - items.extend(item_factory(item) for item in [Buff.movement] * options.movement_buff_number.value) - items.extend(item_factory(item) for item in [Buff.luck] * options.luck_buff_number.value) +def create_player_buffs(item_factory: StardewItemFactory, world_options: options.StardewOptions, items: List[Item]): + movement_buffs: int = world_options[options.NumberOfMovementBuffs] + luck_buffs: int = world_options[options.NumberOfLuckBuffs] + need_all_buffs = world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_qi + need_half_buffs = world_options[options.FestivalLocations] == options.FestivalLocations.option_easy + create_player_buff(item_factory, Buff.movement, movement_buffs, need_all_buffs, need_half_buffs, items) + create_player_buff(item_factory, Buff.luck, luck_buffs, need_all_buffs, need_half_buffs, items) + + +def create_player_buff(item_factory, buff: str, amount: int, need_all_buffs: bool, need_half_buffs: bool, items: List[Item]): + progression_buffs = amount if need_all_buffs else (amount // 2 if need_half_buffs else 0) + useful_buffs = amount - progression_buffs + items.extend(item_factory(item) for item in [buff] * progression_buffs) + items.extend(item_factory(item, ItemClassification.useful) for item in [buff] * useful_buffs) def create_traveling_merchant_items(item_factory: StardewItemFactory, items: List[Item]): @@ -404,8 +457,8 @@ def create_festival_rewards(item_factory: StardewItemFactory, options: StardewVa if options.festival_locations == FestivalLocations.option_disabled: return - items.extend([*[item_factory(item) for item in items_by_group[Group.FESTIVAL] if item.classification != ItemClassification.filler], - item_factory("Stardrop")]) + festival_rewards = [item_factory(item) for item in items_by_group[Group.FESTIVAL] if item.classification != ItemClassification.filler] + items.extend([*festival_rewards, item_factory("Stardrop", get_stardrop_classification(world_options))]) def create_walnut_purchase_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -419,17 +472,30 @@ def create_walnut_purchase_rewards(item_factory: StardewItemFactory, options: St *[item_factory(item) for item in items_by_group[Group.WALNUT_PURCHASE]]]) - def create_special_order_board_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): if options.special_order_locations == SpecialOrderLocations.option_disabled: return + need_all_recipes = world_is_perfection(world_options) + items_and_classifications = {item: (special_order_board_item_classification(item, need_all_recipes)) for item in items_by_group[Group.SPECIAL_ORDER_BOARD]} - items.extend([item_factory(item) for item in items_by_group[Group.SPECIAL_ORDER_BOARD]]) + items.extend([item_factory(item, items_and_classifications[item]) for item in items_and_classifications]) -def create_special_order_qi_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if (options.special_order_locations != SpecialOrderLocations.option_board_qi or - options.exclude_ginger_island == ExcludeGingerIsland.option_true): +def special_order_board_item_classification(item: ItemData, need_all_recipes: bool) -> ItemClassification: + if item.classification is ItemClassification.useful: + return ItemClassification.useful + if item.name == "Special Order Board": + return ItemClassification.progression + if need_all_recipes and "Recipe" in item.name: + return ItemClassification.progression_skip_balancing + if item.name == "Monster Musk Recipe": + return ItemClassification.progression_skip_balancing + return ItemClassification.useful + + +def create_special_order_qi_rewards(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + if (world_options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_board_qi or + world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true): return qi_gem_rewards = ["100 Qi Gems", "10 Qi Gems", "40 Qi Gems", "25 Qi Gems", "25 Qi Gems", "40 Qi Gems", "20 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems"] @@ -490,11 +556,13 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options required_resource_pack = number_locations - len(items_already_added) if required_resource_pack < number_priority_items: chosen_priority_items = [item_factory(resource_pack) for resource_pack in - random.sample(priority_filler_items, required_resource_pack)] + random.sample(priority_filler_items, required_resource_pack)] return chosen_priority_items items = [] - chosen_priority_items = [item_factory(resource_pack) for resource_pack in priority_filler_items] + chosen_priority_items = [item_factory(resource_pack, + ItemClassification.trap if resource_pack.classification == ItemClassification.trap else ItemClassification.useful) + for resource_pack in priority_filler_items] items.extend(chosen_priority_items) required_resource_pack -= number_priority_items all_filler_packs = [filler_pack for filler_pack in all_filler_packs @@ -507,10 +575,11 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options while exactly_2 and required_resource_pack == 1: resource_pack = random.choice(all_filler_packs) exactly_2 = Group.EXACTLY_TWO in resource_pack.groups - items.append(item_factory(resource_pack)) + classification = ItemClassification.useful if resource_pack.classification == ItemClassification.progression else resource_pack.classification + items.append(item_factory(resource_pack, classification)) required_resource_pack -= 1 if exactly_2: - items.append(item_factory(resource_pack)) + items.append(item_factory(resource_pack, classification)) required_resource_pack -= 1 if exactly_2 or Group.MAXIMUM_ONE in resource_pack.groups: all_filler_packs.remove(resource_pack) @@ -536,3 +605,11 @@ def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool): all_filler_packs.extend(items_by_group[Group.TRAP]) all_filler_packs = remove_excluded_packs(all_filler_packs, exclude_ginger_island) return all_filler_packs + + +def get_stardrop_classification(world_options) -> ItemClassification: + return ItemClassification.progression_skip_balancing if world_is_perfection(world_options) else ItemClassification.useful + + +def world_is_perfection(world_options) -> bool: + return world_options[options.Goal] == options.Goal.option_perfection diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 75d16f40dd10..9d7019e35caa 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -259,7 +259,7 @@ def __post_init__(self): Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), WaterItem.green_algae: self.fishing.can_fish_in_freshwater(), ArtisanGood.green_tea: self.artisan.can_keg(Vegetable.tea_leaves), - Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_south)), + Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_west)), Forageable.hay: self.buildings.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), Forageable.hazelnut: self.tool.can_forage(Season.fall), Forageable.holly: self.tool.can_forage(Season.winter), diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 7b1da6b01bba..e9542f00f3eb 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -56,7 +56,8 @@ def has_children(self, number_children: int) -> StardewRule: def can_reproduce(self, number_children: int = 1) -> StardewRule: if number_children <= 0: return True_() - return self.can_get_married() & self.buildings.has_house(2) & self.has_hearts(Generic.bachelor, 12) & self.has_children(number_children - 1) + baby_rules = [self.can_get_married(), self.buildings.has_house(2), self.has_hearts(Generic.bachelor, 12), self.has_children(number_children - 1)] + return And(baby_rules) def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 1eac0984a094..c7d661c20b4a 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -63,6 +63,10 @@ def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOption # 1min36 - 1min38 # After the combat not duplicating a bunch of stuff # 1min28 - 1min30 # with the caching of combat rules # 1min25 - 1min26 # after caching seasons + # 1min19 - 1min25 # moved some progression items to useful + # 1min30 - 1min32 # with the flattening + # 1min25 - 1min36 # with zero flattening + # 1min36 - 1min40 # with complex flattening only in simplify def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): @@ -380,7 +384,7 @@ def set_island_entrances_rules(logic: StardewLogic, multi_world, player): MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_volcano_dwarf, player), logic.wallet.can_speak_dwarf()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.climb_to_volcano_10, player), - (logic.ability.can_mine_perfectly() & logic.tool.can_water(1) & logic.received("Volcano Exit Shortcut")).simplify()) + (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_docks_to_dig_site, Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_volcano_to_dig_site, diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 3dad59cfb214..a47c460ac2d2 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -8,11 +8,6 @@ MISSING_ITEM = "THIS ITEM IS MISSING" -should_do_complex_flatten_init = False -should_do_simple_flatten_init = True -should_do_complex_flatten_simplify = False -should_do_simple_flatten_simplify = False - class StardewRule: def __call__(self, state: CollectionState) -> bool: @@ -194,6 +189,8 @@ def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: Star self.rules = frozenset(rules_list) self._simplified = False + self.rules = frozenset(rules_list) + def __call__(self, state: CollectionState) -> bool: result = all(rule(state) for rule in self.rules) return result @@ -279,7 +276,8 @@ def get_difficulty(self): return max(rule.get_difficulty() for rule in easiest_n_rules) def simplify(self): - return Count(self.count, [rule.simplify() for rule in self.rules]) + return self + # return Count(self.count, [rule.simplify() for rule in self.rules]) class TotalReceived(StardewRule): @@ -387,4 +385,5 @@ def __hash__(self): return hash(self.item) def simplify(self) -> StardewRule: - return self.other_rules[self.item].simplify() + return self + # return self.other_rules[self.item].simplify() From 870ddb2e2d2bc047887496b9ee7349dc038c8fd2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 11:12:25 -0400 Subject: [PATCH 034/482] - Comment out the logic simplification tests since I disabled simplify --- Utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils.py b/Utils.py index f6e4a9ab6052..362335318269 100644 --- a/Utils.py +++ b/Utils.py @@ -138,7 +138,7 @@ def local_path(*path: str) -> str: local_path.cached_path = os.path.dirname(os.path.abspath(sys.argv[0])) else: import __main__ - if hasattr(__main__, "__file__") and os.path.isfile(__main__.__file__): + if False: # we are running in a normal Python environment local_path.cached_path = os.path.dirname(os.path.abspath(__main__.__file__)) else: From 32534d897b882c984e0820eead71ab7045ac88de Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 11:13:10 -0400 Subject: [PATCH 035/482] - Reverted Utils.py --- Utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils.py b/Utils.py index 362335318269..f6e4a9ab6052 100644 --- a/Utils.py +++ b/Utils.py @@ -138,7 +138,7 @@ def local_path(*path: str) -> str: local_path.cached_path = os.path.dirname(os.path.abspath(sys.argv[0])) else: import __main__ - if False: + if hasattr(__main__, "__file__") and os.path.isfile(__main__.__file__): # we are running in a normal Python environment local_path.cached_path = os.path.dirname(os.path.abspath(__main__.__file__)) else: From 5906c8bfecd03499ca232179d0151c71a663b034 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 16:33:38 -0400 Subject: [PATCH 036/482] - Made the weapons progressive --- worlds/stardew_valley/data/items.csv | 79 ++++---- worlds/stardew_valley/items.py | 63 ++++--- worlds/stardew_valley/logic/combat_logic.py | 19 +- worlds/stardew_valley/logic/logic.py | 4 +- worlds/stardew_valley/stardew_rule.py | 8 - .../strings/ap_names/ap_weapon_names.py | 7 + worlds/stardew_valley/strings/weapon_names.py | 1 - worlds/stardew_valley/test/TestGeneration.py | 171 ++++++++++++++---- worlds/stardew_valley/test/TestItems.py | 7 + worlds/stardew_valley/test/TestOptions.py | 5 +- worlds/stardew_valley/test/TestRules.py | 30 +-- 11 files changed, 246 insertions(+), 148 deletions(-) create mode 100644 worlds/stardew_valley/strings/ap_names/ap_weapon_names.py diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index de3cbf812ba6..8e62d0f0af34 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -10,45 +10,42 @@ id,name,classification,groups,mod_name 22,Movie Theater,useful,, 23,Stardrop,progression,, 24,Progressive Backpack,progression,, -25,Rusty Sword,progression,WEAPON, -26,Leather Boots,progression,"FOOTWEAR,MINES_FLOOR_10", -27,Work Boots,useful,"FOOTWEAR,MINES_FLOOR_10", -28,Wooden Blade,progression,"MINES_FLOOR_10,WEAPON", -29,Iron Dirk,progression,"MINES_FLOOR_10,WEAPON", -30,Wind Spire,progression,"MINES_FLOOR_10,WEAPON", -31,Femur,progression,"MINES_FLOOR_10,WEAPON", -32,Steel Smallsword,progression,"MINES_FLOOR_20,WEAPON", -33,Wood Club,progression,"MINES_FLOOR_20,WEAPON", -34,Elf Blade,progression,"MINES_FLOOR_20,WEAPON", -35,Glow Ring,useful,"MINES_FLOOR_20,RING", -36,Magnet Ring,useful,"MINES_FLOOR_20,RING", -37,Slingshot,progression,WEAPON, -38,Tundra Boots,useful,"FOOTWEAR,MINES_FLOOR_50", -39,Thermal Boots,useful,"FOOTWEAR,MINES_FLOOR_50", -40,Combat Boots,useful,"FOOTWEAR,MINES_FLOOR_50", -41,Silver Saber,progression,"MINES_FLOOR_50,WEAPON", -42,Pirate's Sword,progression,"MINES_FLOOR_50,WEAPON", -43,Crystal Dagger,progression,"MINES_FLOOR_60,WEAPON", -44,Cutlass,progression,"MINES_FLOOR_60,WEAPON", -45,Iron Edge,progression,"MINES_FLOOR_60,WEAPON", -46,Burglar's Shank,progression,"MINES_FLOOR_60,WEAPON", -47,Wood Mallet,progression,"MINES_FLOOR_60,WEAPON", -48,Master Slingshot,progression,WEAPON, -49,Firewalker Boots,useful,"FOOTWEAR,MINES_FLOOR_80", -50,Dark Boots,useful,"FOOTWEAR,MINES_FLOOR_80", -51,Claymore,progression,"MINES_FLOOR_80,WEAPON", -52,Templar's Blade,progression,"MINES_FLOOR_80,WEAPON", -53,Kudgel,progression,"MINES_FLOOR_80,WEAPON", -54,Shadow Dagger,progression,"MINES_FLOOR_80,WEAPON", -55,Obsidian Edge,progression,"MINES_FLOOR_90,WEAPON", -56,Tempered Broadsword,progression,"MINES_FLOOR_90,WEAPON", -57,Wicked Kris,progression,"MINES_FLOOR_90,WEAPON", -58,Bone Sword,progression,"MINES_FLOOR_90,WEAPON", -59,Ossified Blade,progression,"MINES_FLOOR_90,WEAPON", -60,Space Boots,useful,"FOOTWEAR,MINES_FLOOR_110", -61,Crystal Shoes,useful,"FOOTWEAR,MINES_FLOOR_110", -62,Steel Falchion,progression,"MINES_FLOOR_110,WEAPON", -63,The Slammer,progression,"MINES_FLOOR_110,WEAPON", +25,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +26,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +27,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +28,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +29,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +30,Progressive Footwear,useful,"FOOTWEAR", +31,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +32,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +33,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +34,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +35,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +36,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +37,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +38,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +39,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +40,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +41,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +42,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +43,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +44,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +45,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +46,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +47,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +48,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +49,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +50,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +51,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +52,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +53,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +54,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +55,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +56,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +57,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +58,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +59,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +60,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 64,Skull Key,progression,, 65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, 66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, @@ -91,12 +88,8 @@ id,name,classification,groups,mod_name 103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, 104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, 105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, -106,Galaxy Sword,progression,"GALAXY_WEAPONS,WEAPON", -107,Galaxy Dagger,progression,"GALAXY_WEAPONS,WEAPON", -108,Galaxy Hammer,progression,"GALAXY_WEAPONS,WEAPON", 109,Movement Speed Bonus,progression,, 110,Luck Bonus,progression,, -111,Lava Katana,progression,"MINES_FLOOR_110,WEAPON", 112,Progressive House,progression,, 113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, 114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 7d7b665d8d5e..402beb050038 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -12,6 +12,7 @@ from .mods.mod_data import ModNames from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, Friendsanity, Museumsanity, \ Fishsanity, BuildingProgression, SkillProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations +from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff ITEM_CODE_OFFSET = 717000 @@ -25,23 +26,20 @@ class Group(enum.Enum): FRIENDSHIP_PACK = enum.auto() COMMUNITY_REWARD = enum.auto() TRASH = enum.auto() - MINES_FLOOR_10 = enum.auto() - MINES_FLOOR_20 = enum.auto() - MINES_FLOOR_50 = enum.auto() - MINES_FLOOR_60 = enum.auto() - MINES_FLOOR_80 = enum.auto() - MINES_FLOOR_90 = enum.auto() - MINES_FLOOR_110 = enum.auto() FOOTWEAR = enum.auto() HATS = enum.auto() RING = enum.auto() WEAPON = enum.auto() + WEAPON_GENERIC = enum.auto() + WEAPON_SWORD = enum.auto() + WEAPON_CLUB = enum.auto() + WEAPON_DAGGER = enum.auto() + WEAPON_SLINGSHOT = enum.auto() PROGRESSIVE_TOOLS = enum.auto() SKILL_LEVEL_UP = enum.auto() BUILDING = enum.auto() WIZARD_BUILDING = enum.auto() ARCADE_MACHINE_BUFFS = enum.auto() - GALAXY_WEAPONS = enum.auto() BASE_RESOURCE = enum.auto() WARP_TOTEM = enum.auto() GEODE = enum.auto() @@ -171,7 +169,8 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items.extend(item_factory(item) for item in items_by_group[Group.COMMUNITY_REWARD]) create_backpack_items(item_factory, options, items) - create_mine_rewards(item_factory, items, random) + create_weapons(item_factory, world_options, items) + items.append(item_factory("Skull Key")) create_elevators(item_factory, options, items) create_tools(item_factory, options, items) create_skills(item_factory, options, items) @@ -184,7 +183,6 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_stardrops(item_factory, options, items) create_museum_items(item_factory, options, items) create_arcade_machine_items(item_factory, options, items) - items.append(item_factory(random.choice(items_by_group[Group.GALAXY_WEAPONS]))) create_player_buffs(item_factory, options, items) create_traveling_merchant_items(item_factory, items) items.append(item_factory("Return Scepter")) @@ -209,22 +207,31 @@ def create_backpack_items(item_factory: StardewItemFactory, options: StardewVall items.append(item_factory("Progressive Backpack")) -def create_mine_rewards(item_factory: StardewItemFactory, items: List[Item], random: Random): - items.append(item_factory("Rusty Sword")) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_10]))) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_20]))) - items.append(item_factory("Slingshot")) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_50]))) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_60]))) - items.append(item_factory("Master Slingshot")) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_80]))) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_90]))) - items.append(item_factory(random.choice(items_by_group[Group.MINES_FLOOR_110]))) - items.append(item_factory("Skull Key")) +def create_weapons(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + items.extend(item_factory(item) for item in [APWeapon.slingshot] * 2) + monstersanity = options.Monstersanity + monstersanity_option = world_options[monstersanity] + if monstersanity_option == options.Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons + items.extend(item_factory(item) for item in [APWeapon.weapon] * 5) + items.extend(item_factory(item) for item in [APWeapon.footwear] * 3) # 1-2 | 3-4 | 6-7-8 + return + + items.extend(item_factory(item) for item in [APWeapon.sword] * 5) + items.extend(item_factory(item) for item in [APWeapon.club] * 5) + items.extend(item_factory(item) for item in [APWeapon.dagger] * 5) + items.extend(item_factory(item) for item in [APWeapon.footwear] * 4) # 1-2 | 3-4 | 6-7-8 | 11-13 + if monstersanity_option == monstersanity.option_goals or monstersanity_option == monstersanity.option_one_per_category or \ + monstersanity_option == monstersanity.option_short_goals or monstersanity_option == monstersanity.option_very_short_goals: + return + if world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + rings_items = [item for item in items_by_group[Group.RING] if item.classification is not ItemClassification.filler] + else: + rings_items = [item for item in items_by_group[Group.RING]] + items.extend(item_factory(item) for item in rings_items) -def create_elevators(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if options.elevator_progression == ElevatorProgression.option_vanilla: +def create_elevators(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + if world_options[options.ElevatorProgression] == options.ElevatorProgression.option_vanilla: return items.extend([item_factory(item) for item in ["Progressive Mine Elevator"] * 24]) @@ -343,7 +350,8 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S need_all_hearts_up_to_date = world_is_perfection(world_options) government_assigned_bachelor = random.choice([villager.name for villager in all_villagers if villager.bachelor and (villager.mod_name is None or villager.mod_name in mods)]) - need_recipes = world_options[options.Shipsanity] == options.Shipsanity.option_everything or world_options[options.Shipsanity] == options.Shipsanity.option_quality_everything + need_recipes = world_options[options.Shipsanity] == options.Shipsanity.option_everything or world_options[ + options.Shipsanity] == options.Shipsanity.option_quality_everything for villager in all_villagers: if villager.mod_name not in mods and villager.mod_name is not None: continue @@ -363,7 +371,7 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S if heart % heart_size == 0 or heart == heart_cap: items.append(item_factory(f"{villager.name} <3", classification)) if should_next_hearts_be_useful(need_all_hearts_up_to_date, government_assigned_bachelor, need_recipes, - villager, heart, heart_size, heart_cap): + villager, heart, heart_size, heart_cap): classification = ItemClassification.useful if not exclude_non_bachelors: need_pet = world_options[options.Goal] == options.Goal.option_grandpa_evaluation @@ -567,7 +575,8 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options required_resource_pack -= number_priority_items all_filler_packs = [filler_pack for filler_pack in all_filler_packs if Group.MAXIMUM_ONE not in filler_pack.groups or - filler_pack.name not in [priority_item.name for priority_item in priority_filler_items]] + (filler_pack.name not in [priority_item.name for priority_item in + priority_filler_items] and filler_pack.name not in items_already_added_names)] while required_resource_pack > 0: resource_pack = random.choice(all_filler_packs) diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index f0a0d558d5b5..42f25a7abaea 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -5,10 +5,12 @@ from ..data.monster_data import StardewMonster from ..mods.logic.magic_logic import MagicLogic from ..stardew_rule import StardewRule, Or, And +from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.performance_names import Performance -from ..items import all_items, Group from ..strings.region_names import Region +valid_weapons = [APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger] + class CombatLogic: player: int @@ -59,24 +61,19 @@ def has_galaxy_weapon(self) -> StardewRule: return self.has_galaxy_weapon_rule def has_received_any_weapon(self) -> StardewRule: - return self.received(item.name for item in all_items if Group.WEAPON in item.groups) + return self.received(valid_weapons, 1) def has_received_decent_weapon(self) -> StardewRule: - decent_weapon_rule = self.received(item.name for item in all_items - if Group.WEAPON in item.groups and (Group.MINES_FLOOR_50 in item.groups or Group.MINES_FLOOR_60 in item.groups)) - return decent_weapon_rule | self.has_received_good_weapon() + return Or(self.received(weapon, 2) for weapon in valid_weapons) def has_received_good_weapon(self) -> StardewRule: - good_weapon_rule = self.received(item.name for item in all_items - if Group.WEAPON in item.groups and (Group.MINES_FLOOR_80 in item.groups or Group.MINES_FLOOR_90 in item.groups)) - return good_weapon_rule | self.has_received_great_weapon() + return Or(self.received(weapon, 3) for weapon in valid_weapons) def has_received_great_weapon(self) -> StardewRule: - great_weapon_rule = self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.MINES_FLOOR_110 in item.groups) - return great_weapon_rule | self.has_received_galaxy_weapon() + return Or(self.received(weapon, 4) for weapon in valid_weapons) def has_received_galaxy_weapon(self) -> StardewRule: - return self.received(item.name for item in all_items if Group.WEAPON in item.groups and Group.GALAXY_WEAPONS in item.groups) + return Or(self.received(weapon, 5) for weapon in valid_weapons) def can_buy_weapon(self, weapon_rule: StardewRule = None) -> StardewRule: adventure_guild_rule = self.region.can_reach(Region.adventurer_guild) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9d7019e35caa..8a628da02053 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -40,6 +40,7 @@ from ..stardew_rule import False_, Or, True_, Count, And, Has, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals from ..strings.animal_product_names import AnimalProduct +from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.ap_names.buff_names import Buff from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building @@ -354,7 +355,6 @@ def __post_init__(self): Animal.sheep: self.can_buy_animal(Animal.sheep), Fish.shrimp: self.skill.can_crab_pot(Region.beach), Loot.slime: self.mine.can_mine_in_the_mines_floor_1_40(), - Weapon.any_slingshot: self.received(Weapon.slingshot) | self.received(Weapon.master_slingshot), Fish.snail: self.skill.can_crab_pot(Region.town), Forageable.snow_yam: self.tool.can_forage(Season.winter, Region.beach, True), Trash.soggy_newspaper: self.skill.can_crab_pot(), @@ -781,7 +781,7 @@ def has_walnut(self, number: int) -> StardewRule: reach_caves = And(self.region.can_reach(Region.qi_walnut_room), self.region.can_reach(Region.dig_site), self.region.can_reach(Region.gourmand_frog_cave), self.region.can_reach(Region.colored_crystals_cave), - self.region.can_reach(Region.shipwreck), self.has(Weapon.any_slingshot)) + self.region.can_reach(Region.shipwreck), self.received(APWeapon.slingshot)) reach_entire_island = And(reach_outside_areas, reach_all_volcano, reach_caves, reach_southeast, reach_pirate_cove) if number <= 5: diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index a47c460ac2d2..016791cae7ab 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -336,14 +336,6 @@ def __repr__(self): return f"Received {self.count} {self.item}" def get_difficulty(self): - if self.item == "Spring": - return 0 - if self.item == "Summer": - return 1 - if self.item == "Fall": - return 2 - if self.item == "Winter": - return 3 return self.count diff --git a/worlds/stardew_valley/strings/ap_names/ap_weapon_names.py b/worlds/stardew_valley/strings/ap_names/ap_weapon_names.py new file mode 100644 index 000000000000..7fcd6873761c --- /dev/null +++ b/worlds/stardew_valley/strings/ap_names/ap_weapon_names.py @@ -0,0 +1,7 @@ +class APWeapon: + weapon = "Progressive Weapon" + sword = "Progressive Sword" + club = "Progressive Club" + dagger = "Progressive Dagger" + slingshot = "Progressive Slingshot" + footwear = "Progressive Footwear" diff --git a/worlds/stardew_valley/strings/weapon_names.py b/worlds/stardew_valley/strings/weapon_names.py index 009cd6df0d6f..1c3e508cfa99 100644 --- a/worlds/stardew_valley/strings/weapon_names.py +++ b/worlds/stardew_valley/strings/weapon_names.py @@ -1,4 +1,3 @@ class Weapon: slingshot = "Slingshot" master_slingshot = "Master Slingshot" - any_slingshot = "Any Slingshot" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 5f7e001913f8..e740600f58d2 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -1,6 +1,6 @@ -import typing +from typing import List -from BaseClasses import ItemClassification, MultiWorld +from BaseClasses import ItemClassification, MultiWorld, Item from . import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_with_mods, \ allsanity_options_without_mods, minimal_locations_maximal_items from .. import locations, items, location_table, options @@ -32,7 +32,6 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) - items_to_ignore.extend(footwear.name for footwear in items.items_by_group[Group.FOOTWEAR]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression @@ -81,7 +80,6 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.WEAPON]) - items_to_ignore.extend(season.name for season in items.items_by_group[Group.FOOTWEAR]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] @@ -118,34 +116,98 @@ def test_does_not_create_exactly_two_items(self): self.assertTrue(count == 0 or count == 2) -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 - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_10])) - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_20])) - self.assertIn(self.world.create_item("Slingshot"), self.multiworld.itempool) - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_50])) - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_60])) - self.assertIn(self.world.create_item("Master Slingshot"), self.multiworld.itempool) - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_80])) - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_90])) - self.assertIn(self.world.create_item("Stardrop"), self.multiworld.itempool) - self.assertTrue(any(self.world.create_item(item) in self.multiworld.itempool - for item in items_by_group[Group.MINES_FLOOR_110])) - self.assertIn(self.world.create_item("Skull Key"), self.multiworld.itempool) - - # This test has a 1/90,000 chance to fail... Sorry in advance - def test_when_generate_world_then_rewards_are_not_all_vanilla(self): - self.assertFalse(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 TestMonstersanityNone(SVTestBase): + options = {options.Monstersanity.internal_name: options.Monstersanity.option_none} + + def test_when_generate_world_then_5_generic_weapons_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Weapon"), 5) + + def test_when_generate_world_then_zero_specific_weapons_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Sword"), 0) + self.assertEqual(item_pool.count("Progressive Club"), 0) + self.assertEqual(item_pool.count("Progressive Dagger"), 0) + + def test_when_generate_world_then_2_slingshots_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Slingshot"), 2) + + def test_when_generate_world_then_3_shoes_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Footwear"), 3) + + +class TestMonstersanityGoals(SVTestBase): + options = {options.Monstersanity.internal_name: options.Monstersanity.option_goals} + + def test_when_generate_world_then_no_generic_weapons_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Weapon"), 0) + + def test_when_generate_world_then_5_specific_weapons_of_each_type_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Sword"), 5) + self.assertEqual(item_pool.count("Progressive Club"), 5) + self.assertEqual(item_pool.count("Progressive Dagger"), 5) + + def test_when_generate_world_then_2_slingshots_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Slingshot"), 2) + + def test_when_generate_world_then_4_shoes_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Footwear"), 4) + + +class TestMonstersanityOnePerCategory(SVTestBase): + options = {options.Monstersanity.internal_name: options.Monstersanity.option_one_per_category} + + def test_when_generate_world_then_no_generic_weapons_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Weapon"), 0) + + def test_when_generate_world_then_5_specific_weapons_of_each_type_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Sword"), 5) + self.assertEqual(item_pool.count("Progressive Club"), 5) + self.assertEqual(item_pool.count("Progressive Dagger"), 5) + + def test_when_generate_world_then_2_slingshots_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Slingshot"), 2) + + def test_when_generate_world_then_4_shoes_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Footwear"), 4) + + +class TestMonstersanityProgressive(SVTestBase): + options = {options.Monstersanity.internal_name: options.Monstersanity.option_progressive_goals} + + def test_when_generate_world_then_no_generic_weapons_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Weapon"), 0) + + def test_when_generate_world_then_5_specific_weapons_of_each_type_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Sword"), 5) + self.assertEqual(item_pool.count("Progressive Club"), 5) + self.assertEqual(item_pool.count("Progressive Dagger"), 5) + + def test_when_generate_world_then_2_slingshots_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Slingshot"), 2) + + def test_when_generate_world_then_4_shoes_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Footwear"), 4) + + def test_when_generate_world_then_many_rings_shoes_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertIn("Hot Java Ring", item_pool) + self.assertIn("Wedding Ring", item_pool) + self.assertIn("Slime Charmer Ring", item_pool) class TestProgressiveElevator(SVTestBase): @@ -156,20 +218,51 @@ class TestProgressiveElevator(SVTestBase): } def test_given_elevator_to_floor_105_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")] * 21) - 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")) - floor_120 = self.multiworld.get_region("The Mines - Floor 120", self.player) + items_for_115 = self.generate_items_for_mine_115() + last_elevator = self.get_item_by_name("Progressive Mine Elevator") + self.collect(items_for_115) + floor_115 = self.multiworld.get_region("The Mines - Floor 115", self.player) floor_120 = self.multiworld.get_region("The Mines - Floor 120", self.player) + self.assertTrue(floor_115.can_reach(self.multiworld.state)) self.assertFalse(floor_120.can_reach(self.multiworld.state)) - self.collect(self.get_item_by_name("Progressive Mine Elevator")) + self.collect(last_elevator) self.assertTrue(floor_120.can_reach(self.multiworld.state)) + def test_given_access_to_floor_115_when_find_another_pickaxe_and_dagger_then_does_not_have_access_to_floor_120(self): + items_for_115 = self.generate_items_for_mine_115() + items_for_120 = self.generate_items_for_extra_mine_levels("Progressive Dagger") + self.collect(items_for_115) + + self.assertTrue(self.multiworld.get_region("The Mines - Floor 115", self.player).can_reach(self.multiworld.state)) + self.assertFalse(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) + + self.collect(items_for_120) + + self.assertTrue(self.multiworld.get_region("The Mines - Floor 115", self.player).can_reach(self.multiworld.state)) + self.assertFalse(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) + + self.remove(items_for_115) + self.remove(items_for_120) + + def generate_items_for_mine_115(self) -> List[Item]: + pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 2 + elevators = [self.get_item_by_name("Progressive Mine Elevator")] * 21 + swords = [self.get_item_by_name("Progressive Sword")] * 3 + combat_levels = [self.get_item_by_name("Combat Level")] * 4 + guild = self.get_item_by_name("Adventurer's Guild") + return [*combat_levels, *elevators, guild, *pickaxes, *swords] + + def generate_items_for_extra_mine_levels(self, weapon_name: str) -> List[Item]: + last_pickaxe = self.get_item_by_name("Progressive Pickaxe") + last_weapon = self.multiworld.create_item(weapon_name, self.player) + second_last_combat_level = self.get_item_by_name("Combat Level") + last_combat_level = self.get_item_by_name("Combat Level") + return [last_pickaxe, last_weapon, second_last_combat_level, last_combat_level] + + class TestLocationGeneration(SVTestBase): def test_all_location_created_are_in_location_table(self): diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index 38f59c74904f..c0b9e4f77dec 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -50,3 +50,10 @@ def test_correct_number_of_stardrops(self): multiworld = setup_solo_multiworld(allsanity_options, seed=seed) stardrop_items = [item for item in multiworld.get_items() if "Stardrop" in item.name] self.assertEqual(len(stardrop_items), 5) + + def test_no_duplicate_rings(self): + seed = random.randrange(sys.maxsize) + allsanity_options = self.allsanity_options_without_mods() + multiworld = setup_solo_multiworld(allsanity_options, seed=seed) + ring_items = [item.name for item in multiworld.get_items() if Group.RING in item_table[item.name].groups] + self.assertEqual(len(ring_items), len(set(ring_items))) diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index ccffc2848a80..28cbfcf9f032 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -21,8 +21,9 @@ def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): for item in multiworld.get_items(): multiworld.state.collect(item) - - tester.assertTrue(multiworld.find_item("Victory", 1).can_reach(multiworld.state)) + victory = multiworld.find_item("Victory", 1) + can_reach_victory = victory.can_reach(multiworld.state) + tester.assertTrue(can_reach_victory) def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 143c6dd0cc97..9995d075ca00 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -276,23 +276,25 @@ def test_mine(self): 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("Rusty Sword", 1) - self.GiveItemAndCheckReachableMine("Wooden Blade", 1) - self.GiveItemAndCheckReachableMine("Elf Blade", 1) + self.GiveItemAndCheckReachableMine("Progressive Sword", 1) + self.GiveItemAndCheckReachableMine("Progressive Dagger", 1) + self.GiveItemAndCheckReachableMine("Progressive Club", 1) - self.GiveItemAndCheckReachableMine("Silver Saber", 2) - self.GiveItemAndCheckReachableMine("Crystal Dagger", 2) + self.GiveItemAndCheckReachableMine("Progressive Sword", 2) + self.GiveItemAndCheckReachableMine("Progressive Dagger", 2) + self.GiveItemAndCheckReachableMine("Progressive Club", 2) - self.GiveItemAndCheckReachableMine("Claymore", 3) - self.GiveItemAndCheckReachableMine("Obsidian Edge", 3) - self.GiveItemAndCheckReachableMine("Bone Sword", 3) + self.GiveItemAndCheckReachableMine("Progressive Sword", 3) + self.GiveItemAndCheckReachableMine("Progressive Dagger", 3) + self.GiveItemAndCheckReachableMine("Progressive Club", 3) - self.GiveItemAndCheckReachableMine("The Slammer", 4) - self.GiveItemAndCheckReachableMine("Lava Katana", 4) + self.GiveItemAndCheckReachableMine("Progressive Sword", 4) + self.GiveItemAndCheckReachableMine("Progressive Dagger", 4) + self.GiveItemAndCheckReachableMine("Progressive Club", 4) - self.GiveItemAndCheckReachableMine("Galaxy Sword", 5) - self.GiveItemAndCheckReachableMine("Galaxy Hammer", 5) - self.GiveItemAndCheckReachableMine("Galaxy Dagger", 5) + 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) @@ -322,8 +324,6 @@ def GiveItemAndCheckReachableMine(self, item_name: str, reachable_level: int): else: self.assertFalse(self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) - self.remove(item) - class TestMonstersanityProgressiveRules(SVTestBase): options = { From b7f405ed4912164b6e5d1a99856655b55ebe2ebf Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 16:54:59 -0400 Subject: [PATCH 037/482] - Put back the old weapons as deprecated so people can stardew inventory them if they want --- worlds/stardew_valley/data/items.csv | 112 ++++++++++++++++++--------- 1 file changed, 76 insertions(+), 36 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 8e62d0f0af34..da4f2d325c9a 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -10,42 +10,43 @@ id,name,classification,groups,mod_name 22,Movie Theater,useful,, 23,Stardrop,progression,, 24,Progressive Backpack,progression,, -25,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", -26,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", -27,Progressive Club,progression,"WEAPON,WEAPON_CLUB", -28,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", -29,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -30,Progressive Footwear,useful,"FOOTWEAR", -31,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -32,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -33,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -34,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -35,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -36,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -37,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -38,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -39,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -40,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -41,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -42,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -43,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -44,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -45,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -46,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -47,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -48,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -49,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -50,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -51,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -52,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -53,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -54,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -55,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -56,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -57,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -58,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -59,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -60,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +25,Rusty Sword,filler,"WEAPON,DEPRECATED", +26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", +27,Work Boots,filler,"FOOTWEAR,DEPRECATED", +28,Wooden Blade,filler,"WEAPON,DEPRECATED", +29,Iron Dirk,filler,"WEAPON,DEPRECATED", +30,Wind Spire,filler,"WEAPON,DEPRECATED", +31,Femur,filler,"WEAPON,DEPRECATED", +32,Steel Smallsword,filler,"WEAPON,DEPRECATED", +33,Wood Club,filler,"WEAPON,DEPRECATED", +34,Elf Blade,filler,"WEAPON,DEPRECATED", +37,Slingshot,filler,"WEAPON,DEPRECATED", +38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", +39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", +40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", +41,Silver Saber,filler,"WEAPON,DEPRECATED", +42,Pirate's Sword,filler,"WEAPON,DEPRECATED", +43,Crystal Dagger,filler,"WEAPON,DEPRECATED", +44,Cutlass,filler,"WEAPON,DEPRECATED", +45,Iron Edge,filler,"WEAPON,DEPRECATED", +46,Burglar's Shank,filler,"WEAPON,DEPRECATED", +47,Wood Mallet,filler,"WEAPON,DEPRECATED", +48,Master Slingshot,filler,"WEAPON,DEPRECATED", +49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", +50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", +51,Claymore,filler,"WEAPON,DEPRECATED", +52,Templar's Blade,filler,"WEAPON,DEPRECATED", +53,Kudgel,filler,"WEAPON,DEPRECATED", +54,Shadow Dagger,filler,"WEAPON,DEPRECATED", +55,Obsidian Edge,filler,"WEAPON,DEPRECATED", +56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", +57,Wicked Kris,filler,"WEAPON,DEPRECATED", +58,Bone Sword,filler,"WEAPON,DEPRECATED", +59,Ossified Blade,filler,"WEAPON,DEPRECATED", +60,Space Boots,filler,"FOOTWEAR,DEPRECATED", +61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", +62,Steel Falchion,filler,"WEAPON,DEPRECATED", +63,The Slammer,filler,"WEAPON,DEPRECATED", 64,Skull Key,progression,, 65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, 66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, @@ -88,6 +89,9 @@ id,name,classification,groups,mod_name 103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, 104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, 105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, +106,Galaxy Sword,filler,"WEAPON,DEPRECATED", +107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", +108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", 109,Movement Speed Bonus,progression,, 110,Luck Bonus,progression,, 112,Progressive House,progression,, @@ -266,6 +270,42 @@ id,name,classification,groups,mod_name 286,Deluxe Scarecrow Recipe,progression,"FESTIVAL,RARECROW", 287,Treehouse,progression,"GINGER_ISLAND", 288,Coffee Bean,progression,CROPSANITY, +288,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +289,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +290,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +291,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +292,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +293,Progressive Footwear,useful,"FOOTWEAR", +294,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +295,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +296,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +297,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +298,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +299,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +300,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +301,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +302,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +303,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +304,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +305,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +306,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +307,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +308,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +309,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +310,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +311,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +312,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +313,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +314,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +315,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +316,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +317,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +318,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +319,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +320,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +321,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +322,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +323,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, From df33f26f83846e2761e4f6ef4041ce54f8f128cb Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 16:56:33 -0400 Subject: [PATCH 038/482] - Added lava katana as a deprecated weapon --- worlds/stardew_valley/data/items.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index da4f2d325c9a..7396b0d72eea 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -94,6 +94,7 @@ id,name,classification,groups,mod_name 108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", 109,Movement Speed Bonus,progression,, 110,Luck Bonus,progression,, +111,Lava Katana,progression,"WEAPON,DEPRECATED", 112,Progressive House,progression,, 113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, 114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, From 0d07edcbbbcd1ffc899e2d312e9b868710a0152f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 16:57:20 -0400 Subject: [PATCH 039/482] - Lava katana should be filler --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/test/TestGeneration.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 7396b0d72eea..696508a5c2cf 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -94,7 +94,7 @@ id,name,classification,groups,mod_name 108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", 109,Movement Speed Bonus,progression,, 110,Luck Bonus,progression,, -111,Lava Katana,progression,"WEAPON,DEPRECATED", +111,Lava Katana,filler,"WEAPON,DEPRECATED", 112,Progressive House,progression,, 113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, 114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index e740600f58d2..26aa07cd9648 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -31,7 +31,6 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore = [event.name for event in items.events] items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) - items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression From 466adf0c7de869b560136220787daaf2280c9509 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 17:08:51 -0400 Subject: [PATCH 040/482] - Should exclude weapons but not footwear from the progression tests --- worlds/stardew_valley/test/TestGeneration.py | 7 +++---- worlds/stardew_valley/test/mods/TestMods.py | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 26aa07cd9648..8a999490ecc8 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -31,10 +31,10 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore = [event.name for event in items.events] items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) + items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) - progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression - and item.name not in items_to_ignore] + progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] for progression_item in progression_items: with self.subTest(f"{progression_item.name}"): self.assertIn(progression_item.name, all_created_items) @@ -80,8 +80,7 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) - progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression - and item.name not in items_to_ignore] + progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] for progression_item in progression_items: with self.subTest(f"{progression_item.name}"): if Group.GINGER_ISLAND in progression_item.groups: diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 9bdabaf73f14..0c52ffb5dc1f 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -61,7 +61,6 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore = [event.name for event in items.events] items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) - items_to_ignore.extend(footwear.name for footwear in items.items_by_group[Group.FOOTWEAR]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression @@ -85,7 +84,6 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore = [event.name for event in items.events] items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) - items_to_ignore.extend(footwear.name for footwear in items.items_by_group[Group.FOOTWEAR]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression From 63560c226639d91afb0e47ac9a1974f9da63cbc9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 11 Aug 2023 12:49:46 -0400 Subject: [PATCH 041/482] - Extracted a method to please ProfBytes --- worlds/stardew_valley/rules.py | 39 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index c7d661c20b4a..11f38c2a9f5c 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -641,22 +641,31 @@ def set_monstersanity_monster_rules(all_location_names: List[str], logic: Starde MultiWorldRules.set_rule(location, rule.simplify()) -def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monstersanity_option): +def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player): for monster_category in all_monsters_by_category: - location_names = [name for name in all_location_names if name.startswith(monster_eradication_prefix) and name.endswith(monster_category)] - if not location_names: - continue - location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) - for i in range(5): - location_name = location_names[i] - if location_name not in all_location_names: - continue - location = multi_world.get_location(location_name, player) - if i < 3: - rule = logic.combat.can_kill_any_monster(all_monsters_by_category[monster_category]) & logic.time.has_lived_months((i+1) * 2) - else: - rule = logic.combat.can_kill_all_monsters(all_monsters_by_category[monster_category]) & logic.time.has_lived_months(i * 3) - MultiWorldRules.set_rule(location, rule.simplify()) + set_monstersanity_progressive_single_category_rules(all_location_names, logic, multi_world, player, monster_category) + + +def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monster_category: str): + location_names = [name for name in all_location_names if name.startswith(monster_eradication_prefix) and name.endswith(monster_category)] + if not location_names: + return + location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) + for i in range(5): + location_name = location_names[i] + set_monstersanity_progressive_single_category_rules(all_location_names, logic, multi_world, monster_category, location_name, i) + + +def set_monstersanity_progressive_category_rule(all_location_names: List[str], logic: StardewLogic, multi_world, player, + monster_category: str, location_name: str, goal_index): + if location_name not in all_location_names: + return + location = multi_world.get_location(location_name, player) + if goal_index < 3: + rule = logic.combat.can_kill_any_monster(all_monsters_by_category[monster_category]) & logic.time.has_lived_months((goal_index + 1) * 2) + else: + rule = logic.combat.can_kill_all_monsters(all_monsters_by_category[monster_category]) & logic.time.has_lived_months(goal_index * 3) + MultiWorldRules.set_rule(location, rule.simplify()) def get_monster_eradication_number(location_name, monster_category) -> int: From 8f7e6b4a660214be9d587f1928b3752558e3664e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 11 Aug 2023 12:51:32 -0400 Subject: [PATCH 042/482] - Thank you test suite for saving my butt so much I feel like princess peach --- worlds/stardew_valley/rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 11f38c2a9f5c..643c54b3a4fb 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -623,7 +623,7 @@ def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, return if monstersanity_option == options.Monstersanity.option_progressive_goals: - set_monstersanity_progressive_category_rules(all_location_names, logic, multi_world, player, monstersanity_option) + set_monstersanity_progressive_category_rules(all_location_names, logic, multi_world, player) return set_monstersanity_category_rules(all_location_names, logic, multi_world, player, monstersanity_option) @@ -653,7 +653,7 @@ def set_monstersanity_progressive_single_category_rules(all_location_names: List location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) for i in range(5): location_name = location_names[i] - set_monstersanity_progressive_single_category_rules(all_location_names, logic, multi_world, monster_category, location_name, i) + set_monstersanity_progressive_category_rule(all_location_names, logic, multi_world, player, monster_category, location_name, i) def set_monstersanity_progressive_category_rule(all_location_names: List[str], logic: StardewLogic, multi_world, player, From be7122106c23689b2c8e0efcc9251741e8fe7fad Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 14 Aug 2023 16:48:58 -0400 Subject: [PATCH 043/482] - WIP shipsanity --- worlds/stardew_valley/data/locations.csv | 574 ++++++++++++++++++++++- worlds/stardew_valley/items.py | 1 + worlds/stardew_valley/options.py | 15 +- 3 files changed, 578 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 6d73a6ee0445..1e6aca00047e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1037,8 +1037,578 @@ id,region,name,tags,mod_name 2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", 2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", 2347,Farming,Harvest Coffee Bean,"CROPSANITY", -2500,Farm,PLACEHOLDER Shipsanity start,"SHIPSANITY" -3000,Farm,PLACEHOLDER Shipsanity end,"SHIPSANITY" +2401,Farm,Shipsanity: Duck Egg,"SHIPSANITY", +2402,Farm,Shipsanity: Duck Feather,"SHIPSANITY", +2403,Farm,Shipsanity: Egg,"SHIPSANITY", +2404,Farm,Shipsanity: Goat Milk,"SHIPSANITY", +2405,Farm,Shipsanity: L. Goat Milk,"SHIPSANITY", +2406,Farm,Shipsanity: Large Egg,"SHIPSANITY", +2407,Farm,Shipsanity: Large Milk,"SHIPSANITY", +2408,Farm,Shipsanity: Milk,"SHIPSANITY", +2409,Farm,Shipsanity: Rabbit's Foot,"SHIPSANITY", +2410,Farm,Shipsanity: Roe,"SHIPSANITY", +2411,Farm,Shipsanity: Truffle,"SHIPSANITY", +2412,Farm,Shipsanity: Void Egg,"SHIPSANITY", +2413,Farm,Shipsanity: Wool,"SHIPSANITY", +2414,Farm,Shipsanity: Anchor,"SHIPSANITY", +2415,Farm,Shipsanity: Ancient Doll,"SHIPSANITY", +2416,Farm,Shipsanity: Ancient Drum,"SHIPSANITY", +2417,Farm,Shipsanity: Ancient Seed,"SHIPSANITY", +2418,Farm,Shipsanity: Ancient Sword,"SHIPSANITY", +2419,Farm,Shipsanity: Arrowhead,"SHIPSANITY", +2420,Farm,Shipsanity: Artifact Trove,"SHIPSANITY", +2421,Farm,Shipsanity: Bone Flute,"SHIPSANITY", +2422,Farm,Shipsanity: Chewing Stick,"SHIPSANITY", +2423,Farm,Shipsanity: Chicken Statue,"SHIPSANITY", +2424,Farm,Shipsanity: Chipped Amphora,"SHIPSANITY", +2425,Farm,Shipsanity: Dinosaur Egg,"SHIPSANITY", +2426,Farm,Shipsanity: Dried Starfish,"SHIPSANITY", +2427,Farm,Shipsanity: Dwarf Gadget,"SHIPSANITY", +2428,Farm,Shipsanity: Dwarf Scroll I,"SHIPSANITY", +2429,Farm,Shipsanity: Dwarf Scroll II,"SHIPSANITY", +2430,Farm,Shipsanity: Dwarf Scroll III,"SHIPSANITY", +2431,Farm,Shipsanity: Dwarf Scroll IV,"SHIPSANITY", +2432,Farm,Shipsanity: Dwarvish Helm,"SHIPSANITY", +2433,Farm,Shipsanity: Elvish Jewelry,"SHIPSANITY", +2434,Farm,Shipsanity: Glass Shards,"SHIPSANITY", +2435,Farm,Shipsanity: Golden Mask,"SHIPSANITY", +2436,Farm,Shipsanity: Golden Relic,"SHIPSANITY", +2437,Farm,Shipsanity: Ornamental Fan,"SHIPSANITY", +2438,Farm,Shipsanity: Prehistoric Handaxe,"SHIPSANITY", +2439,Farm,Shipsanity: Prehistoric Tool,"SHIPSANITY", +2440,Farm,Shipsanity: Rare Disc,"SHIPSANITY", +2441,Farm,Shipsanity: Rusty Cog,"SHIPSANITY", +2442,Farm,Shipsanity: Rusty Spoon,"SHIPSANITY", +2443,Farm,Shipsanity: Rusty Spur,"SHIPSANITY", +2444,Farm,Shipsanity: Strange Doll,"SHIPSANITY", +2445,Farm,Shipsanity: Strange Doll (Green),"SHIPSANITY", +2446,Farm,Shipsanity: Treasure Chest,"SHIPSANITY", +2447,Farm,Shipsanity: Aged Roe,"SHIPSANITY", +2448,Farm,Shipsanity: Beer,"SHIPSANITY", +2449,Farm,Shipsanity: Caviar,"SHIPSANITY", +2450,Farm,Shipsanity: Cheese,"SHIPSANITY", +2451,Farm,Shipsanity: Cloth,"SHIPSANITY", +2452,Farm,Shipsanity: Coffee,"SHIPSANITY", +2453,Farm,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY", +2454,Farm,Shipsanity: Duck Mayonnaise,"SHIPSANITY", +2455,Farm,Shipsanity: Goat Cheese,"SHIPSANITY", +2456,Farm,Shipsanity: Green Tea,"SHIPSANITY", +2457,Farm,Shipsanity: Honey,"SHIPSANITY", +2458,Farm,Shipsanity: Jelly,"SHIPSANITY", +2459,Farm,Shipsanity: Juice,"SHIPSANITY", +2460,Farm,Shipsanity: Maple Syrup,"SHIPSANITY", +2461,Farm,Shipsanity: Mayonnaise,"SHIPSANITY", +2462,Farm,Shipsanity: Mead,"SHIPSANITY", +2463,Farm,Shipsanity: Oak Resin,"SHIPSANITY", +2464,Farm,Shipsanity: Pale Ale,"SHIPSANITY", +2465,Farm,Shipsanity: Pickles,"SHIPSANITY", +2466,Farm,Shipsanity: Pine Tar,"SHIPSANITY", +2467,Farm,Shipsanity: Truffle Oil,"SHIPSANITY", +2468,Farm,Shipsanity: Void Mayonnaise,"SHIPSANITY", +2469,Farm,Shipsanity: Wine,"SHIPSANITY", +2470,Farm,Shipsanity: Algae Soup,"SHIPSANITY", +2471,Farm,Shipsanity: Artichoke Dip,"SHIPSANITY", +2472,Farm,Shipsanity: Autumn's Bounty,"SHIPSANITY", +2473,Farm,Shipsanity: Baked Fish,"SHIPSANITY", +2474,Farm,Shipsanity: Bean Hotpot,"SHIPSANITY", +2475,Farm,Shipsanity: Blackberry Cobbler,"SHIPSANITY", +2476,Farm,Shipsanity: Blueberry Tart,"SHIPSANITY", +2477,Farm,Shipsanity: Bread,"SHIPSANITY", +2478,Farm,Shipsanity: Bruschetta,"SHIPSANITY", +2479,Farm,Shipsanity: Carp Surprise,"SHIPSANITY", +2480,Farm,Shipsanity: Cheese Cauliflower,"SHIPSANITY", +2481,Farm,Shipsanity: Chocolate Cake,"SHIPSANITY", +2482,Farm,Shipsanity: Chowder,"SHIPSANITY", +2483,Farm,Shipsanity: Coleslaw,"SHIPSANITY", +2484,Farm,Shipsanity: Complete Breakfast,"SHIPSANITY", +2485,Farm,Shipsanity: Cookie,"SHIPSANITY", +2486,Farm,Shipsanity: Crab Cakes,"SHIPSANITY", +2487,Farm,Shipsanity: Cranberry Candy,"SHIPSANITY", +2488,Farm,Shipsanity: Cranberry Sauce,"SHIPSANITY", +2489,Farm,Shipsanity: Crispy Bass,"SHIPSANITY", +2490,Farm,Shipsanity: Dish O' The Sea,"SHIPSANITY", +2491,Farm,Shipsanity: Eggplant Parmesan,"SHIPSANITY", +2492,Farm,Shipsanity: Escargot,"SHIPSANITY", +2493,Farm,Shipsanity: Farmer's Lunch,"SHIPSANITY", +2494,Farm,Shipsanity: Fiddlehead Risotto,"SHIPSANITY", +2495,Farm,Shipsanity: Fish Stew,"SHIPSANITY", +2496,Farm,Shipsanity: Fish Taco,"SHIPSANITY", +2497,Farm,Shipsanity: Fried Calamari,"SHIPSANITY", +2498,Farm,Shipsanity: Fried Eel,"SHIPSANITY", +2499,Farm,Shipsanity: Fried Egg,"SHIPSANITY", +2500,Farm,Shipsanity: Fried Mushroom,"SHIPSANITY", +2501,Farm,Shipsanity: Fruit Salad,"SHIPSANITY", +2502,Farm,Shipsanity: Glazed Yams,"SHIPSANITY", +2503,Farm,Shipsanity: Hashbrowns,"SHIPSANITY", +2504,Farm,Shipsanity: Ice Cream,"SHIPSANITY", +2505,Farm,Shipsanity: Lobster Bisque,"SHIPSANITY", +2506,Farm,Shipsanity: Lucky Lunch,"SHIPSANITY", +2507,Farm,Shipsanity: Maki Roll,"SHIPSANITY", +2508,Farm,Shipsanity: Maple Bar,"SHIPSANITY", +2509,Farm,Shipsanity: Miner's Treat,"SHIPSANITY", +2510,Farm,Shipsanity: Omelet,"SHIPSANITY", +2511,Farm,Shipsanity: Pale Broth,"SHIPSANITY", +2512,Farm,Shipsanity: Pancakes,"SHIPSANITY", +2513,Farm,Shipsanity: Parsnip Soup,"SHIPSANITY", +2514,Farm,Shipsanity: Pepper Poppers,"SHIPSANITY", +2515,Farm,Shipsanity: Pink Cake,"SHIPSANITY", +2516,Farm,Shipsanity: Pizza,"SHIPSANITY", +2517,Farm,Shipsanity: Plum Pudding,"SHIPSANITY", +2518,Farm,Shipsanity: Poppyseed Muffin,"SHIPSANITY", +2519,Farm,Shipsanity: Pumpkin Pie,"SHIPSANITY", +2520,Farm,Shipsanity: Pumpkin Soup,"SHIPSANITY", +2521,Farm,Shipsanity: Radish Salad,"SHIPSANITY", +2522,Farm,Shipsanity: Red Plate,"SHIPSANITY", +2523,Farm,Shipsanity: Rhubarb Pie,"SHIPSANITY", +2524,Farm,Shipsanity: Rice Pudding,"SHIPSANITY", +2525,Farm,Shipsanity: Roasted Hazelnuts,"SHIPSANITY", +2526,Farm,Shipsanity: Roots Platter,"SHIPSANITY", +2527,Farm,Shipsanity: Salad,"SHIPSANITY", +2528,Farm,Shipsanity: Salmon Dinner,"SHIPSANITY", +2529,Farm,Shipsanity: Sashimi,"SHIPSANITY", +2530,Farm,Shipsanity: Seafoam Pudding,"SHIPSANITY", +2531,Farm,Shipsanity: Shrimp Cocktail,"SHIPSANITY", +2532,Farm,Shipsanity: Spaghetti,"SHIPSANITY", +2533,Farm,Shipsanity: Spicy Eel,"SHIPSANITY", +2534,Farm,Shipsanity: Squid Ink Ravioli,"SHIPSANITY", +2535,Farm,Shipsanity: Stir Fry,"SHIPSANITY", +2536,Farm,Shipsanity: Strange Bun,"SHIPSANITY", +2537,Farm,Shipsanity: Stuffing,"SHIPSANITY", +2538,Farm,Shipsanity: Super Meal,"SHIPSANITY", +2539,Farm,Shipsanity: Survival Burger,"SHIPSANITY", +2540,Farm,Shipsanity: Tom Kha Soup,"SHIPSANITY", +2541,Farm,Shipsanity: Tortilla,"SHIPSANITY", +2542,Farm,Shipsanity: Triple Shot Espresso,"SHIPSANITY", +2543,Farm,Shipsanity: Trout Soup,"SHIPSANITY", +2544,Farm,Shipsanity: Vegetable Medley,"SHIPSANITY", +2545,Farm,Shipsanity: Bait,"SHIPSANITY", +2546,Farm,Shipsanity: Barbed Hook,"SHIPSANITY", +2547,Farm,Shipsanity: Basic Fertilizer,"SHIPSANITY", +2548,Farm,Shipsanity: Basic Retaining Soil,"SHIPSANITY", +2549,Farm,Shipsanity: Blue Slime Egg,"SHIPSANITY", +2550,Farm,Shipsanity: Bomb,"SHIPSANITY", +2551,Farm,Shipsanity: Brick Floor,"SHIPSANITY", +2552,Farm,Shipsanity: Bug Steak,"SHIPSANITY", +2553,Farm,Shipsanity: Cherry Bomb,"SHIPSANITY", +2554,Farm,Shipsanity: Cobblestone Path,"SHIPSANITY", +2555,Farm,Shipsanity: Cookout Kit,"SHIPSANITY", +2556,Farm,Shipsanity: Cork Bobber,"SHIPSANITY", +2557,Farm,Shipsanity: Crab Pot,"SHIPSANITY", +2558,Farm,Shipsanity: Crystal Floor,"SHIPSANITY", +2559,Farm,Shipsanity: Crystal Path,"SHIPSANITY", +2560,Farm,Shipsanity: Deluxe Speed-Gro,"SHIPSANITY", +2561,Farm,Shipsanity: Dressed Spinner,"SHIPSANITY", +2562,Farm,Shipsanity: Drum Block,"SHIPSANITY", +2563,Farm,Shipsanity: Explosive Ammo,"SHIPSANITY", +2564,Farm,Shipsanity: Fiber Seeds,"SHIPSANITY", +2565,Farm,Shipsanity: Field Snack,"SHIPSANITY", +2566,Farm,Shipsanity: Flute Block,"SHIPSANITY", +2567,Farm,Shipsanity: Gate,"SHIPSANITY", +2568,Farm,Shipsanity: Gravel Path,"SHIPSANITY", +2569,Farm,Shipsanity: Green Slime Egg,"SHIPSANITY", +2570,Farm,Shipsanity: Hardwood Fence,"SHIPSANITY", +2571,Farm,Shipsanity: Iridium Sprinkler,"SHIPSANITY", +2572,Farm,Shipsanity: Iron Fence,"SHIPSANITY", +2573,Farm,Shipsanity: Jack-O-Lantern,"SHIPSANITY", +2574,Farm,Shipsanity: Lead Bobber,"SHIPSANITY", +2575,Farm,Shipsanity: Life Elixir,"SHIPSANITY", +2576,Farm,Shipsanity: Magnet,"SHIPSANITY", +2577,Farm,Shipsanity: Mega Bomb,"SHIPSANITY", +2578,Farm,Shipsanity: Monster Musk,"SHIPSANITY", +2579,Farm,Shipsanity: Oil of Garlic,"SHIPSANITY", +2580,Farm,Shipsanity: Purple Slime Egg,"SHIPSANITY", +2581,Farm,Shipsanity: Quality Bobber,"SHIPSANITY", +2582,Farm,Shipsanity: Quality Fertilizer,"SHIPSANITY", +2583,Farm,Shipsanity: Quality Retaining Soil,"SHIPSANITY", +2584,Farm,Shipsanity: Quality Sprinkler,"SHIPSANITY", +2585,Farm,Shipsanity: Rain Totem,"SHIPSANITY", +2586,Farm,Shipsanity: Red Slime Egg,"SHIPSANITY", +2587,Farm,Shipsanity: Rustic Plank Floor,"SHIPSANITY", +2588,Farm,Shipsanity: Speed-Gro,"SHIPSANITY", +2589,Farm,Shipsanity: Spinner,"SHIPSANITY", +2590,Farm,Shipsanity: Sprinkler,"SHIPSANITY", +2591,Farm,Shipsanity: Stepping Stone Path,"SHIPSANITY", +2592,Farm,Shipsanity: Stone Fence,"SHIPSANITY", +2593,Farm,Shipsanity: Stone Floor,"SHIPSANITY", +2594,Farm,Shipsanity: Stone Walkway Floor,"SHIPSANITY", +2595,Farm,Shipsanity: Straw Floor,"SHIPSANITY", +2596,Farm,Shipsanity: Torch,"SHIPSANITY", +2597,Farm,Shipsanity: Trap Bobber,"SHIPSANITY", +2598,Farm,Shipsanity: Treasure Hunter,"SHIPSANITY", +2599,Farm,Shipsanity: Tree Fertilizer,"SHIPSANITY", +2600,Farm,Shipsanity: Warp Totem: Beach,"SHIPSANITY", +2601,Farm,Shipsanity: Warp Totem: Desert,"SHIPSANITY", +2602,Farm,Shipsanity: Warp Totem: Farm,"SHIPSANITY", +2603,Farm,Shipsanity: Warp Totem: Island,"SHIPSANITY", +2604,Farm,Shipsanity: Warp Totem: Mountains,"SHIPSANITY", +2605,Farm,Shipsanity: Weathered Floor,"SHIPSANITY", +2606,Farm,Shipsanity: Wild Bait,"SHIPSANITY", +2607,Farm,Shipsanity: Wood Fence,"SHIPSANITY", +2608,Farm,Shipsanity: Wood Floor,"SHIPSANITY", +2609,Farm,Shipsanity: Wood Path,"SHIPSANITY", +2610,Farm,Shipsanity: Amaranth,"SHIPSANITY", +2611,Farm,Shipsanity: Ancient Fruit,"SHIPSANITY", +2612,Farm,Shipsanity: Apple,"SHIPSANITY", +2613,Farm,Shipsanity: Apricot,"SHIPSANITY", +2614,Farm,Shipsanity: Artichoke,"SHIPSANITY", +2615,Farm,Shipsanity: Beet,"SHIPSANITY", +2616,Farm,Shipsanity: Blue Jazz,"SHIPSANITY", +2617,Farm,Shipsanity: Blueberry,"SHIPSANITY", +2618,Farm,Shipsanity: Bok Choy,"SHIPSANITY", +2619,Farm,Shipsanity: Cauliflower,"SHIPSANITY", +2620,Farm,Shipsanity: Cherry,"SHIPSANITY", +2621,Farm,Shipsanity: Corn,"SHIPSANITY", +2622,Farm,Shipsanity: Cranberries,"SHIPSANITY", +2623,Farm,Shipsanity: Eggplant,"SHIPSANITY", +2624,Farm,Shipsanity: Fairy Rose,"SHIPSANITY", +2625,Farm,Shipsanity: Garlic,"SHIPSANITY", +2626,Farm,Shipsanity: Grape,"SHIPSANITY", +2627,Farm,Shipsanity: Green Bean,"SHIPSANITY", +2628,Farm,Shipsanity: Hops,"SHIPSANITY", +2629,Farm,Shipsanity: Hot Pepper,"SHIPSANITY", +2630,Farm,Shipsanity: Kale,"SHIPSANITY", +2631,Farm,Shipsanity: Melon,"SHIPSANITY", +2632,Farm,Shipsanity: Orange,"SHIPSANITY", +2633,Farm,Shipsanity: Parsnip,"SHIPSANITY", +2634,Farm,Shipsanity: Peach,"SHIPSANITY", +2635,Farm,Shipsanity: Pomegranate,"SHIPSANITY", +2636,Farm,Shipsanity: Poppy,"SHIPSANITY", +2637,Farm,Shipsanity: Potato,"SHIPSANITY", +2638,Farm,Shipsanity: Pumpkin,"SHIPSANITY", +2639,Farm,Shipsanity: Radish,"SHIPSANITY", +2640,Farm,Shipsanity: Red Cabbage,"SHIPSANITY", +2641,Farm,Shipsanity: Rhubarb,"SHIPSANITY", +2642,Farm,Shipsanity: Starfruit,"SHIPSANITY", +2643,Farm,Shipsanity: Strawberry,"SHIPSANITY", +2644,Farm,Shipsanity: Summer Spangle,"SHIPSANITY", +2645,Farm,Shipsanity: Sunflower,"SHIPSANITY", +2646,Farm,Shipsanity: Sweet Gem Berry,"SHIPSANITY", +2647,Farm,Shipsanity: Tea Leaves,"SHIPSANITY", +2648,Farm,Shipsanity: Tomato,"SHIPSANITY", +2649,Farm,Shipsanity: Tulip,"SHIPSANITY", +2650,Farm,Shipsanity: Unmilled Rice,"SHIPSANITY", +2651,Farm,Shipsanity: Wheat,"SHIPSANITY", +2652,Farm,Shipsanity: Yam,"SHIPSANITY", +2653,Farm,Shipsanity: Albacore,"SHIPSANITY", +2654,Farm,Shipsanity: Anchovy,"SHIPSANITY", +2655,Farm,Shipsanity: Angler,"SHIPSANITY", +2656,Farm,Shipsanity: Blobfish,"SHIPSANITY", +2657,Farm,Shipsanity: Bream,"SHIPSANITY", +2658,Farm,Shipsanity: Bullhead,"SHIPSANITY", +2659,Farm,Shipsanity: Carp,"SHIPSANITY", +2660,Farm,Shipsanity: Catfish,"SHIPSANITY", +2661,Farm,Shipsanity: Chub,"SHIPSANITY", +2662,Farm,Shipsanity: Cockle,"SHIPSANITY", +2663,Farm,Shipsanity: Crab,"SHIPSANITY", +2664,Farm,Shipsanity: Crayfish,"SHIPSANITY", +2665,Farm,Shipsanity: Crimsonfish,"SHIPSANITY", +2666,Farm,Shipsanity: Dorado,"SHIPSANITY", +2667,Farm,Shipsanity: Eel,"SHIPSANITY", +2668,Farm,Shipsanity: Flounder,"SHIPSANITY", +2669,Farm,Shipsanity: Ghostfish,"SHIPSANITY", +2670,Farm,Shipsanity: Glacierfish,"SHIPSANITY", +2671,Farm,Shipsanity: Halibut,"SHIPSANITY", +2672,Farm,Shipsanity: Herring,"SHIPSANITY", +2673,Farm,Shipsanity: Ice Pip,"SHIPSANITY", +2674,Farm,Shipsanity: Largemouth Bass,"SHIPSANITY", +2675,Farm,Shipsanity: Lava Eel,"SHIPSANITY", +2676,Farm,Shipsanity: Legend,"SHIPSANITY", +2677,Farm,Shipsanity: Lingcod,"SHIPSANITY", +2678,Farm,Shipsanity: Lobster,"SHIPSANITY", +2679,Farm,Shipsanity: Midnight Carp,"SHIPSANITY", +2680,Farm,Shipsanity: Midnight Squid,"SHIPSANITY", +2681,Farm,Shipsanity: Mussel,"SHIPSANITY", +2682,Farm,Shipsanity: Mutant Carp,"SHIPSANITY", +2683,Farm,Shipsanity: Octopus,"SHIPSANITY", +2684,Farm,Shipsanity: Oyster,"SHIPSANITY", +2685,Farm,Shipsanity: Perch,"SHIPSANITY", +2686,Farm,Shipsanity: Periwinkle,"SHIPSANITY", +2687,Farm,Shipsanity: Pike,"SHIPSANITY", +2688,Farm,Shipsanity: Pufferfish,"SHIPSANITY", +2689,Farm,Shipsanity: Rainbow Trout,"SHIPSANITY", +2690,Farm,Shipsanity: Red Mullet,"SHIPSANITY", +2691,Farm,Shipsanity: Red Snapper,"SHIPSANITY", +2692,Farm,Shipsanity: Salmon,"SHIPSANITY", +2693,Farm,Shipsanity: Sandfish,"SHIPSANITY", +2694,Farm,Shipsanity: Sardine,"SHIPSANITY", +2695,Farm,Shipsanity: Scorpion Carp,"SHIPSANITY", +2696,Farm,Shipsanity: Sea Cucumber,"SHIPSANITY", +2697,Farm,Shipsanity: Shad,"SHIPSANITY", +2698,Farm,Shipsanity: Shrimp,"SHIPSANITY", +2699,Farm,Shipsanity: Slimejack,"SHIPSANITY", +2700,Farm,Shipsanity: Smallmouth Bass,"SHIPSANITY", +2701,Farm,Shipsanity: Snail,"SHIPSANITY", +2702,Farm,Shipsanity: Spook Fish,"SHIPSANITY", +2703,Farm,Shipsanity: Squid,"SHIPSANITY", +2704,Farm,Shipsanity: Stonefish,"SHIPSANITY", +2705,Farm,Shipsanity: Sturgeon,"SHIPSANITY", +2706,Farm,Shipsanity: Sunfish,"SHIPSANITY", +2707,Farm,Shipsanity: Super Cucumber,"SHIPSANITY", +2708,Farm,Shipsanity: Tiger Trout,"SHIPSANITY", +2709,Farm,Shipsanity: Tilapia,"SHIPSANITY", +2710,Farm,Shipsanity: Tuna,"SHIPSANITY", +2711,Farm,Shipsanity: Void Salmon,"SHIPSANITY", +2712,Farm,Shipsanity: Walleye,"SHIPSANITY", +2713,Farm,Shipsanity: Woodskip,"SHIPSANITY", +2714,Farm,Shipsanity: Blackberry,"SHIPSANITY", +2715,Farm,Shipsanity: Cactus Fruit,"SHIPSANITY", +2716,Farm,Shipsanity: Cave Carrot,"SHIPSANITY", +2717,Farm,Shipsanity: Chanterelle,"SHIPSANITY", +2718,Farm,Shipsanity: Clam,"SHIPSANITY", +2719,Farm,Shipsanity: Coconut,"SHIPSANITY", +2720,Farm,Shipsanity: Common Mushroom,"SHIPSANITY", +2721,Farm,Shipsanity: Coral,"SHIPSANITY", +2722,Farm,Shipsanity: Crocus,"SHIPSANITY", +2723,Farm,Shipsanity: Crystal Fruit,"SHIPSANITY", +2724,Farm,Shipsanity: Daffodil,"SHIPSANITY", +2725,Farm,Shipsanity: Dandelion,"SHIPSANITY", +2726,Farm,Shipsanity: Fiddlehead Fern,"SHIPSANITY", +2727,Farm,Shipsanity: Hazelnut,"SHIPSANITY", +2728,Farm,Shipsanity: Holly,"SHIPSANITY", +2729,Farm,Shipsanity: Leek,"SHIPSANITY", +2730,Farm,Shipsanity: Morel,"SHIPSANITY", +2731,Farm,Shipsanity: Nautilus Shell,"SHIPSANITY", +2732,Farm,Shipsanity: Purple Mushroom,"SHIPSANITY", +2733,Farm,Shipsanity: Rainbow Shell,"SHIPSANITY", +2734,Farm,Shipsanity: Red Mushroom,"SHIPSANITY", +2735,Farm,Shipsanity: Salmonberry,"SHIPSANITY", +2736,Farm,Shipsanity: Sea Urchin,"SHIPSANITY", +2737,Farm,Shipsanity: Snow Yam,"SHIPSANITY", +2738,Farm,Shipsanity: Spice Berry,"SHIPSANITY", +2739,Farm,Shipsanity: Spring Onion,"SHIPSANITY", +2740,Farm,Shipsanity: Sweet Pea,"SHIPSANITY", +2741,Farm,Shipsanity: Wild Horseradish,"SHIPSANITY", +2742,Farm,Shipsanity: Wild Plum,"SHIPSANITY", +2743,Farm,Shipsanity: Winter Root,"SHIPSANITY", +2744,Farm,Shipsanity: Tea Set,"SHIPSANITY", +2745,Farm,Shipsanity: Battery Pack,"SHIPSANITY", +2746,Farm,Shipsanity: Clay,"SHIPSANITY", +2747,Farm,Shipsanity: Copper Bar,"SHIPSANITY", +2748,Farm,Shipsanity: Fiber,"SHIPSANITY", +2749,Farm,Shipsanity: Gold Bar,"SHIPSANITY", +2750,Farm,Shipsanity: Hardwood,"SHIPSANITY", +2751,Farm,Shipsanity: Iridium Bar,"SHIPSANITY", +2752,Farm,Shipsanity: Iron Bar,"SHIPSANITY", +2753,Farm,Shipsanity: Lumber,"SHIPSANITY", +2754,Farm,Shipsanity: Oil,"SHIPSANITY", +2755,Farm,Shipsanity: Refined Quartz,"SHIPSANITY", +2756,Farm,Shipsanity: Rice,"SHIPSANITY", +2757,Farm,Shipsanity: Sap,"SHIPSANITY", +2758,Farm,Shipsanity: Stone,"SHIPSANITY", +2759,Farm,Shipsanity: Sugar,"SHIPSANITY", +2760,Farm,Shipsanity: Vinegar,"SHIPSANITY", +2761,Farm,Shipsanity: Wheat Flour,"SHIPSANITY", +2762,Farm,Shipsanity: Wood,"SHIPSANITY", +2763,Farm,Shipsanity: Aerinite,"SHIPSANITY", +2764,Farm,Shipsanity: Alamite,"SHIPSANITY", +2765,Farm,Shipsanity: Amethyst,"SHIPSANITY", +2766,Farm,Shipsanity: Amphibian Fossil,"SHIPSANITY", +2767,Farm,Shipsanity: Aquamarine,"SHIPSANITY", +2768,Farm,Shipsanity: Baryte,"SHIPSANITY", +2769,Farm,Shipsanity: Basalt,"SHIPSANITY", +2770,Farm,Shipsanity: Bixite,"SHIPSANITY", +2771,Farm,Shipsanity: Calcite,"SHIPSANITY", +2772,Farm,Shipsanity: Celestine,"SHIPSANITY", +2773,Farm,Shipsanity: Coal,"SHIPSANITY", +2774,Farm,Shipsanity: Copper Ore,"SHIPSANITY", +2775,Farm,Shipsanity: Diamond,"SHIPSANITY", +2776,Farm,Shipsanity: Dolomite,"SHIPSANITY", +2777,Farm,Shipsanity: Earth Crystal,"SHIPSANITY", +2778,Farm,Shipsanity: Emerald,"SHIPSANITY", +2779,Farm,Shipsanity: Esperite,"SHIPSANITY", +2780,Farm,Shipsanity: Fairy Stone,"SHIPSANITY", +2781,Farm,Shipsanity: Fire Opal,"SHIPSANITY", +2782,Farm,Shipsanity: Fire Quartz,"SHIPSANITY", +2783,Farm,Shipsanity: Fluorapatite,"SHIPSANITY", +2784,Farm,Shipsanity: Frozen Geode,"SHIPSANITY", +2785,Farm,Shipsanity: Frozen Tear,"SHIPSANITY", +2786,Farm,Shipsanity: Geminite,"SHIPSANITY", +2787,Farm,Shipsanity: Geode,"SHIPSANITY", +2788,Farm,Shipsanity: Ghost Crystal,"SHIPSANITY", +2789,Farm,Shipsanity: Gold Ore,"SHIPSANITY", +2790,Farm,Shipsanity: Granite,"SHIPSANITY", +2791,Farm,Shipsanity: Helvite,"SHIPSANITY", +2792,Farm,Shipsanity: Hematite,"SHIPSANITY", +2793,Farm,Shipsanity: Iridium Ore,"SHIPSANITY", +2794,Farm,Shipsanity: Iron Ore,"SHIPSANITY", +2795,Farm,Shipsanity: Jade,"SHIPSANITY", +2796,Farm,Shipsanity: Jagoite,"SHIPSANITY", +2797,Farm,Shipsanity: Jamborite,"SHIPSANITY", +2798,Farm,Shipsanity: Jasper,"SHIPSANITY", +2799,Farm,Shipsanity: Kyanite,"SHIPSANITY", +2800,Farm,Shipsanity: Lemon Stone,"SHIPSANITY", +2801,Farm,Shipsanity: Limestone,"SHIPSANITY", +2802,Farm,Shipsanity: Lunarite,"SHIPSANITY", +2803,Farm,Shipsanity: Magma Geode,"SHIPSANITY", +2804,Farm,Shipsanity: Malachite,"SHIPSANITY", +2805,Farm,Shipsanity: Marble,"SHIPSANITY", +2806,Farm,Shipsanity: Mudstone,"SHIPSANITY", +2807,Farm,Shipsanity: Nautilus Fossil,"SHIPSANITY", +2808,Farm,Shipsanity: Nekoite,"SHIPSANITY", +2809,Farm,Shipsanity: Neptunite,"SHIPSANITY", +2810,Farm,Shipsanity: Obsidian,"SHIPSANITY", +2811,Farm,Shipsanity: Ocean Stone,"SHIPSANITY", +2812,Farm,Shipsanity: Omni Geode,"SHIPSANITY", +2813,Farm,Shipsanity: Opal,"SHIPSANITY", +2814,Farm,Shipsanity: Orpiment,"SHIPSANITY", +2815,Farm,Shipsanity: Palm Fossil,"SHIPSANITY", +2816,Farm,Shipsanity: Petrified Slime,"SHIPSANITY", +2817,Farm,Shipsanity: Prehistoric Rib,"SHIPSANITY", +2818,Farm,Shipsanity: Prehistoric Scapula,"SHIPSANITY", +2819,Farm,Shipsanity: Prehistoric Skull,"SHIPSANITY", +2820,Farm,Shipsanity: Prehistoric Tibia,"SHIPSANITY", +2821,Farm,Shipsanity: Prehistoric Vertebra,"SHIPSANITY", +2822,Farm,Shipsanity: Prismatic Shard,"SHIPSANITY", +2823,Farm,Shipsanity: Pyrite,"SHIPSANITY", +2824,Farm,Shipsanity: Quartz,"SHIPSANITY", +2825,Farm,Shipsanity: Ruby,"SHIPSANITY", +2826,Farm,Shipsanity: Sandstone,"SHIPSANITY", +2827,Farm,Shipsanity: Skeletal Hand,"SHIPSANITY", +2828,Farm,Shipsanity: Skeletal Tail,"SHIPSANITY", +2829,Farm,Shipsanity: Slate,"SHIPSANITY", +2830,Farm,Shipsanity: Soapstone,"SHIPSANITY", +2831,Farm,Shipsanity: Star Shards,"SHIPSANITY", +2832,Farm,Shipsanity: Thunder Egg,"SHIPSANITY", +2833,Farm,Shipsanity: Tigerseye,"SHIPSANITY", +2834,Farm,Shipsanity: Topaz,"SHIPSANITY", +2835,Farm,Shipsanity: Trilobite,"SHIPSANITY", +2836,Farm,Shipsanity: Bat Wing,"SHIPSANITY", +2837,Farm,Shipsanity: Bone Fragment,"SHIPSANITY", +2838,Farm,Shipsanity: Curiosity Lure,"SHIPSANITY", +2839,Farm,Shipsanity: Slime,"SHIPSANITY", +2840,Farm,Shipsanity: Solar Essence,"SHIPSANITY", +2841,Farm,Shipsanity: Squid Ink,"SHIPSANITY", +2842,Farm,Shipsanity: Void Essence,"SHIPSANITY", +2843,Farm,Shipsanity: Bouquet,"SHIPSANITY", +2844,Farm,Shipsanity: Energy Tonic,"SHIPSANITY", +2845,Farm,Shipsanity: Golden Pumpkin,"SHIPSANITY", +2846,Farm,Shipsanity: Green Algae,"SHIPSANITY", +2847,Farm,Shipsanity: Hay,"SHIPSANITY", +2848,Farm,Shipsanity: Magic Rock Candy,"SHIPSANITY", +2849,Farm,Shipsanity: Muscle Remedy,"SHIPSANITY", +2850,Farm,Shipsanity: Pearl,"SHIPSANITY", +2851,Farm,Shipsanity: Rotten Plant,"SHIPSANITY", +2852,Farm,Shipsanity: Seaweed,"SHIPSANITY", +2853,Farm,Shipsanity: Void Ghost Pendant,"SHIPSANITY", +2854,Farm,Shipsanity: White Algae,"SHIPSANITY", +2855,Farm,Shipsanity: Wilted Bouquet,"SHIPSANITY", +2856,Farm,Shipsanity: Secret Note,"SHIPSANITY", +2857,Farm,Shipsanity: Acorn,"SHIPSANITY", +2858,Farm,Shipsanity: Amaranth Seeds,"SHIPSANITY", +2859,Farm,Shipsanity: Ancient Seeds,"SHIPSANITY", +2860,Farm,Shipsanity: Apple Sapling,"SHIPSANITY", +2861,Farm,Shipsanity: Apricot Sapling,"SHIPSANITY", +2862,Farm,Shipsanity: Artichoke Seeds,"SHIPSANITY", +2863,Farm,Shipsanity: Bean Starter,"SHIPSANITY", +2864,Farm,Shipsanity: Beet Seeds,"SHIPSANITY", +2865,Farm,Shipsanity: Blueberry Seeds,"SHIPSANITY", +2866,Farm,Shipsanity: Bok Choy Seeds,"SHIPSANITY", +2867,Farm,Shipsanity: Cactus Seeds,"SHIPSANITY", +2868,Farm,Shipsanity: Cauliflower Seeds,"SHIPSANITY", +2869,Farm,Shipsanity: Cherry Sapling,"SHIPSANITY", +2870,Farm,Shipsanity: Coffee Bean,"SHIPSANITY", +2871,Farm,Shipsanity: Corn Seeds,"SHIPSANITY", +2872,Farm,Shipsanity: Cranberry Seeds,"SHIPSANITY", +2873,Farm,Shipsanity: Eggplant Seeds,"SHIPSANITY", +2874,Farm,Shipsanity: Fairy Seeds,"SHIPSANITY", +2875,Farm,Shipsanity: Fall Seeds,"SHIPSANITY", +2876,Farm,Shipsanity: Garlic Seeds,"SHIPSANITY", +2877,Farm,Shipsanity: Grape Starter,"SHIPSANITY", +2878,Farm,Shipsanity: Grass Starter,"SHIPSANITY", +2879,Farm,Shipsanity: Hops Starter,"SHIPSANITY", +2880,Farm,Shipsanity: Jazz Seeds,"SHIPSANITY", +2881,Farm,Shipsanity: Kale Seeds,"SHIPSANITY", +2882,Farm,Shipsanity: Mahogany Seed,"SHIPSANITY", +2883,Farm,Shipsanity: Maple Seed,"SHIPSANITY", +2884,Farm,Shipsanity: Melon Seeds,"SHIPSANITY", +2885,Farm,Shipsanity: Mixed Seeds,"SHIPSANITY", +2886,Farm,Shipsanity: Orange Sapling,"SHIPSANITY", +2887,Farm,Shipsanity: Parsnip Seeds,"SHIPSANITY", +2888,Farm,Shipsanity: Peach Sapling,"SHIPSANITY", +2889,Farm,Shipsanity: Pepper Seeds,"SHIPSANITY", +2890,Farm,Shipsanity: Pine Cone,"SHIPSANITY", +2891,Farm,Shipsanity: Pomegranate Sapling,"SHIPSANITY", +2892,Farm,Shipsanity: Poppy Seeds,"SHIPSANITY", +2893,Farm,Shipsanity: Potato Seeds,"SHIPSANITY", +2894,Farm,Shipsanity: Pumpkin Seeds,"SHIPSANITY", +2895,Farm,Shipsanity: Radish Seeds,"SHIPSANITY", +2896,Farm,Shipsanity: Rare Seed,"SHIPSANITY", +2897,Farm,Shipsanity: Red Cabbage Seeds,"SHIPSANITY", +2898,Farm,Shipsanity: Rhubarb Seeds,"SHIPSANITY", +2899,Farm,Shipsanity: Rice Shoot,"SHIPSANITY", +2900,Farm,Shipsanity: Spangle Seeds,"SHIPSANITY", +2901,Farm,Shipsanity: Spring Seeds,"SHIPSANITY", +2902,Farm,Shipsanity: Starfruit Seeds,"SHIPSANITY", +2903,Farm,Shipsanity: Strawberry Seeds,"SHIPSANITY", +2904,Farm,Shipsanity: Summer Seeds,"SHIPSANITY", +2905,Farm,Shipsanity: Sunflower Seeds,"SHIPSANITY", +2906,Farm,Shipsanity: Tea Sapling,"SHIPSANITY", +2907,Farm,Shipsanity: Tomato Seeds,"SHIPSANITY", +2908,Farm,Shipsanity: Tulip Bulb,"SHIPSANITY", +2909,Farm,Shipsanity: Wheat Seeds,"SHIPSANITY", +2910,Farm,Shipsanity: Winter Seeds,"SHIPSANITY", +2911,Farm,Shipsanity: Yam Seeds,"SHIPSANITY", +2912,Farm,Shipsanity: Broken CD,"SHIPSANITY", +2913,Farm,Shipsanity: Broken Glasses,"SHIPSANITY", +2914,Farm,Shipsanity: Driftwood,"SHIPSANITY", +2915,Farm,Shipsanity: Joja Cola,"SHIPSANITY", +2916,Farm,Shipsanity: Soggy Newspaper,"SHIPSANITY", +2917,Farm,Shipsanity: Trash,"SHIPSANITY", +2918,Farm,Shipsanity: Bug Meat,"SHIPSANITY", +2919,Farm,Shipsanity: Golden Egg,"SHIPSANITY", +2920,Farm,Shipsanity: Ostrich Egg,"SHIPSANITY,GINGER_ISLAND", +2921,Farm,Shipsanity: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND", +2922,Farm,Shipsanity: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND", +2923,Farm,Shipsanity: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND", +2924,Farm,Shipsanity: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND", +2925,Farm,Shipsanity: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND", +2926,Farm,Shipsanity: Mummified Bat,"SHIPSANITY,GINGER_ISLAND", +2927,Farm,Shipsanity: Mummified Frog,"SHIPSANITY,GINGER_ISLAND", +2928,Farm,Shipsanity: Snake Skull,"SHIPSANITY,GINGER_ISLAND", +2929,Farm,Shipsanity: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND", +2930,Farm,Shipsanity: Banana Pudding,"SHIPSANITY,GINGER_ISLAND", +2931,Farm,Shipsanity: Ginger Ale,"SHIPSANITY,GINGER_ISLAND", +2932,Farm,Shipsanity: Mango Sticky Rice,"SHIPSANITY,GINGER_ISLAND", +2933,Farm,Shipsanity: Piña Colada,"SHIPSANITY,GINGER_ISLAND", +2934,Farm,Shipsanity: Poi,"SHIPSANITY,GINGER_ISLAND", +2935,Farm,Shipsanity: Tropical Curry,"SHIPSANITY,GINGER_ISLAND", +2936,Farm,Shipsanity: Deluxe Fertilizer,"SHIPSANITY,GINGER_ISLAND", +2937,Farm,Shipsanity: Deluxe Retaining Soil,"SHIPSANITY,GINGER_ISLAND", +2938,Farm,Shipsanity: Fairy Dust,"SHIPSANITY,GINGER_ISLAND", +2939,Farm,Shipsanity: Hyper Speed-Gro,"SHIPSANITY,GINGER_ISLAND", +2940,Farm,Shipsanity: Magic Bait,"SHIPSANITY,GINGER_ISLAND", +2941,Farm,Shipsanity: Banana,"SHIPSANITY,GINGER_ISLAND", +2942,Farm,Shipsanity: Mango,"SHIPSANITY,GINGER_ISLAND", +2943,Farm,Shipsanity: Pineapple,"SHIPSANITY,GINGER_ISLAND", +2944,Farm,Shipsanity: Qi Fruit,"SHIPSANITY,GINGER_ISLAND", +2945,Farm,Shipsanity: Taro Root,"SHIPSANITY,GINGER_ISLAND", +2946,Farm,Shipsanity: Blue Discus,"SHIPSANITY,GINGER_ISLAND", +2947,Farm,Shipsanity: Glacierfish Jr.,"SHIPSANITY,GINGER_ISLAND", +2948,Farm,Shipsanity: Legend II,"SHIPSANITY,GINGER_ISLAND", +2949,Farm,Shipsanity: Lionfish,"SHIPSANITY,GINGER_ISLAND", +2950,Farm,Shipsanity: Ms. Angler,"SHIPSANITY,GINGER_ISLAND", +2951,Farm,Shipsanity: Radioactive Carp,"SHIPSANITY,GINGER_ISLAND", +2952,Farm,Shipsanity: Son of Crimsonfish,"SHIPSANITY,GINGER_ISLAND", +2953,Farm,Shipsanity: Stingray,"SHIPSANITY,GINGER_ISLAND", +2954,Farm,Shipsanity: Ginger,"SHIPSANITY,GINGER_ISLAND", +2955,Farm,Shipsanity: Magma Cap,"SHIPSANITY,GINGER_ISLAND", +2956,Farm,Shipsanity: Cinder Shard,"SHIPSANITY,GINGER_ISLAND", +2957,Farm,Shipsanity: Dragon Tooth,"SHIPSANITY,GINGER_ISLAND", +2958,Farm,Shipsanity: Qi Seasoning,"SHIPSANITY,GINGER_ISLAND", +2959,Farm,Shipsanity: Radioactive Bar,"SHIPSANITY,GINGER_ISLAND", +2960,Farm,Shipsanity: Radioactive Ore,"SHIPSANITY,GINGER_ISLAND", +2961,Farm,Shipsanity: Enricher,"SHIPSANITY,GINGER_ISLAND", +2962,Farm,Shipsanity: Pressure Nozzle,"SHIPSANITY,GINGER_ISLAND", +2963,Farm,Shipsanity: Galaxy Soul,"SHIPSANITY,GINGER_ISLAND", +2964,Farm,Shipsanity: Tiger Slime Egg,"SHIPSANITY,GINGER_ISLAND", +2965,Farm,Shipsanity: Movie Ticket,"SHIPSANITY,GINGER_ISLAND", +2966,Farm,Shipsanity: Journal Scrap,"SHIPSANITY,GINGER_ISLAND", +2967,Farm,Shipsanity: Banana Sapling,"SHIPSANITY,GINGER_ISLAND", +2968,Farm,Shipsanity: Mango Sapling,"SHIPSANITY,GINGER_ISLAND", +2969,Farm,Shipsanity: Mushroom Tree Seed,"SHIPSANITY,GINGER_ISLAND", +2970,Farm,Shipsanity: Pineapple Seeds,"SHIPSANITY,GINGER_ISLAND", +2971,Farm,Shipsanity: Qi Bean,"SHIPSANITY,GINGER_ISLAND", +2972,Farm,Shipsanity: Taro Tuber,"SHIPSANITY,GINGER_ISLAND", 3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", 3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", 3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 402beb050038..e41eb252fb1a 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -553,6 +553,7 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options priority_filler_items = [] priority_filler_items.extend(useful_resource_packs) + if include_traps: priority_filler_items.extend(trap_items) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index def373a6cf32..4378c9885fb5 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -373,30 +373,25 @@ class Shipsanity(Choice): """Locations for shipping items? None: There are no checks for shipping items Crops: Every crop being shipped is a check - Quality Crops: Every crop being shipped is a check, but only granted if it is gold-quality Fish: Every fish being shipped is a check except legendaries - Quality Fish: Every fish being shipped is a check except legendaries, but only granted if it is gold-quality Full Shipment: Every item in the Collections page is a check - Quality Full Shipment: Every item in the Collections page is a check, but only granted if it is gold-quality when applicable Full Shipment With Fish: Every item in the Collections page and every fish is a check - Quality Full Shipment With Fish: Every item in the Collections page and every fish is a check, but only granted if it is gold-quality when applicable Everything: Every item in the game that can be shipped is a check - Quality Everything: Every item in the game that can be shipped is a check, but only granted if it is gold-quality when applicable """ internal_name = "shipsanity" display_name = "Shipsanity" default = 0 option_none = 0 option_crops = 1 - option_quality_crops = 2 + # option_quality_crops = 2 option_fish = 3 - option_quality_fish = 4 + # option_quality_fish = 4 option_full_shipment = 5 - option_quality_full_shipment = 6 + # option_quality_full_shipment = 6 option_full_shipment_with_fish = 7 - option_quality_full_shipment_with_fish = 8 + # option_quality_full_shipment_with_fish = 8 option_everything = 9 - option_quality_everything = 10 + # option_quality_everything = 10 class Friendsanity(Choice): From 16aa70a37e87dd352e85af4cdee419fa4146e013 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 16 Aug 2023 13:08:52 -0400 Subject: [PATCH 044/482] - Rebase from the coffee bean and museum PR --- worlds/stardew_valley/data/items.csv | 72 ++++++++++----------- worlds/stardew_valley/items.py | 3 +- worlds/stardew_valley/logic/logic.py | 11 ++-- worlds/stardew_valley/logic/museum_logic.py | 28 ++++++-- worlds/stardew_valley/logic/wallet_logic.py | 4 +- worlds/stardew_valley/rules.py | 26 ++++---- worlds/stardew_valley/test/TestRules.py | 12 ++-- 7 files changed, 86 insertions(+), 70 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 696508a5c2cf..f651323b3ac9 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -271,42 +271,42 @@ id,name,classification,groups,mod_name 286,Deluxe Scarecrow Recipe,progression,"FESTIVAL,RARECROW", 287,Treehouse,progression,"GINGER_ISLAND", 288,Coffee Bean,progression,CROPSANITY, -288,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", -289,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", -290,Progressive Club,progression,"WEAPON,WEAPON_CLUB", -291,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", -292,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -293,Progressive Footwear,useful,"FOOTWEAR", -294,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -295,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -296,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -297,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -298,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -299,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -300,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -301,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -302,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -303,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -304,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -305,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -306,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -307,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -308,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -309,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -310,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -311,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -312,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -313,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -314,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -315,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -316,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -317,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -318,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -319,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -320,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -321,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -322,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -323,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +294,Progressive Footwear,useful,"FOOTWEAR", +295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index e41eb252fb1a..f4f43aca0179 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -350,8 +350,7 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S need_all_hearts_up_to_date = world_is_perfection(world_options) government_assigned_bachelor = random.choice([villager.name for villager in all_villagers if villager.bachelor and (villager.mod_name is None or villager.mod_name in mods)]) - need_recipes = world_options[options.Shipsanity] == options.Shipsanity.option_everything or world_options[ - options.Shipsanity] == options.Shipsanity.option_quality_everything + need_recipes = world_options[options.Shipsanity] == options.Shipsanity.option_everything for villager in all_villagers: if villager.mod_name not in mods and villager.mod_name is not None: continue diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 8a628da02053..436c8f3a450f 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -27,6 +27,7 @@ from .time_logic import TimeLogic from .tool_logic import ToolLogic from .wallet_logic import WalletLogic +from ..data.crops_data import crops_by_name from ..data.monster_data import all_monsters_by_category from ..mods.logic.mod_logic import ModLogic from .. import options @@ -172,7 +173,7 @@ def __post_init__(self): self.crop_rules.update({crop.name: self.crop.can_grow(crop) for crop in all_crops}) self.crop_rules.update({ Seed.coffee: (self.season.has(Season.spring) | self.season.has( - Season.summer)) & self.has_traveling_merchant(), + Season.summer)) & self.can_buy_seed(crops_by_name[Seed.coffee].seed), Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), }) @@ -486,8 +487,8 @@ def __post_init__(self): FestivalCheck.mermaid_pearl: self.season.has(Season.winter) & self.region.can_reach(Region.beach), FestivalCheck.cone_hat: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(2500), FestivalCheck.iridium_fireplace: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(15000), - FestivalCheck.rarecrow_7: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_find_museum_artifacts(20), - FestivalCheck.rarecrow_8: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_find_museum_items(40), + FestivalCheck.rarecrow_7: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_donate_museum_artifacts(20), + FestivalCheck.rarecrow_8: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_donate_museum_items(40), FestivalCheck.lupini_red_eagle: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), FestivalCheck.lupini_portrait_mermaid: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), FestivalCheck.lupini_solar_kingdom: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), @@ -632,7 +633,7 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: self.money.can_have_earned_total(1000000), # 1 000 000g second point self.skill.has_total_level(30), # Total Skills: 30 self.skill.has_total_level(50), # Total Skills: 50 - # Completing the museum not expected + self.museum.can_complete_museum(), # Completing the museum for a point # Catching every fish not expected # Shipping every item not expected self.relationship.can_get_married() & self.buildings.has_house(2), @@ -643,7 +644,7 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: self.can_complete_community_center(), # CC Ceremony first point self.can_complete_community_center(), # CC Ceremony second point self.received(Wallet.skull_key), # Skull Key obtained - self.wallet.has_rusty_key(), # Rusty key not expected + self.wallet.has_rusty_key(), # Rusty key obtained ] return Count(12, rules_worth_a_point) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 0d525ec758f9..ea1a3986ded8 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -3,7 +3,7 @@ from .action_logic import ActionLogic from .has_logic import HasLogic from .. import options -from ..data.museum_data import MuseumItem, all_museum_items, all_artifact_items +from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals from ..stardew_rule import StardewRule, And, False_, Count from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -26,6 +26,18 @@ def __init__(self, player: int, museum_option: int, received: ReceivedLogic, has self.region = region self.action = action + def can_donate_museum_item(self, item: MuseumItem) -> StardewRule: + return self.region.can_reach(Region.museum) & self.can_find_museum_item(item) + + def can_donate_museum_items(self, number: int) -> StardewRule: + return self.region.can_reach(Region.museum) & self.can_find_museum_items(number) + + def can_donate_museum_artifacts(self, number: int) -> StardewRule: + return self.region.can_reach(Region.museum) & self.can_find_museum_artifacts(number) + + def can_donate_museum_minerals(self, number: int) -> StardewRule: + return self.region.can_reach(Region.museum) & self.can_find_museum_minerals(number) + def can_find_museum_item(self, item: MuseumItem) -> StardewRule: region_rule = self.region.can_reach_all_except_one(item.locations) geodes_rule = And([self.action.can_open_geode(geode) for geode in item.geodes]) @@ -38,9 +50,15 @@ def can_find_museum_item(self, item: MuseumItem) -> StardewRule: def can_find_museum_artifacts(self, number: int) -> StardewRule: rules = [] - for donation in all_museum_items: - if donation in all_artifact_items: - rules.append(self.can_find_museum_item(donation)) + for artifact in all_museum_artifacts: + rules.append(self.can_find_museum_item(artifact)) + + return Count(number, rules) + + def can_find_museum_minerals(self, number: int) -> StardewRule: + rules = [] + for mineral in all_museum_minerals: + rules.append(self.can_find_museum_item(mineral)) return Count(number, rules) @@ -52,7 +70,7 @@ def can_find_museum_items(self, number: int) -> StardewRule: return Count(number, rules) def can_complete_museum(self) -> StardewRule: - rules = [] + rules = [self.region.can_reach(Region.museum)] if self.museum_option != options.Museumsanity.option_none: rules.append(self.received("Traveling Merchant Metal Detector", 4)) diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index 77a1b769229c..b661f2386428 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,7 +1,7 @@ from .museum_logic import MuseumLogic from .. import options from ..data.museum_data import dwarf_scrolls, all_museum_items -from ..stardew_rule import StardewRule +from ..stardew_rule import StardewRule, And from .received_logic import ReceivedLogic from ..strings.wallet_item_names import Wallet @@ -18,7 +18,7 @@ def __init__(self, player: int, received: ReceivedLogic, museum: MuseumLogic): def can_speak_dwarf(self) -> StardewRule: if self.museum.museum_option == options.Museumsanity.option_none: - return self.museum.can_donate_many([item.name for item in dwarf_scrolls]) + return And([self.museum.can_donate_museum_item(item) for item in dwarf_scrolls]) return self.received("Dwarvish Translation Guide") def has_rusty_key(self) -> StardewRule: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 643c54b3a4fb..d222c5f9540d 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -5,15 +5,14 @@ from worlds.generic import Rules as MultiWorldRules from . import options, locations from .bundles import Bundle -from .data.monster_data import all_monsters_by_category, all_monsters, all_monsters_by_name +from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices from .stardew_rule import And from .strings.building_names import Building from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance -from .data.museum_data import all_museum_items, all_mineral_items, all_artifact_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, \ - all_museum_items_by_name -from .strings.performance_names import Performance +from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals,\ + all_museum_artifacts, Artifact from .strings.region_names import Region from .mods.mod_data import ModNames from .locations import LocationTags @@ -544,8 +543,7 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi if museum_location.name in all_location_names: donation_name = museum_location.name[len(museum_prefix):] required_detectors = counter * 5 // number_donations - rule = logic.can_find_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", - required_detectors) + rule = logic.museum.can_find_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", required_detectors) MultiWorldRules.set_rule(multiworld.get_location(museum_location.name, player), rule.simplify()) counter += 1 @@ -560,21 +558,21 @@ def set_museum_milestone_rule(logic: StardewLogic, multi_world: MultiWorld, muse metal_detector = "Traveling Merchant Metal Detector" rule = None if milestone_name.endswith(donations_suffix): - rule = get_museum_item_count_rule(logic, donations_suffix, milestone_name, all_museum_items, logic.can_find_museum_items) + rule = get_museum_item_count_rule(logic, donations_suffix, milestone_name, all_museum_items, logic.museum.can_find_museum_items) elif milestone_name.endswith(minerals_suffix): - rule = get_museum_item_count_rule(logic, minerals_suffix, milestone_name, all_museum_minerals, logic.can_find_museum_minerals) + rule = get_museum_item_count_rule(logic, minerals_suffix, milestone_name, all_museum_minerals, logic.museum.can_find_museum_minerals) elif milestone_name.endswith(artifacts_suffix): - rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_museum_artifacts, logic.can_find_museum_artifacts) + rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_museum_artifacts, logic.museum.can_find_museum_artifacts) elif milestone_name == "Dwarf Scrolls": - rule = And([logic.can_find_museum_item(item) for item in dwarf_scrolls]) & logic.received(metal_detector, 4) + rule = And([logic.museum.can_find_museum_item(item) for item in dwarf_scrolls]) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Front": - rule = And([logic.can_find_museum_item(item) for item in skeleton_front]) & logic.received(metal_detector, 4) + rule = And([logic.museum.can_find_museum_item(item) for item in skeleton_front]) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Middle": - rule = And([logic.can_find_museum_item(item) for item in skeleton_middle]) & logic.received(metal_detector, 4) + rule = And([logic.museum.can_find_museum_item(item) for item in skeleton_middle]) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Back": - rule = And([logic.can_find_museum_item(item) for item in skeleton_back]) & logic.received(metal_detector, 4) + rule = And([logic.museum.can_find_museum_item(item) for item in skeleton_back]) & logic.received(metal_detector, 4) elif milestone_name == "Ancient Seed": - rule = logic.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) + rule = logic.museum.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) if rule is None: return MultiWorldRules.set_rule(multi_world.get_location(museum_milestone.name, player), rule.simplify()) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 9995d075ca00..f5af277a8eff 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -408,12 +408,12 @@ def test_cannot_make_any_donation_without_museum_access(self): collect_all_except(self.multiworld, guild_item) for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]: - self.assertFalse(self.world.logic.can_reach_location(donation.name)(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item(guild_item), event=True) for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]: - self.assertTrue(self.world.logic.can_reach_location(donation.name)(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) class TestDonationLogicRandomized(SVTestBase): @@ -428,12 +428,12 @@ def test_cannot_make_any_donation_without_museum_access(self): donation_locations = [location for location in self.multiworld.get_locations() if not location.event and LocationTags.MUSEUM_DONATIONS in location_table[location.name].tags] for donation in donation_locations: - self.assertFalse(self.world.logic.can_reach_location(donation.name)(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item(guild_item), event=True) for donation in donation_locations: - self.assertTrue(self.world.logic.can_reach_location(donation.name)(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) class TestDonationLogicMilestones(SVTestBase): @@ -447,12 +447,12 @@ def test_cannot_make_any_donation_without_museum_access(self): collect_all_except(self.multiworld, guild_item) for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]: - self.assertFalse(self.world.logic.can_reach_location(donation.name)(self.multiworld.state)) + self.assertFalse(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item(guild_item), event=True) for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]: - self.assertTrue(self.world.logic.can_reach_location(donation.name)(self.multiworld.state)) + self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) def swap_museum_and_guild(multiworld, player): From 4efa6d9a387dbc75220ef87e76b8a1301815f9ab Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 16 Aug 2023 13:10:26 -0400 Subject: [PATCH 045/482] - Update expected location count --- worlds/stardew_valley/test/TestGeneration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 8a999490ecc8..417032062046 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -278,7 +278,7 @@ def test_minimal_location_maximal_items_still_valid(self): self.assertGreaterEqual(len(valid_locations), len(multiworld.itempool)) def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1053 + expected_locations = 1054 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -292,7 +292,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 1305 + expected_locations = 1306 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) From e0eec4cce3a37767c2d5ff4aa299c032afb461c3 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 17 Aug 2023 21:30:44 -0400 Subject: [PATCH 046/482] - Added shipsanity location tags --- worlds/stardew_valley/data/locations.csv | 2255 +++++++++++----------- worlds/stardew_valley/locations.py | 3 + worlds/stardew_valley/options.py | 2 +- 3 files changed, 1132 insertions(+), 1128 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 1e6aca00047e..660f0aee4742 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1,43 +1,43 @@ -id,region,name,tags,mod_name -1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -31,Abandoned JojaMart,The Missing Bundle,BUNDLE, -32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", -34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", -35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", -37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", -101,Pierre's General Store,Large Pack,BACKPACK, -102,Pierre's General Store,Deluxe Pack,BACKPACK, +id,region,name,tags,mod_name +1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", +2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", +3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", +4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", +5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", +6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", +7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", +8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", +9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", +10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", +11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", +12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", +13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", +14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", +15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", +16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", +17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", +18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", +19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", +27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", +28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", +29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", +30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", +31,Abandoned JojaMart,The Missing Bundle,BUNDLE, +32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", +34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", +35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", +37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +101,Pierre's General Store,Large Pack,BACKPACK, +102,Pierre's General Store,Deluxe Pack,BACKPACK, 103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", 104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", 105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", @@ -58,48 +58,48 @@ id,region,name,tags,mod_name 120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", 121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", 122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", -202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", -203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", -204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", -205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", -206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", -207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", -208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", -209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", -210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", -211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", -212,Quarry Mine,Grim Reaper statue,MANDATORY, -213,The Mines,The Mines Entrance Cutscene,MANDATORY, -214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, -215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, -216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, -217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, -218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, -219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, -220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, -221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, -222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, -223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, -224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, -225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, -226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, -227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, -228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, -229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, -230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, -231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, -232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, -233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, -234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, -235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, -236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, -237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, -251,Volcano - Floor 10,Volcano Caldera Treasure,"MANDATORY,GINGER_ISLAND", +123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", +202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", +203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", +204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", +205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", +206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", +207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", +208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", +209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", +210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", +211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", +212,Quarry Mine,Grim Reaper statue,MANDATORY, +213,The Mines,The Mines Entrance Cutscene,MANDATORY, +214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, +215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, +216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, +217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, +218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, +219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, +220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, +221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, +222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, +223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, +224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, +225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, +226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, +227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, +228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, +229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, +230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, +231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, +232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, +233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, +234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, +235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, +236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, +237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, +251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", 301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", 302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", 303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", @@ -150,98 +150,98 @@ id,region,name,tags,mod_name 348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", 349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", 350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, -402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, -403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, -404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, -405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, -406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, -407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, -408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, -409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, -410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, -411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, -412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, -413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, -414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, -415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, -416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, -417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, -418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, -501,Town,Introductions,"MANDATORY,QUEST", -502,Town,How To Win Friends,"MANDATORY,QUEST", -503,Farm,Getting Started,"MANDATORY,QUEST", -504,Farm,Raising Animals,"MANDATORY,QUEST", -505,Farm,Advancement,"MANDATORY,QUEST", -506,Museum,Archaeology,"MANDATORY,QUEST", -507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", +401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, +402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, +403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, +404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, +405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, +406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, +407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, +408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, +409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, +410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, +411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, +412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, +413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, +414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, +415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, +416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, +417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, +418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, +501,Town,Introductions,"MANDATORY,QUEST", +502,Town,How To Win Friends,"MANDATORY,QUEST", +503,Farm,Getting Started,"MANDATORY,QUEST", +504,Farm,Raising Animals,"MANDATORY,QUEST", +505,Farm,Advancement,"MANDATORY,QUEST", +506,Museum,Archaeology,"MANDATORY,QUEST", +507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", 508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", 509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", 510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", -511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", -512,Sam's House,Jodi's Request,"MANDATORY,QUEST", -513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", -514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", -515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", +511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", +512,Sam's House,Jodi's Request,"MANDATORY,QUEST", +513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", +514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", +515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", 516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", -517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", -518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", -519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", +517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", +518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", +519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", 520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", 521,Alex's House,Knee Therapy,"MANDATORY,QUEST", 522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", 523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", -524,Desert,The Mysterious Qi,"MANDATORY,QUEST", +524,Desert,The Mysterious Qi,"MANDATORY,QUEST", 525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", -526,Town,A Winter Mystery,"MANDATORY,QUEST", -527,Secret Woods,Strange Note,"MANDATORY,QUEST", +526,Town,A Winter Mystery,"MANDATORY,QUEST", +527,Secret Woods,Strange Note,"MANDATORY,QUEST", 528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", 529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", 530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", 531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", 532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", -533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", +533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", 534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", -535,Sam's House,Fish Casserole,"MANDATORY,QUEST", +535,Sam's House,Fish Casserole,"MANDATORY,QUEST", 536,Fishing,Catch A Squid,"MANDATORY,QUEST", -537,Saloon,Fish Stew,"MANDATORY,QUEST", +537,Saloon,Fish Stew,"MANDATORY,QUEST", 538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", 539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", 540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", -541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", +541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", 542,Alex's House,Granny's Gift,"MANDATORY,QUEST", 543,Desert,Exotic Spirits,"MANDATORY,QUEST", 544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", -545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Railroad,Dark Talisman,"MANDATORY,QUEST,REQUIRES_MUSEUM", -547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", -548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", -601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", -602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", -603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", -604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", -605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", -606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", -607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", -608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", -609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", -610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", -611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", -612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", -613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", -614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", -615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", -616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", -617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", -618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", -619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", -620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", -621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", -701,Secret Woods,Old Master Cannoli,MANDATORY, -702,Beach,Beach Bridge Repair,MANDATORY, -703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,MANDATORY, -705,Farmhouse,Have Another Baby,MANDATORY, +545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", +546,Railroad,Dark Talisman,"MANDATORY,QUEST,REQUIRES_MUSEUM", +547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", +548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", +601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", +602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", +603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", +604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", +605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", +606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", +607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", +608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", +609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", +610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", +611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", +612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", +613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", +614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", +615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", +616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", +617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", +618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", +619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", +620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", +621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", +701,Secret Woods,Old Master Cannoli,MANDATORY, +702,Beach,Beach Bridge Repair,MANDATORY, +703,Desert,Galaxy Sword Shrine,MANDATORY, +704,Farmhouse,Have a Baby,MANDATORY, +705,Farmhouse,Have Another Baby,MANDATORY, 801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, 802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, 803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, @@ -266,38 +266,38 @@ id,region,name,tags,mod_name 826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, 827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, 828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, -841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, -842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, -843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, -844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, -845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, -846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, -847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, -848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, -849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, -850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, -851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, -852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, -853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, -854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, -855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, -856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, -857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, -858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, -859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, -860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, -861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, -862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, -863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, -864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, -865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, -866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, -867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, -868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, -869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, -870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, -871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, -872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, +841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, +842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, +843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, +844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, +845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, +846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, +847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, +848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, +849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, +850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, +851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, +852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, +853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, +854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, +855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, +856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, +857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, +858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, +859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, +860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, +861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, +862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, +863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, +864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, +865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, +866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, +867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, +868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, +869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, +870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, +871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, +872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, 901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", 902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", 903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", @@ -363,7 +363,7 @@ id,region,name,tags,mod_name 1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", 1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, 1044,Fishing,Fishsanity: Lingcod,FISHSANITY, -1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, +1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, 1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, 1047,Fishing,Fishsanity: Octopus,FISHSANITY, 1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, @@ -374,16 +374,16 @@ id,region,name,tags,mod_name 1053,Fishing,Fishsanity: Legend,FISHSANITY, 1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, 1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, -1056,Town,Fishsanity: Crayfish,FISHSANITY, -1057,Town,Fishsanity: Snail,FISHSANITY, -1058,Town,Fishsanity: Periwinkle,FISHSANITY, -1059,Beach,Fishsanity: Lobster,FISHSANITY, -1060,Beach,Fishsanity: Clam,FISHSANITY, -1061,Beach,Fishsanity: Crab,FISHSANITY, -1062,Beach,Fishsanity: Cockle,FISHSANITY, -1063,Beach,Fishsanity: Mussel,FISHSANITY, -1064,Beach,Fishsanity: Shrimp,FISHSANITY, -1065,Beach,Fishsanity: Oyster,FISHSANITY, +1056,Town,Fishsanity: Crayfish,FISHSANITY, +1057,Town,Fishsanity: Snail,FISHSANITY, +1058,Town,Fishsanity: Periwinkle,FISHSANITY, +1059,Beach,Fishsanity: Lobster,FISHSANITY, +1060,Beach,Fishsanity: Clam,FISHSANITY, +1061,Beach,Fishsanity: Crab,FISHSANITY, +1062,Beach,Fishsanity: Cockle,FISHSANITY, +1063,Beach,Fishsanity: Mussel,FISHSANITY, +1064,Beach,Fishsanity: Shrimp,FISHSANITY, +1065,Beach,Fishsanity: Oyster,FISHSANITY, 1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, 1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, 1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, @@ -564,34 +564,34 @@ id,region,name,tags,mod_name 1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, 1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, 1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, -1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, -1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, -1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, -1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, -1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, -1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, -1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, -1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, -1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, -1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, -1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, -1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, -1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, -1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, -1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, -1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, -1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, -1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, -1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, -1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, -1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, -1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, -1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, -1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, -1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, -1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, -1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, -1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, +1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, +1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, +1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, +1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, +1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, +1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, +1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, +1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, +1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, +1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, +1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, +1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, +1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, +1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, +1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, +1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, +1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, +1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, +1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, +1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, +1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, +1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, +1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, +1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, +1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, +1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, +1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, +1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, 1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, 1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, 1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, @@ -648,20 +648,20 @@ id,region,name,tags,mod_name 1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, 1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, 1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, -1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, -1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, -1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, -1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, -1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, -1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, -1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, -1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, -1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, -1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, -1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, -1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, -1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, -1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, +1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, +1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, +1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, +1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, +1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, +1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, +1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, +1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, +1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, +1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, +1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, +1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, +1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, +1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, 1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, 1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, 1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, @@ -696,16 +696,16 @@ id,region,name,tags,mod_name 1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, 1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, 1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, -1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, -1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, -1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, -1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, -1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, -1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, -1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, -1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, -1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, -1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, +1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, +1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, +1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, +1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, +1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, +1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, +1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, +1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, +1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, +1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, 1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, 1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, 1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, @@ -746,16 +746,16 @@ id,region,name,tags,mod_name 1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, 1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, 1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, -1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, -1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, -1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, -1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, -1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, -1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, -1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, -1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, -1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, -1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, +1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, +1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, +1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, +1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, +1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, +1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, +1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, +1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, +1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, +1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, 1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, 1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, 1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, @@ -776,26 +776,26 @@ id,region,name,tags,mod_name 1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, 1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, 1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", -1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", -1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", -1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", -1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", -1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", -1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", -1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", -1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", -1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", +1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", +1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", +1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", +1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", +1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", +1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", +1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", +1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", +1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", +1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", 1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, 1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, 1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, @@ -816,16 +816,16 @@ id,region,name,tags,mod_name 1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, 1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, 1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, -1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, -1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, -1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, -1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, -1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, -1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, -1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, -1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, -1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, -1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, +1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, +1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, +1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, +1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, +1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, +1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, +1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, +1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, +1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, +1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, 1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, 1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, 1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, @@ -846,26 +846,26 @@ id,region,name,tags,mod_name 1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, 1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, 1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, -1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, -1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, -1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, -1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, -1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, -1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, -1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, -1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, -1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, -1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, -1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, -1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, -1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, -1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, -1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, -1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, -1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, -1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, -1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, -1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, +1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, +1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, +1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, +1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, +1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, +1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, +1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, +1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, +1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, +1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, +1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, +1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, +1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, +1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, +1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, +1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, +1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, +1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, +1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, +1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, 1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, 1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, 1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, @@ -896,11 +896,11 @@ id,region,name,tags,mod_name 1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, 1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, 1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, -1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, -1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, -1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, -1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, -1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, +1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, +1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, +1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, +1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, +1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, 1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, 1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, 1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, @@ -945,8 +945,8 @@ id,region,name,tags,mod_name 2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, 2029,Feast of the Winter Star,Secret Santa,FESTIVAL, 2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, -2031,Farm,Collect All Rarecrows,FESTIVAL, -2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2031,Farm,Collect All Rarecrows,FESTIVAL, +2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, 2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, 2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, @@ -961,35 +961,35 @@ id,region,name,tags,mod_name 2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, 2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, 2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, -2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, 2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, -2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,SPECIAL_ORDER_QI,JUNIMO_KART", -2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, -2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, -2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, -2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", -2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", -2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", -2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", -2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", -2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", -2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", -2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", -2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", -2215,Dig Site,Open Professor Snail Cave,"GINGER_ISLAND", -2216,Field Office,Complete Island Field Office,"GINGER_ISLAND", +2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", +2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, +2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, +2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, +2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", +2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", +2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", +2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", +2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", +2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", +2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", +2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", +2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", +2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, +2216,Field Office,Complete Island Field Office,GINGER_ISLAND, 2301,Farming,Harvest Amaranth,"CROPSANITY", 2302,Farming,Harvest Artichoke,"CROPSANITY", 2303,Farming,Harvest Beet,"CROPSANITY", @@ -1037,707 +1037,708 @@ id,region,name,tags,mod_name 2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", 2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", 2347,Farming,Harvest Coffee Bean,"CROPSANITY", -2401,Farm,Shipsanity: Duck Egg,"SHIPSANITY", -2402,Farm,Shipsanity: Duck Feather,"SHIPSANITY", -2403,Farm,Shipsanity: Egg,"SHIPSANITY", -2404,Farm,Shipsanity: Goat Milk,"SHIPSANITY", -2405,Farm,Shipsanity: L. Goat Milk,"SHIPSANITY", -2406,Farm,Shipsanity: Large Egg,"SHIPSANITY", -2407,Farm,Shipsanity: Large Milk,"SHIPSANITY", -2408,Farm,Shipsanity: Milk,"SHIPSANITY", -2409,Farm,Shipsanity: Rabbit's Foot,"SHIPSANITY", -2410,Farm,Shipsanity: Roe,"SHIPSANITY", -2411,Farm,Shipsanity: Truffle,"SHIPSANITY", -2412,Farm,Shipsanity: Void Egg,"SHIPSANITY", -2413,Farm,Shipsanity: Wool,"SHIPSANITY", -2414,Farm,Shipsanity: Anchor,"SHIPSANITY", -2415,Farm,Shipsanity: Ancient Doll,"SHIPSANITY", -2416,Farm,Shipsanity: Ancient Drum,"SHIPSANITY", -2417,Farm,Shipsanity: Ancient Seed,"SHIPSANITY", -2418,Farm,Shipsanity: Ancient Sword,"SHIPSANITY", -2419,Farm,Shipsanity: Arrowhead,"SHIPSANITY", -2420,Farm,Shipsanity: Artifact Trove,"SHIPSANITY", -2421,Farm,Shipsanity: Bone Flute,"SHIPSANITY", -2422,Farm,Shipsanity: Chewing Stick,"SHIPSANITY", -2423,Farm,Shipsanity: Chicken Statue,"SHIPSANITY", -2424,Farm,Shipsanity: Chipped Amphora,"SHIPSANITY", -2425,Farm,Shipsanity: Dinosaur Egg,"SHIPSANITY", -2426,Farm,Shipsanity: Dried Starfish,"SHIPSANITY", -2427,Farm,Shipsanity: Dwarf Gadget,"SHIPSANITY", -2428,Farm,Shipsanity: Dwarf Scroll I,"SHIPSANITY", -2429,Farm,Shipsanity: Dwarf Scroll II,"SHIPSANITY", -2430,Farm,Shipsanity: Dwarf Scroll III,"SHIPSANITY", -2431,Farm,Shipsanity: Dwarf Scroll IV,"SHIPSANITY", -2432,Farm,Shipsanity: Dwarvish Helm,"SHIPSANITY", -2433,Farm,Shipsanity: Elvish Jewelry,"SHIPSANITY", -2434,Farm,Shipsanity: Glass Shards,"SHIPSANITY", -2435,Farm,Shipsanity: Golden Mask,"SHIPSANITY", -2436,Farm,Shipsanity: Golden Relic,"SHIPSANITY", -2437,Farm,Shipsanity: Ornamental Fan,"SHIPSANITY", -2438,Farm,Shipsanity: Prehistoric Handaxe,"SHIPSANITY", -2439,Farm,Shipsanity: Prehistoric Tool,"SHIPSANITY", -2440,Farm,Shipsanity: Rare Disc,"SHIPSANITY", -2441,Farm,Shipsanity: Rusty Cog,"SHIPSANITY", -2442,Farm,Shipsanity: Rusty Spoon,"SHIPSANITY", -2443,Farm,Shipsanity: Rusty Spur,"SHIPSANITY", -2444,Farm,Shipsanity: Strange Doll,"SHIPSANITY", -2445,Farm,Shipsanity: Strange Doll (Green),"SHIPSANITY", -2446,Farm,Shipsanity: Treasure Chest,"SHIPSANITY", -2447,Farm,Shipsanity: Aged Roe,"SHIPSANITY", -2448,Farm,Shipsanity: Beer,"SHIPSANITY", -2449,Farm,Shipsanity: Caviar,"SHIPSANITY", -2450,Farm,Shipsanity: Cheese,"SHIPSANITY", -2451,Farm,Shipsanity: Cloth,"SHIPSANITY", -2452,Farm,Shipsanity: Coffee,"SHIPSANITY", -2453,Farm,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY", -2454,Farm,Shipsanity: Duck Mayonnaise,"SHIPSANITY", -2455,Farm,Shipsanity: Goat Cheese,"SHIPSANITY", -2456,Farm,Shipsanity: Green Tea,"SHIPSANITY", -2457,Farm,Shipsanity: Honey,"SHIPSANITY", -2458,Farm,Shipsanity: Jelly,"SHIPSANITY", -2459,Farm,Shipsanity: Juice,"SHIPSANITY", -2460,Farm,Shipsanity: Maple Syrup,"SHIPSANITY", -2461,Farm,Shipsanity: Mayonnaise,"SHIPSANITY", -2462,Farm,Shipsanity: Mead,"SHIPSANITY", -2463,Farm,Shipsanity: Oak Resin,"SHIPSANITY", -2464,Farm,Shipsanity: Pale Ale,"SHIPSANITY", -2465,Farm,Shipsanity: Pickles,"SHIPSANITY", -2466,Farm,Shipsanity: Pine Tar,"SHIPSANITY", -2467,Farm,Shipsanity: Truffle Oil,"SHIPSANITY", -2468,Farm,Shipsanity: Void Mayonnaise,"SHIPSANITY", -2469,Farm,Shipsanity: Wine,"SHIPSANITY", -2470,Farm,Shipsanity: Algae Soup,"SHIPSANITY", -2471,Farm,Shipsanity: Artichoke Dip,"SHIPSANITY", -2472,Farm,Shipsanity: Autumn's Bounty,"SHIPSANITY", -2473,Farm,Shipsanity: Baked Fish,"SHIPSANITY", -2474,Farm,Shipsanity: Bean Hotpot,"SHIPSANITY", -2475,Farm,Shipsanity: Blackberry Cobbler,"SHIPSANITY", -2476,Farm,Shipsanity: Blueberry Tart,"SHIPSANITY", -2477,Farm,Shipsanity: Bread,"SHIPSANITY", -2478,Farm,Shipsanity: Bruschetta,"SHIPSANITY", -2479,Farm,Shipsanity: Carp Surprise,"SHIPSANITY", -2480,Farm,Shipsanity: Cheese Cauliflower,"SHIPSANITY", -2481,Farm,Shipsanity: Chocolate Cake,"SHIPSANITY", -2482,Farm,Shipsanity: Chowder,"SHIPSANITY", -2483,Farm,Shipsanity: Coleslaw,"SHIPSANITY", -2484,Farm,Shipsanity: Complete Breakfast,"SHIPSANITY", -2485,Farm,Shipsanity: Cookie,"SHIPSANITY", -2486,Farm,Shipsanity: Crab Cakes,"SHIPSANITY", -2487,Farm,Shipsanity: Cranberry Candy,"SHIPSANITY", -2488,Farm,Shipsanity: Cranberry Sauce,"SHIPSANITY", -2489,Farm,Shipsanity: Crispy Bass,"SHIPSANITY", -2490,Farm,Shipsanity: Dish O' The Sea,"SHIPSANITY", -2491,Farm,Shipsanity: Eggplant Parmesan,"SHIPSANITY", -2492,Farm,Shipsanity: Escargot,"SHIPSANITY", -2493,Farm,Shipsanity: Farmer's Lunch,"SHIPSANITY", -2494,Farm,Shipsanity: Fiddlehead Risotto,"SHIPSANITY", -2495,Farm,Shipsanity: Fish Stew,"SHIPSANITY", -2496,Farm,Shipsanity: Fish Taco,"SHIPSANITY", -2497,Farm,Shipsanity: Fried Calamari,"SHIPSANITY", -2498,Farm,Shipsanity: Fried Eel,"SHIPSANITY", -2499,Farm,Shipsanity: Fried Egg,"SHIPSANITY", -2500,Farm,Shipsanity: Fried Mushroom,"SHIPSANITY", -2501,Farm,Shipsanity: Fruit Salad,"SHIPSANITY", -2502,Farm,Shipsanity: Glazed Yams,"SHIPSANITY", -2503,Farm,Shipsanity: Hashbrowns,"SHIPSANITY", -2504,Farm,Shipsanity: Ice Cream,"SHIPSANITY", -2505,Farm,Shipsanity: Lobster Bisque,"SHIPSANITY", -2506,Farm,Shipsanity: Lucky Lunch,"SHIPSANITY", -2507,Farm,Shipsanity: Maki Roll,"SHIPSANITY", -2508,Farm,Shipsanity: Maple Bar,"SHIPSANITY", -2509,Farm,Shipsanity: Miner's Treat,"SHIPSANITY", -2510,Farm,Shipsanity: Omelet,"SHIPSANITY", -2511,Farm,Shipsanity: Pale Broth,"SHIPSANITY", -2512,Farm,Shipsanity: Pancakes,"SHIPSANITY", -2513,Farm,Shipsanity: Parsnip Soup,"SHIPSANITY", -2514,Farm,Shipsanity: Pepper Poppers,"SHIPSANITY", -2515,Farm,Shipsanity: Pink Cake,"SHIPSANITY", -2516,Farm,Shipsanity: Pizza,"SHIPSANITY", -2517,Farm,Shipsanity: Plum Pudding,"SHIPSANITY", -2518,Farm,Shipsanity: Poppyseed Muffin,"SHIPSANITY", -2519,Farm,Shipsanity: Pumpkin Pie,"SHIPSANITY", -2520,Farm,Shipsanity: Pumpkin Soup,"SHIPSANITY", -2521,Farm,Shipsanity: Radish Salad,"SHIPSANITY", -2522,Farm,Shipsanity: Red Plate,"SHIPSANITY", -2523,Farm,Shipsanity: Rhubarb Pie,"SHIPSANITY", -2524,Farm,Shipsanity: Rice Pudding,"SHIPSANITY", -2525,Farm,Shipsanity: Roasted Hazelnuts,"SHIPSANITY", -2526,Farm,Shipsanity: Roots Platter,"SHIPSANITY", -2527,Farm,Shipsanity: Salad,"SHIPSANITY", -2528,Farm,Shipsanity: Salmon Dinner,"SHIPSANITY", -2529,Farm,Shipsanity: Sashimi,"SHIPSANITY", -2530,Farm,Shipsanity: Seafoam Pudding,"SHIPSANITY", -2531,Farm,Shipsanity: Shrimp Cocktail,"SHIPSANITY", -2532,Farm,Shipsanity: Spaghetti,"SHIPSANITY", -2533,Farm,Shipsanity: Spicy Eel,"SHIPSANITY", -2534,Farm,Shipsanity: Squid Ink Ravioli,"SHIPSANITY", -2535,Farm,Shipsanity: Stir Fry,"SHIPSANITY", -2536,Farm,Shipsanity: Strange Bun,"SHIPSANITY", -2537,Farm,Shipsanity: Stuffing,"SHIPSANITY", -2538,Farm,Shipsanity: Super Meal,"SHIPSANITY", -2539,Farm,Shipsanity: Survival Burger,"SHIPSANITY", -2540,Farm,Shipsanity: Tom Kha Soup,"SHIPSANITY", -2541,Farm,Shipsanity: Tortilla,"SHIPSANITY", -2542,Farm,Shipsanity: Triple Shot Espresso,"SHIPSANITY", -2543,Farm,Shipsanity: Trout Soup,"SHIPSANITY", -2544,Farm,Shipsanity: Vegetable Medley,"SHIPSANITY", -2545,Farm,Shipsanity: Bait,"SHIPSANITY", -2546,Farm,Shipsanity: Barbed Hook,"SHIPSANITY", -2547,Farm,Shipsanity: Basic Fertilizer,"SHIPSANITY", -2548,Farm,Shipsanity: Basic Retaining Soil,"SHIPSANITY", -2549,Farm,Shipsanity: Blue Slime Egg,"SHIPSANITY", -2550,Farm,Shipsanity: Bomb,"SHIPSANITY", -2551,Farm,Shipsanity: Brick Floor,"SHIPSANITY", -2552,Farm,Shipsanity: Bug Steak,"SHIPSANITY", -2553,Farm,Shipsanity: Cherry Bomb,"SHIPSANITY", -2554,Farm,Shipsanity: Cobblestone Path,"SHIPSANITY", -2555,Farm,Shipsanity: Cookout Kit,"SHIPSANITY", -2556,Farm,Shipsanity: Cork Bobber,"SHIPSANITY", -2557,Farm,Shipsanity: Crab Pot,"SHIPSANITY", -2558,Farm,Shipsanity: Crystal Floor,"SHIPSANITY", -2559,Farm,Shipsanity: Crystal Path,"SHIPSANITY", -2560,Farm,Shipsanity: Deluxe Speed-Gro,"SHIPSANITY", -2561,Farm,Shipsanity: Dressed Spinner,"SHIPSANITY", -2562,Farm,Shipsanity: Drum Block,"SHIPSANITY", -2563,Farm,Shipsanity: Explosive Ammo,"SHIPSANITY", -2564,Farm,Shipsanity: Fiber Seeds,"SHIPSANITY", -2565,Farm,Shipsanity: Field Snack,"SHIPSANITY", -2566,Farm,Shipsanity: Flute Block,"SHIPSANITY", -2567,Farm,Shipsanity: Gate,"SHIPSANITY", -2568,Farm,Shipsanity: Gravel Path,"SHIPSANITY", -2569,Farm,Shipsanity: Green Slime Egg,"SHIPSANITY", -2570,Farm,Shipsanity: Hardwood Fence,"SHIPSANITY", -2571,Farm,Shipsanity: Iridium Sprinkler,"SHIPSANITY", -2572,Farm,Shipsanity: Iron Fence,"SHIPSANITY", -2573,Farm,Shipsanity: Jack-O-Lantern,"SHIPSANITY", -2574,Farm,Shipsanity: Lead Bobber,"SHIPSANITY", -2575,Farm,Shipsanity: Life Elixir,"SHIPSANITY", -2576,Farm,Shipsanity: Magnet,"SHIPSANITY", -2577,Farm,Shipsanity: Mega Bomb,"SHIPSANITY", -2578,Farm,Shipsanity: Monster Musk,"SHIPSANITY", -2579,Farm,Shipsanity: Oil of Garlic,"SHIPSANITY", -2580,Farm,Shipsanity: Purple Slime Egg,"SHIPSANITY", -2581,Farm,Shipsanity: Quality Bobber,"SHIPSANITY", -2582,Farm,Shipsanity: Quality Fertilizer,"SHIPSANITY", -2583,Farm,Shipsanity: Quality Retaining Soil,"SHIPSANITY", -2584,Farm,Shipsanity: Quality Sprinkler,"SHIPSANITY", -2585,Farm,Shipsanity: Rain Totem,"SHIPSANITY", -2586,Farm,Shipsanity: Red Slime Egg,"SHIPSANITY", -2587,Farm,Shipsanity: Rustic Plank Floor,"SHIPSANITY", -2588,Farm,Shipsanity: Speed-Gro,"SHIPSANITY", -2589,Farm,Shipsanity: Spinner,"SHIPSANITY", -2590,Farm,Shipsanity: Sprinkler,"SHIPSANITY", -2591,Farm,Shipsanity: Stepping Stone Path,"SHIPSANITY", -2592,Farm,Shipsanity: Stone Fence,"SHIPSANITY", -2593,Farm,Shipsanity: Stone Floor,"SHIPSANITY", -2594,Farm,Shipsanity: Stone Walkway Floor,"SHIPSANITY", -2595,Farm,Shipsanity: Straw Floor,"SHIPSANITY", -2596,Farm,Shipsanity: Torch,"SHIPSANITY", -2597,Farm,Shipsanity: Trap Bobber,"SHIPSANITY", -2598,Farm,Shipsanity: Treasure Hunter,"SHIPSANITY", -2599,Farm,Shipsanity: Tree Fertilizer,"SHIPSANITY", -2600,Farm,Shipsanity: Warp Totem: Beach,"SHIPSANITY", -2601,Farm,Shipsanity: Warp Totem: Desert,"SHIPSANITY", -2602,Farm,Shipsanity: Warp Totem: Farm,"SHIPSANITY", -2603,Farm,Shipsanity: Warp Totem: Island,"SHIPSANITY", -2604,Farm,Shipsanity: Warp Totem: Mountains,"SHIPSANITY", -2605,Farm,Shipsanity: Weathered Floor,"SHIPSANITY", -2606,Farm,Shipsanity: Wild Bait,"SHIPSANITY", -2607,Farm,Shipsanity: Wood Fence,"SHIPSANITY", -2608,Farm,Shipsanity: Wood Floor,"SHIPSANITY", -2609,Farm,Shipsanity: Wood Path,"SHIPSANITY", -2610,Farm,Shipsanity: Amaranth,"SHIPSANITY", -2611,Farm,Shipsanity: Ancient Fruit,"SHIPSANITY", -2612,Farm,Shipsanity: Apple,"SHIPSANITY", -2613,Farm,Shipsanity: Apricot,"SHIPSANITY", -2614,Farm,Shipsanity: Artichoke,"SHIPSANITY", -2615,Farm,Shipsanity: Beet,"SHIPSANITY", -2616,Farm,Shipsanity: Blue Jazz,"SHIPSANITY", -2617,Farm,Shipsanity: Blueberry,"SHIPSANITY", -2618,Farm,Shipsanity: Bok Choy,"SHIPSANITY", -2619,Farm,Shipsanity: Cauliflower,"SHIPSANITY", -2620,Farm,Shipsanity: Cherry,"SHIPSANITY", -2621,Farm,Shipsanity: Corn,"SHIPSANITY", -2622,Farm,Shipsanity: Cranberries,"SHIPSANITY", -2623,Farm,Shipsanity: Eggplant,"SHIPSANITY", -2624,Farm,Shipsanity: Fairy Rose,"SHIPSANITY", -2625,Farm,Shipsanity: Garlic,"SHIPSANITY", -2626,Farm,Shipsanity: Grape,"SHIPSANITY", -2627,Farm,Shipsanity: Green Bean,"SHIPSANITY", -2628,Farm,Shipsanity: Hops,"SHIPSANITY", -2629,Farm,Shipsanity: Hot Pepper,"SHIPSANITY", -2630,Farm,Shipsanity: Kale,"SHIPSANITY", -2631,Farm,Shipsanity: Melon,"SHIPSANITY", -2632,Farm,Shipsanity: Orange,"SHIPSANITY", -2633,Farm,Shipsanity: Parsnip,"SHIPSANITY", -2634,Farm,Shipsanity: Peach,"SHIPSANITY", -2635,Farm,Shipsanity: Pomegranate,"SHIPSANITY", -2636,Farm,Shipsanity: Poppy,"SHIPSANITY", -2637,Farm,Shipsanity: Potato,"SHIPSANITY", -2638,Farm,Shipsanity: Pumpkin,"SHIPSANITY", -2639,Farm,Shipsanity: Radish,"SHIPSANITY", -2640,Farm,Shipsanity: Red Cabbage,"SHIPSANITY", -2641,Farm,Shipsanity: Rhubarb,"SHIPSANITY", -2642,Farm,Shipsanity: Starfruit,"SHIPSANITY", -2643,Farm,Shipsanity: Strawberry,"SHIPSANITY", -2644,Farm,Shipsanity: Summer Spangle,"SHIPSANITY", -2645,Farm,Shipsanity: Sunflower,"SHIPSANITY", -2646,Farm,Shipsanity: Sweet Gem Berry,"SHIPSANITY", -2647,Farm,Shipsanity: Tea Leaves,"SHIPSANITY", -2648,Farm,Shipsanity: Tomato,"SHIPSANITY", -2649,Farm,Shipsanity: Tulip,"SHIPSANITY", -2650,Farm,Shipsanity: Unmilled Rice,"SHIPSANITY", -2651,Farm,Shipsanity: Wheat,"SHIPSANITY", -2652,Farm,Shipsanity: Yam,"SHIPSANITY", -2653,Farm,Shipsanity: Albacore,"SHIPSANITY", -2654,Farm,Shipsanity: Anchovy,"SHIPSANITY", -2655,Farm,Shipsanity: Angler,"SHIPSANITY", -2656,Farm,Shipsanity: Blobfish,"SHIPSANITY", -2657,Farm,Shipsanity: Bream,"SHIPSANITY", -2658,Farm,Shipsanity: Bullhead,"SHIPSANITY", -2659,Farm,Shipsanity: Carp,"SHIPSANITY", -2660,Farm,Shipsanity: Catfish,"SHIPSANITY", -2661,Farm,Shipsanity: Chub,"SHIPSANITY", -2662,Farm,Shipsanity: Cockle,"SHIPSANITY", -2663,Farm,Shipsanity: Crab,"SHIPSANITY", -2664,Farm,Shipsanity: Crayfish,"SHIPSANITY", -2665,Farm,Shipsanity: Crimsonfish,"SHIPSANITY", -2666,Farm,Shipsanity: Dorado,"SHIPSANITY", -2667,Farm,Shipsanity: Eel,"SHIPSANITY", -2668,Farm,Shipsanity: Flounder,"SHIPSANITY", -2669,Farm,Shipsanity: Ghostfish,"SHIPSANITY", -2670,Farm,Shipsanity: Glacierfish,"SHIPSANITY", -2671,Farm,Shipsanity: Halibut,"SHIPSANITY", -2672,Farm,Shipsanity: Herring,"SHIPSANITY", -2673,Farm,Shipsanity: Ice Pip,"SHIPSANITY", -2674,Farm,Shipsanity: Largemouth Bass,"SHIPSANITY", -2675,Farm,Shipsanity: Lava Eel,"SHIPSANITY", -2676,Farm,Shipsanity: Legend,"SHIPSANITY", -2677,Farm,Shipsanity: Lingcod,"SHIPSANITY", -2678,Farm,Shipsanity: Lobster,"SHIPSANITY", -2679,Farm,Shipsanity: Midnight Carp,"SHIPSANITY", -2680,Farm,Shipsanity: Midnight Squid,"SHIPSANITY", -2681,Farm,Shipsanity: Mussel,"SHIPSANITY", -2682,Farm,Shipsanity: Mutant Carp,"SHIPSANITY", -2683,Farm,Shipsanity: Octopus,"SHIPSANITY", -2684,Farm,Shipsanity: Oyster,"SHIPSANITY", -2685,Farm,Shipsanity: Perch,"SHIPSANITY", -2686,Farm,Shipsanity: Periwinkle,"SHIPSANITY", -2687,Farm,Shipsanity: Pike,"SHIPSANITY", -2688,Farm,Shipsanity: Pufferfish,"SHIPSANITY", -2689,Farm,Shipsanity: Rainbow Trout,"SHIPSANITY", -2690,Farm,Shipsanity: Red Mullet,"SHIPSANITY", -2691,Farm,Shipsanity: Red Snapper,"SHIPSANITY", -2692,Farm,Shipsanity: Salmon,"SHIPSANITY", -2693,Farm,Shipsanity: Sandfish,"SHIPSANITY", -2694,Farm,Shipsanity: Sardine,"SHIPSANITY", -2695,Farm,Shipsanity: Scorpion Carp,"SHIPSANITY", -2696,Farm,Shipsanity: Sea Cucumber,"SHIPSANITY", -2697,Farm,Shipsanity: Shad,"SHIPSANITY", -2698,Farm,Shipsanity: Shrimp,"SHIPSANITY", -2699,Farm,Shipsanity: Slimejack,"SHIPSANITY", -2700,Farm,Shipsanity: Smallmouth Bass,"SHIPSANITY", -2701,Farm,Shipsanity: Snail,"SHIPSANITY", -2702,Farm,Shipsanity: Spook Fish,"SHIPSANITY", -2703,Farm,Shipsanity: Squid,"SHIPSANITY", -2704,Farm,Shipsanity: Stonefish,"SHIPSANITY", -2705,Farm,Shipsanity: Sturgeon,"SHIPSANITY", -2706,Farm,Shipsanity: Sunfish,"SHIPSANITY", -2707,Farm,Shipsanity: Super Cucumber,"SHIPSANITY", -2708,Farm,Shipsanity: Tiger Trout,"SHIPSANITY", -2709,Farm,Shipsanity: Tilapia,"SHIPSANITY", -2710,Farm,Shipsanity: Tuna,"SHIPSANITY", -2711,Farm,Shipsanity: Void Salmon,"SHIPSANITY", -2712,Farm,Shipsanity: Walleye,"SHIPSANITY", -2713,Farm,Shipsanity: Woodskip,"SHIPSANITY", -2714,Farm,Shipsanity: Blackberry,"SHIPSANITY", -2715,Farm,Shipsanity: Cactus Fruit,"SHIPSANITY", -2716,Farm,Shipsanity: Cave Carrot,"SHIPSANITY", -2717,Farm,Shipsanity: Chanterelle,"SHIPSANITY", -2718,Farm,Shipsanity: Clam,"SHIPSANITY", -2719,Farm,Shipsanity: Coconut,"SHIPSANITY", -2720,Farm,Shipsanity: Common Mushroom,"SHIPSANITY", -2721,Farm,Shipsanity: Coral,"SHIPSANITY", -2722,Farm,Shipsanity: Crocus,"SHIPSANITY", -2723,Farm,Shipsanity: Crystal Fruit,"SHIPSANITY", -2724,Farm,Shipsanity: Daffodil,"SHIPSANITY", -2725,Farm,Shipsanity: Dandelion,"SHIPSANITY", -2726,Farm,Shipsanity: Fiddlehead Fern,"SHIPSANITY", -2727,Farm,Shipsanity: Hazelnut,"SHIPSANITY", -2728,Farm,Shipsanity: Holly,"SHIPSANITY", -2729,Farm,Shipsanity: Leek,"SHIPSANITY", -2730,Farm,Shipsanity: Morel,"SHIPSANITY", -2731,Farm,Shipsanity: Nautilus Shell,"SHIPSANITY", -2732,Farm,Shipsanity: Purple Mushroom,"SHIPSANITY", -2733,Farm,Shipsanity: Rainbow Shell,"SHIPSANITY", -2734,Farm,Shipsanity: Red Mushroom,"SHIPSANITY", -2735,Farm,Shipsanity: Salmonberry,"SHIPSANITY", -2736,Farm,Shipsanity: Sea Urchin,"SHIPSANITY", -2737,Farm,Shipsanity: Snow Yam,"SHIPSANITY", -2738,Farm,Shipsanity: Spice Berry,"SHIPSANITY", -2739,Farm,Shipsanity: Spring Onion,"SHIPSANITY", -2740,Farm,Shipsanity: Sweet Pea,"SHIPSANITY", -2741,Farm,Shipsanity: Wild Horseradish,"SHIPSANITY", -2742,Farm,Shipsanity: Wild Plum,"SHIPSANITY", -2743,Farm,Shipsanity: Winter Root,"SHIPSANITY", -2744,Farm,Shipsanity: Tea Set,"SHIPSANITY", -2745,Farm,Shipsanity: Battery Pack,"SHIPSANITY", -2746,Farm,Shipsanity: Clay,"SHIPSANITY", -2747,Farm,Shipsanity: Copper Bar,"SHIPSANITY", -2748,Farm,Shipsanity: Fiber,"SHIPSANITY", -2749,Farm,Shipsanity: Gold Bar,"SHIPSANITY", -2750,Farm,Shipsanity: Hardwood,"SHIPSANITY", -2751,Farm,Shipsanity: Iridium Bar,"SHIPSANITY", -2752,Farm,Shipsanity: Iron Bar,"SHIPSANITY", -2753,Farm,Shipsanity: Lumber,"SHIPSANITY", -2754,Farm,Shipsanity: Oil,"SHIPSANITY", -2755,Farm,Shipsanity: Refined Quartz,"SHIPSANITY", -2756,Farm,Shipsanity: Rice,"SHIPSANITY", -2757,Farm,Shipsanity: Sap,"SHIPSANITY", -2758,Farm,Shipsanity: Stone,"SHIPSANITY", -2759,Farm,Shipsanity: Sugar,"SHIPSANITY", -2760,Farm,Shipsanity: Vinegar,"SHIPSANITY", -2761,Farm,Shipsanity: Wheat Flour,"SHIPSANITY", -2762,Farm,Shipsanity: Wood,"SHIPSANITY", -2763,Farm,Shipsanity: Aerinite,"SHIPSANITY", -2764,Farm,Shipsanity: Alamite,"SHIPSANITY", -2765,Farm,Shipsanity: Amethyst,"SHIPSANITY", -2766,Farm,Shipsanity: Amphibian Fossil,"SHIPSANITY", -2767,Farm,Shipsanity: Aquamarine,"SHIPSANITY", -2768,Farm,Shipsanity: Baryte,"SHIPSANITY", -2769,Farm,Shipsanity: Basalt,"SHIPSANITY", -2770,Farm,Shipsanity: Bixite,"SHIPSANITY", -2771,Farm,Shipsanity: Calcite,"SHIPSANITY", -2772,Farm,Shipsanity: Celestine,"SHIPSANITY", -2773,Farm,Shipsanity: Coal,"SHIPSANITY", -2774,Farm,Shipsanity: Copper Ore,"SHIPSANITY", -2775,Farm,Shipsanity: Diamond,"SHIPSANITY", -2776,Farm,Shipsanity: Dolomite,"SHIPSANITY", -2777,Farm,Shipsanity: Earth Crystal,"SHIPSANITY", -2778,Farm,Shipsanity: Emerald,"SHIPSANITY", -2779,Farm,Shipsanity: Esperite,"SHIPSANITY", -2780,Farm,Shipsanity: Fairy Stone,"SHIPSANITY", -2781,Farm,Shipsanity: Fire Opal,"SHIPSANITY", -2782,Farm,Shipsanity: Fire Quartz,"SHIPSANITY", -2783,Farm,Shipsanity: Fluorapatite,"SHIPSANITY", -2784,Farm,Shipsanity: Frozen Geode,"SHIPSANITY", -2785,Farm,Shipsanity: Frozen Tear,"SHIPSANITY", -2786,Farm,Shipsanity: Geminite,"SHIPSANITY", -2787,Farm,Shipsanity: Geode,"SHIPSANITY", -2788,Farm,Shipsanity: Ghost Crystal,"SHIPSANITY", -2789,Farm,Shipsanity: Gold Ore,"SHIPSANITY", -2790,Farm,Shipsanity: Granite,"SHIPSANITY", -2791,Farm,Shipsanity: Helvite,"SHIPSANITY", -2792,Farm,Shipsanity: Hematite,"SHIPSANITY", -2793,Farm,Shipsanity: Iridium Ore,"SHIPSANITY", -2794,Farm,Shipsanity: Iron Ore,"SHIPSANITY", -2795,Farm,Shipsanity: Jade,"SHIPSANITY", -2796,Farm,Shipsanity: Jagoite,"SHIPSANITY", -2797,Farm,Shipsanity: Jamborite,"SHIPSANITY", -2798,Farm,Shipsanity: Jasper,"SHIPSANITY", -2799,Farm,Shipsanity: Kyanite,"SHIPSANITY", -2800,Farm,Shipsanity: Lemon Stone,"SHIPSANITY", -2801,Farm,Shipsanity: Limestone,"SHIPSANITY", -2802,Farm,Shipsanity: Lunarite,"SHIPSANITY", -2803,Farm,Shipsanity: Magma Geode,"SHIPSANITY", -2804,Farm,Shipsanity: Malachite,"SHIPSANITY", -2805,Farm,Shipsanity: Marble,"SHIPSANITY", -2806,Farm,Shipsanity: Mudstone,"SHIPSANITY", -2807,Farm,Shipsanity: Nautilus Fossil,"SHIPSANITY", -2808,Farm,Shipsanity: Nekoite,"SHIPSANITY", -2809,Farm,Shipsanity: Neptunite,"SHIPSANITY", -2810,Farm,Shipsanity: Obsidian,"SHIPSANITY", -2811,Farm,Shipsanity: Ocean Stone,"SHIPSANITY", -2812,Farm,Shipsanity: Omni Geode,"SHIPSANITY", -2813,Farm,Shipsanity: Opal,"SHIPSANITY", -2814,Farm,Shipsanity: Orpiment,"SHIPSANITY", -2815,Farm,Shipsanity: Palm Fossil,"SHIPSANITY", -2816,Farm,Shipsanity: Petrified Slime,"SHIPSANITY", -2817,Farm,Shipsanity: Prehistoric Rib,"SHIPSANITY", -2818,Farm,Shipsanity: Prehistoric Scapula,"SHIPSANITY", -2819,Farm,Shipsanity: Prehistoric Skull,"SHIPSANITY", -2820,Farm,Shipsanity: Prehistoric Tibia,"SHIPSANITY", -2821,Farm,Shipsanity: Prehistoric Vertebra,"SHIPSANITY", -2822,Farm,Shipsanity: Prismatic Shard,"SHIPSANITY", -2823,Farm,Shipsanity: Pyrite,"SHIPSANITY", -2824,Farm,Shipsanity: Quartz,"SHIPSANITY", -2825,Farm,Shipsanity: Ruby,"SHIPSANITY", -2826,Farm,Shipsanity: Sandstone,"SHIPSANITY", -2827,Farm,Shipsanity: Skeletal Hand,"SHIPSANITY", -2828,Farm,Shipsanity: Skeletal Tail,"SHIPSANITY", -2829,Farm,Shipsanity: Slate,"SHIPSANITY", -2830,Farm,Shipsanity: Soapstone,"SHIPSANITY", -2831,Farm,Shipsanity: Star Shards,"SHIPSANITY", -2832,Farm,Shipsanity: Thunder Egg,"SHIPSANITY", -2833,Farm,Shipsanity: Tigerseye,"SHIPSANITY", -2834,Farm,Shipsanity: Topaz,"SHIPSANITY", -2835,Farm,Shipsanity: Trilobite,"SHIPSANITY", -2836,Farm,Shipsanity: Bat Wing,"SHIPSANITY", -2837,Farm,Shipsanity: Bone Fragment,"SHIPSANITY", -2838,Farm,Shipsanity: Curiosity Lure,"SHIPSANITY", -2839,Farm,Shipsanity: Slime,"SHIPSANITY", -2840,Farm,Shipsanity: Solar Essence,"SHIPSANITY", -2841,Farm,Shipsanity: Squid Ink,"SHIPSANITY", -2842,Farm,Shipsanity: Void Essence,"SHIPSANITY", -2843,Farm,Shipsanity: Bouquet,"SHIPSANITY", -2844,Farm,Shipsanity: Energy Tonic,"SHIPSANITY", -2845,Farm,Shipsanity: Golden Pumpkin,"SHIPSANITY", -2846,Farm,Shipsanity: Green Algae,"SHIPSANITY", -2847,Farm,Shipsanity: Hay,"SHIPSANITY", -2848,Farm,Shipsanity: Magic Rock Candy,"SHIPSANITY", -2849,Farm,Shipsanity: Muscle Remedy,"SHIPSANITY", -2850,Farm,Shipsanity: Pearl,"SHIPSANITY", -2851,Farm,Shipsanity: Rotten Plant,"SHIPSANITY", -2852,Farm,Shipsanity: Seaweed,"SHIPSANITY", -2853,Farm,Shipsanity: Void Ghost Pendant,"SHIPSANITY", -2854,Farm,Shipsanity: White Algae,"SHIPSANITY", -2855,Farm,Shipsanity: Wilted Bouquet,"SHIPSANITY", -2856,Farm,Shipsanity: Secret Note,"SHIPSANITY", -2857,Farm,Shipsanity: Acorn,"SHIPSANITY", -2858,Farm,Shipsanity: Amaranth Seeds,"SHIPSANITY", -2859,Farm,Shipsanity: Ancient Seeds,"SHIPSANITY", -2860,Farm,Shipsanity: Apple Sapling,"SHIPSANITY", -2861,Farm,Shipsanity: Apricot Sapling,"SHIPSANITY", -2862,Farm,Shipsanity: Artichoke Seeds,"SHIPSANITY", -2863,Farm,Shipsanity: Bean Starter,"SHIPSANITY", -2864,Farm,Shipsanity: Beet Seeds,"SHIPSANITY", -2865,Farm,Shipsanity: Blueberry Seeds,"SHIPSANITY", -2866,Farm,Shipsanity: Bok Choy Seeds,"SHIPSANITY", -2867,Farm,Shipsanity: Cactus Seeds,"SHIPSANITY", -2868,Farm,Shipsanity: Cauliflower Seeds,"SHIPSANITY", -2869,Farm,Shipsanity: Cherry Sapling,"SHIPSANITY", -2870,Farm,Shipsanity: Coffee Bean,"SHIPSANITY", -2871,Farm,Shipsanity: Corn Seeds,"SHIPSANITY", -2872,Farm,Shipsanity: Cranberry Seeds,"SHIPSANITY", -2873,Farm,Shipsanity: Eggplant Seeds,"SHIPSANITY", -2874,Farm,Shipsanity: Fairy Seeds,"SHIPSANITY", -2875,Farm,Shipsanity: Fall Seeds,"SHIPSANITY", -2876,Farm,Shipsanity: Garlic Seeds,"SHIPSANITY", -2877,Farm,Shipsanity: Grape Starter,"SHIPSANITY", -2878,Farm,Shipsanity: Grass Starter,"SHIPSANITY", -2879,Farm,Shipsanity: Hops Starter,"SHIPSANITY", -2880,Farm,Shipsanity: Jazz Seeds,"SHIPSANITY", -2881,Farm,Shipsanity: Kale Seeds,"SHIPSANITY", -2882,Farm,Shipsanity: Mahogany Seed,"SHIPSANITY", -2883,Farm,Shipsanity: Maple Seed,"SHIPSANITY", -2884,Farm,Shipsanity: Melon Seeds,"SHIPSANITY", -2885,Farm,Shipsanity: Mixed Seeds,"SHIPSANITY", -2886,Farm,Shipsanity: Orange Sapling,"SHIPSANITY", -2887,Farm,Shipsanity: Parsnip Seeds,"SHIPSANITY", -2888,Farm,Shipsanity: Peach Sapling,"SHIPSANITY", -2889,Farm,Shipsanity: Pepper Seeds,"SHIPSANITY", -2890,Farm,Shipsanity: Pine Cone,"SHIPSANITY", -2891,Farm,Shipsanity: Pomegranate Sapling,"SHIPSANITY", -2892,Farm,Shipsanity: Poppy Seeds,"SHIPSANITY", -2893,Farm,Shipsanity: Potato Seeds,"SHIPSANITY", -2894,Farm,Shipsanity: Pumpkin Seeds,"SHIPSANITY", -2895,Farm,Shipsanity: Radish Seeds,"SHIPSANITY", -2896,Farm,Shipsanity: Rare Seed,"SHIPSANITY", -2897,Farm,Shipsanity: Red Cabbage Seeds,"SHIPSANITY", -2898,Farm,Shipsanity: Rhubarb Seeds,"SHIPSANITY", -2899,Farm,Shipsanity: Rice Shoot,"SHIPSANITY", -2900,Farm,Shipsanity: Spangle Seeds,"SHIPSANITY", -2901,Farm,Shipsanity: Spring Seeds,"SHIPSANITY", -2902,Farm,Shipsanity: Starfruit Seeds,"SHIPSANITY", -2903,Farm,Shipsanity: Strawberry Seeds,"SHIPSANITY", -2904,Farm,Shipsanity: Summer Seeds,"SHIPSANITY", -2905,Farm,Shipsanity: Sunflower Seeds,"SHIPSANITY", -2906,Farm,Shipsanity: Tea Sapling,"SHIPSANITY", -2907,Farm,Shipsanity: Tomato Seeds,"SHIPSANITY", -2908,Farm,Shipsanity: Tulip Bulb,"SHIPSANITY", -2909,Farm,Shipsanity: Wheat Seeds,"SHIPSANITY", -2910,Farm,Shipsanity: Winter Seeds,"SHIPSANITY", -2911,Farm,Shipsanity: Yam Seeds,"SHIPSANITY", -2912,Farm,Shipsanity: Broken CD,"SHIPSANITY", -2913,Farm,Shipsanity: Broken Glasses,"SHIPSANITY", -2914,Farm,Shipsanity: Driftwood,"SHIPSANITY", -2915,Farm,Shipsanity: Joja Cola,"SHIPSANITY", -2916,Farm,Shipsanity: Soggy Newspaper,"SHIPSANITY", -2917,Farm,Shipsanity: Trash,"SHIPSANITY", -2918,Farm,Shipsanity: Bug Meat,"SHIPSANITY", -2919,Farm,Shipsanity: Golden Egg,"SHIPSANITY", -2920,Farm,Shipsanity: Ostrich Egg,"SHIPSANITY,GINGER_ISLAND", -2921,Farm,Shipsanity: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND", -2922,Farm,Shipsanity: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND", -2923,Farm,Shipsanity: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND", -2924,Farm,Shipsanity: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND", -2925,Farm,Shipsanity: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND", -2926,Farm,Shipsanity: Mummified Bat,"SHIPSANITY,GINGER_ISLAND", -2927,Farm,Shipsanity: Mummified Frog,"SHIPSANITY,GINGER_ISLAND", -2928,Farm,Shipsanity: Snake Skull,"SHIPSANITY,GINGER_ISLAND", -2929,Farm,Shipsanity: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND", -2930,Farm,Shipsanity: Banana Pudding,"SHIPSANITY,GINGER_ISLAND", -2931,Farm,Shipsanity: Ginger Ale,"SHIPSANITY,GINGER_ISLAND", -2932,Farm,Shipsanity: Mango Sticky Rice,"SHIPSANITY,GINGER_ISLAND", -2933,Farm,Shipsanity: Piña Colada,"SHIPSANITY,GINGER_ISLAND", -2934,Farm,Shipsanity: Poi,"SHIPSANITY,GINGER_ISLAND", -2935,Farm,Shipsanity: Tropical Curry,"SHIPSANITY,GINGER_ISLAND", -2936,Farm,Shipsanity: Deluxe Fertilizer,"SHIPSANITY,GINGER_ISLAND", -2937,Farm,Shipsanity: Deluxe Retaining Soil,"SHIPSANITY,GINGER_ISLAND", -2938,Farm,Shipsanity: Fairy Dust,"SHIPSANITY,GINGER_ISLAND", -2939,Farm,Shipsanity: Hyper Speed-Gro,"SHIPSANITY,GINGER_ISLAND", -2940,Farm,Shipsanity: Magic Bait,"SHIPSANITY,GINGER_ISLAND", -2941,Farm,Shipsanity: Banana,"SHIPSANITY,GINGER_ISLAND", -2942,Farm,Shipsanity: Mango,"SHIPSANITY,GINGER_ISLAND", -2943,Farm,Shipsanity: Pineapple,"SHIPSANITY,GINGER_ISLAND", -2944,Farm,Shipsanity: Qi Fruit,"SHIPSANITY,GINGER_ISLAND", -2945,Farm,Shipsanity: Taro Root,"SHIPSANITY,GINGER_ISLAND", -2946,Farm,Shipsanity: Blue Discus,"SHIPSANITY,GINGER_ISLAND", -2947,Farm,Shipsanity: Glacierfish Jr.,"SHIPSANITY,GINGER_ISLAND", -2948,Farm,Shipsanity: Legend II,"SHIPSANITY,GINGER_ISLAND", -2949,Farm,Shipsanity: Lionfish,"SHIPSANITY,GINGER_ISLAND", -2950,Farm,Shipsanity: Ms. Angler,"SHIPSANITY,GINGER_ISLAND", -2951,Farm,Shipsanity: Radioactive Carp,"SHIPSANITY,GINGER_ISLAND", -2952,Farm,Shipsanity: Son of Crimsonfish,"SHIPSANITY,GINGER_ISLAND", -2953,Farm,Shipsanity: Stingray,"SHIPSANITY,GINGER_ISLAND", -2954,Farm,Shipsanity: Ginger,"SHIPSANITY,GINGER_ISLAND", -2955,Farm,Shipsanity: Magma Cap,"SHIPSANITY,GINGER_ISLAND", -2956,Farm,Shipsanity: Cinder Shard,"SHIPSANITY,GINGER_ISLAND", -2957,Farm,Shipsanity: Dragon Tooth,"SHIPSANITY,GINGER_ISLAND", -2958,Farm,Shipsanity: Qi Seasoning,"SHIPSANITY,GINGER_ISLAND", -2959,Farm,Shipsanity: Radioactive Bar,"SHIPSANITY,GINGER_ISLAND", -2960,Farm,Shipsanity: Radioactive Ore,"SHIPSANITY,GINGER_ISLAND", -2961,Farm,Shipsanity: Enricher,"SHIPSANITY,GINGER_ISLAND", -2962,Farm,Shipsanity: Pressure Nozzle,"SHIPSANITY,GINGER_ISLAND", -2963,Farm,Shipsanity: Galaxy Soul,"SHIPSANITY,GINGER_ISLAND", -2964,Farm,Shipsanity: Tiger Slime Egg,"SHIPSANITY,GINGER_ISLAND", -2965,Farm,Shipsanity: Movie Ticket,"SHIPSANITY,GINGER_ISLAND", -2966,Farm,Shipsanity: Journal Scrap,"SHIPSANITY,GINGER_ISLAND", -2967,Farm,Shipsanity: Banana Sapling,"SHIPSANITY,GINGER_ISLAND", -2968,Farm,Shipsanity: Mango Sapling,"SHIPSANITY,GINGER_ISLAND", -2969,Farm,Shipsanity: Mushroom Tree Seed,"SHIPSANITY,GINGER_ISLAND", -2970,Farm,Shipsanity: Pineapple Seeds,"SHIPSANITY,GINGER_ISLAND", -2971,Farm,Shipsanity: Qi Bean,"SHIPSANITY,GINGER_ISLAND", -2972,Farm,Shipsanity: Taro Tuber,"SHIPSANITY,GINGER_ISLAND", -3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", -3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", -3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", -3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", -3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", -3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", -3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", -3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", -3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", -3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS,GINGER_ISLAND", -3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", -3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", -3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", -3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS,GINGER_ISLAND", -3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3102,Adventurer's Guild,Monster Eradication: Blue Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3103,Adventurer's Guild,Monster Eradication: Red Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3104,Adventurer's Guild,Monster Eradication: Purple Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3105,Adventurer's Guild,Monster Eradication: Yellow Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3106,Adventurer's Guild,Monster Eradication: Black Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3107,Adventurer's Guild,Monster Eradication: Copper Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3108,Adventurer's Guild,Monster Eradication: Iron Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3109,Adventurer's Guild,Monster Eradication: Tiger Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3110,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3111,Adventurer's Guild,Monster Eradication: Dangerous Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3112,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3113,Adventurer's Guild,Monster Eradication: Dangerous Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3114,Adventurer's Guild,Monster Eradication: Shadow Sniper,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3115,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3116,Adventurer's Guild,Monster Eradication: Dangerous Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3117,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3118,Adventurer's Guild,Monster Eradication: Dangerous Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3119,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3120,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3121,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3122,Adventurer's Guild,Monster Eradication: Dangerous Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3123,Adventurer's Guild,Monster Eradication: Skeleton Mage,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3124,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3125,Adventurer's Guild,Monster Eradication: Dangerous Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3126,Adventurer's Guild,Monster Eradication: Cave Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3127,Adventurer's Guild,Monster Eradication: Dangerous Cave Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3128,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3129,Adventurer's Guild,Monster Eradication: Dangerous Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3130,Adventurer's Guild,Monster Eradication: Mutant Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", -3131,Adventurer's Guild,Monster Eradication: Mutant Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", -3132,Adventurer's Guild,Monster Eradication: Armored Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3133,Adventurer's Guild,Monster Eradication: Dangerous Armored Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3134,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3135,Adventurer's Guild,Monster Eradication: Dangerous Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3136,Adventurer's Guild,Monster Eradication: Magma Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3137,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3138,Adventurer's Guild,Monster Eradication: Dangerous Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3139,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3140,Adventurer's Guild,Monster Eradication: Dangerous Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3141,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3142,Adventurer's Guild,Monster Eradication: Dangerous Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3143,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3144,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3145,Adventurer's Guild,Monster Eradication: Dangerous Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3146,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3147,Adventurer's Guild,Monster Eradication: Royal Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3148,Adventurer's Guild,Monster Eradication: Magma Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -3149,Adventurer's Guild,Monster Eradication: Magma Sparker,"MONSTERSANITY,MONSTERSANITY_MONSTER,GINGER_ISLAND", -5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5011,Stardew Valley,Level 1 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5012,Stardew Valley,Level 2 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5013,Stardew Valley,Level 3 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5014,Stardew Valley,Level 4 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5015,Stardew Valley,Level 5 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5016,Stardew Valley,Level 6 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5017,Stardew Valley,Level 7 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5018,Stardew Valley,Level 8 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5019,Stardew Valley,Level 9 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill -5020,Stardew Valley,Level 10 Socializing,"SOCIALIZING_LEVEL,SKILL_LEVEL",Socializing Skill +2401,Farm,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Farm,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Farm,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Farm,Shipsanity: Brown Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Farm,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Farm,Shipsanity: L. Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Farm,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Farm,Shipsanity: Large Brown Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Farm,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Farm,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Farm,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Farm,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Farm,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Farm,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Farm,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Farm,Shipsanity: Anchor,SHIPSANITY, +2417,Farm,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Farm,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Farm,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Farm,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Farm,Shipsanity: Arrowhead,SHIPSANITY, +2422,Farm,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Farm,Shipsanity: Bone Flute,SHIPSANITY, +2424,Farm,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Farm,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Farm,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Farm,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Farm,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Farm,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Farm,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Farm,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Farm,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Farm,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Farm,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Farm,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Farm,Shipsanity: Glass Shards,SHIPSANITY, +2437,Farm,Shipsanity: Golden Mask,SHIPSANITY, +2438,Farm,Shipsanity: Golden Relic,SHIPSANITY, +2439,Farm,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Farm,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Farm,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Farm,Shipsanity: Rare Disc,SHIPSANITY, +2443,Farm,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Farm,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Farm,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Farm,Shipsanity: Strange Doll,SHIPSANITY, +2447,Farm,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Farm,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Farm,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Farm,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Farm,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Farm,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Farm,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Farm,Shipsanity: Coffee,SHIPSANITY, +2455,Farm,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Farm,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Farm,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Farm,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Farm,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Farm,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Farm,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Farm,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Farm,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Farm,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Farm,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Farm,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Farm,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Farm,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Farm,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Farm,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Farm,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Farm,Shipsanity: Algae Soup,SHIPSANITY, +2473,Farm,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Farm,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Farm,Shipsanity: Baked Fish,SHIPSANITY, +2476,Farm,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Farm,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Farm,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Farm,Shipsanity: Bread,SHIPSANITY, +2480,Farm,Shipsanity: Bruschetta,SHIPSANITY, +2481,Farm,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Farm,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Farm,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Farm,Shipsanity: Chowder,SHIPSANITY, +2485,Farm,Shipsanity: Coleslaw,SHIPSANITY, +2486,Farm,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Farm,Shipsanity: Cookie,SHIPSANITY, +2488,Farm,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Farm,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Farm,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Farm,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Farm,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Farm,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Farm,Shipsanity: Escargot,SHIPSANITY, +2495,Farm,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Farm,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Farm,Shipsanity: Fish Stew,SHIPSANITY, +2498,Farm,Shipsanity: Fish Taco,SHIPSANITY, +2499,Farm,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Farm,Shipsanity: Fried Eel,SHIPSANITY, +2501,Farm,Shipsanity: Fried Egg,SHIPSANITY, +2502,Farm,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Farm,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Farm,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Farm,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Farm,Shipsanity: Ice Cream,SHIPSANITY, +2507,Farm,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Farm,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Farm,Shipsanity: Maki Roll,SHIPSANITY, +2510,Farm,Shipsanity: Maple Bar,SHIPSANITY, +2511,Farm,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Farm,Shipsanity: Omelet,SHIPSANITY, +2513,Farm,Shipsanity: Pale Broth,SHIPSANITY, +2514,Farm,Shipsanity: Pancakes,SHIPSANITY, +2515,Farm,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Farm,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Farm,Shipsanity: Pink Cake,SHIPSANITY, +2518,Farm,Shipsanity: Pizza,SHIPSANITY, +2519,Farm,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Farm,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Farm,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Farm,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Farm,Shipsanity: Radish Salad,SHIPSANITY, +2524,Farm,Shipsanity: Red Plate,SHIPSANITY, +2525,Farm,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Farm,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Farm,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Farm,Shipsanity: Roots Platter,SHIPSANITY, +2529,Farm,Shipsanity: Salad,SHIPSANITY, +2530,Farm,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Farm,Shipsanity: Sashimi,SHIPSANITY, +2532,Farm,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Farm,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Farm,Shipsanity: Spaghetti,SHIPSANITY, +2535,Farm,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Farm,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Farm,Shipsanity: Stir Fry,SHIPSANITY, +2538,Farm,Shipsanity: Strange Bun,SHIPSANITY, +2539,Farm,Shipsanity: Stuffing,SHIPSANITY, +2540,Farm,Shipsanity: Super Meal,SHIPSANITY, +2541,Farm,Shipsanity: Survival Burger,SHIPSANITY, +2542,Farm,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Farm,Shipsanity: Tortilla,SHIPSANITY, +2544,Farm,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Farm,Shipsanity: Trout Soup,SHIPSANITY, +2546,Farm,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Farm,Shipsanity: Bait,SHIPSANITY, +2548,Farm,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Farm,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Farm,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Farm,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Farm,Shipsanity: Bomb,SHIPSANITY, +2553,Farm,Shipsanity: Brick Floor,SHIPSANITY, +2554,Farm,Shipsanity: Bug Steak,SHIPSANITY, +2555,Farm,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Farm,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Farm,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Farm,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Farm,Shipsanity: Crab Pot,SHIPSANITY, +2560,Farm,Shipsanity: Crystal Floor,SHIPSANITY, +2561,Farm,Shipsanity: Crystal Path,SHIPSANITY, +2562,Farm,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Farm,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Farm,Shipsanity: Drum Block,SHIPSANITY, +2565,Farm,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Farm,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Farm,Shipsanity: Field Snack,SHIPSANITY, +2568,Farm,Shipsanity: Flute Block,SHIPSANITY, +2569,Farm,Shipsanity: Gate,SHIPSANITY, +2570,Farm,Shipsanity: Gravel Path,SHIPSANITY, +2571,Farm,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Farm,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Farm,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Farm,Shipsanity: Iron Fence,SHIPSANITY, +2575,Farm,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Farm,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Farm,Shipsanity: Life Elixir,SHIPSANITY, +2578,Farm,Shipsanity: Magnet,SHIPSANITY, +2579,Farm,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Farm,Shipsanity: Monster Musk,SHIPSANITY, +2581,Farm,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Farm,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Farm,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Farm,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Farm,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Farm,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Farm,Shipsanity: Rain Totem,SHIPSANITY, +2588,Farm,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Farm,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Farm,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Farm,Shipsanity: Spinner,SHIPSANITY, +2592,Farm,Shipsanity: Sprinkler,SHIPSANITY, +2593,Farm,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Farm,Shipsanity: Stone Fence,SHIPSANITY, +2595,Farm,Shipsanity: Stone Floor,SHIPSANITY, +2596,Farm,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Farm,Shipsanity: Straw Floor,SHIPSANITY, +2598,Farm,Shipsanity: Torch,SHIPSANITY, +2599,Farm,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Farm,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Farm,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Farm,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Farm,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Farm,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Farm,Shipsanity: Warp Totem: Island,SHIPSANITY, +2606,Farm,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Farm,Shipsanity: Weathered Floor,SHIPSANITY, +2608,Farm,Shipsanity: Wild Bait,SHIPSANITY, +2609,Farm,Shipsanity: Wood Fence,SHIPSANITY, +2610,Farm,Shipsanity: Wood Floor,SHIPSANITY, +2611,Farm,Shipsanity: Wood Path,SHIPSANITY, +2612,Farm,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Farm,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Farm,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Farm,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Farm,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Farm,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Farm,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Farm,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Farm,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Farm,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Farm,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Farm,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Farm,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Farm,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Farm,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Farm,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Farm,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Farm,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Farm,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Farm,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Farm,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Farm,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Farm,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Farm,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Farm,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Farm,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Farm,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Farm,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Farm,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Farm,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Farm,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Farm,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Farm,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Farm,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Farm,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Farm,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Farm,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Farm,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Farm,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Farm,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Farm,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Farm,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Farm,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Farm,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Farm,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Farm,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Farm,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Farm,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Farm,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Farm,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Farm,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Farm,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Farm,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Farm,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Farm,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Farm,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Farm,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Farm,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Farm,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Farm,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Farm,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Farm,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Farm,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Farm,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Farm,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Farm,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Farm,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Farm,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Farm,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Farm,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Farm,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Farm,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Farm,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Farm,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Farm,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Farm,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Farm,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Farm,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Farm,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Farm,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Farm,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Farm,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Farm,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Farm,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Farm,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Farm,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Farm,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Farm,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Farm,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Farm,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Farm,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Farm,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Farm,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Farm,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Farm,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Farm,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Farm,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Farm,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Farm,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Farm,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Farm,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Farm,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Farm,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Farm,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Farm,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Farm,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Farm,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Farm,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Farm,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Farm,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Farm,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Farm,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Farm,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Farm,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Farm,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Farm,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Farm,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Farm,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Farm,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Farm,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Farm,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Farm,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Farm,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Farm,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Farm,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Farm,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Farm,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Farm,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Farm,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Farm,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Farm,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Farm,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Farm,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Farm,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Farm,Shipsanity: Tea Set,SHIPSANITY, +2747,Farm,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Farm,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Farm,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Farm,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Farm,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Farm,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Farm,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Farm,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Farm,Shipsanity: Oil,SHIPSANITY, +2756,Farm,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Farm,Shipsanity: Rice,SHIPSANITY, +2758,Farm,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Farm,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Farm,Shipsanity: Sugar,SHIPSANITY, +2761,Farm,Shipsanity: Vinegar,SHIPSANITY, +2762,Farm,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Farm,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Farm,Shipsanity: Aerinite,SHIPSANITY, +2765,Farm,Shipsanity: Alamite,SHIPSANITY, +2766,Farm,Shipsanity: Amethyst,SHIPSANITY, +2767,Farm,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Farm,Shipsanity: Aquamarine,SHIPSANITY, +2769,Farm,Shipsanity: Baryte,SHIPSANITY, +2770,Farm,Shipsanity: Basalt,SHIPSANITY, +2771,Farm,Shipsanity: Bixite,SHIPSANITY, +2772,Farm,Shipsanity: Calcite,SHIPSANITY, +2773,Farm,Shipsanity: Celestine,SHIPSANITY, +2774,Farm,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Farm,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Farm,Shipsanity: Diamond,SHIPSANITY, +2777,Farm,Shipsanity: Dolomite,SHIPSANITY, +2778,Farm,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Farm,Shipsanity: Emerald,SHIPSANITY, +2780,Farm,Shipsanity: Esperite,SHIPSANITY, +2781,Farm,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Farm,Shipsanity: Fire Opal,SHIPSANITY, +2783,Farm,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Farm,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Farm,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Farm,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Farm,Shipsanity: Geminite,SHIPSANITY, +2788,Farm,Shipsanity: Geode,SHIPSANITY, +2789,Farm,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Farm,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Farm,Shipsanity: Granite,SHIPSANITY, +2792,Farm,Shipsanity: Helvite,SHIPSANITY, +2793,Farm,Shipsanity: Hematite,SHIPSANITY, +2794,Farm,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Farm,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Farm,Shipsanity: Jade,SHIPSANITY, +2797,Farm,Shipsanity: Jagoite,SHIPSANITY, +2798,Farm,Shipsanity: Jamborite,SHIPSANITY, +2799,Farm,Shipsanity: Jasper,SHIPSANITY, +2800,Farm,Shipsanity: Kyanite,SHIPSANITY, +2801,Farm,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Farm,Shipsanity: Limestone,SHIPSANITY, +2803,Farm,Shipsanity: Lunarite,SHIPSANITY, +2804,Farm,Shipsanity: Magma Geode,SHIPSANITY, +2805,Farm,Shipsanity: Malachite,SHIPSANITY, +2806,Farm,Shipsanity: Marble,SHIPSANITY, +2807,Farm,Shipsanity: Mudstone,SHIPSANITY, +2808,Farm,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Farm,Shipsanity: Nekoite,SHIPSANITY, +2810,Farm,Shipsanity: Neptunite,SHIPSANITY, +2811,Farm,Shipsanity: Obsidian,SHIPSANITY, +2812,Farm,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Farm,Shipsanity: Omni Geode,SHIPSANITY, +2814,Farm,Shipsanity: Opal,SHIPSANITY, +2815,Farm,Shipsanity: Orpiment,SHIPSANITY, +2816,Farm,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Farm,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Farm,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Farm,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Farm,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Farm,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Farm,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Farm,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Farm,Shipsanity: Pyrite,SHIPSANITY, +2825,Farm,Shipsanity: Quartz,SHIPSANITY, +2826,Farm,Shipsanity: Ruby,SHIPSANITY, +2827,Farm,Shipsanity: Sandstone,SHIPSANITY, +2828,Farm,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Farm,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Farm,Shipsanity: Slate,SHIPSANITY, +2831,Farm,Shipsanity: Soapstone,SHIPSANITY, +2832,Farm,Shipsanity: Star Shards,SHIPSANITY, +2833,Farm,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Farm,Shipsanity: Tigerseye,SHIPSANITY, +2835,Farm,Shipsanity: Topaz,SHIPSANITY, +2836,Farm,Shipsanity: Trilobite,SHIPSANITY, +2837,Farm,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Farm,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2839,Farm,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Farm,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Farm,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Farm,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Farm,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Farm,Shipsanity: Bouquet,SHIPSANITY, +2845,Farm,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Farm,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Farm,Shipsanity: Green Algae,SHIPSANITY, +2848,Farm,Shipsanity: Hay,SHIPSANITY, +2849,Farm,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Farm,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Farm,Shipsanity: Pearl,SHIPSANITY, +2852,Farm,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Farm,Shipsanity: Seaweed,SHIPSANITY, +2854,Farm,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Farm,Shipsanity: White Algae,SHIPSANITY, +2856,Farm,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Farm,Shipsanity: Secret Note,SHIPSANITY, +2858,Farm,Shipsanity: Acorn,SHIPSANITY, +2859,Farm,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Farm,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Farm,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Farm,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Farm,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Farm,Shipsanity: Bean Starter,SHIPSANITY, +2865,Farm,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Farm,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Farm,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Farm,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Farm,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Farm,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Farm,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Farm,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Farm,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Farm,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Farm,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Farm,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Farm,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Farm,Shipsanity: Grape Starter,SHIPSANITY, +2879,Farm,Shipsanity: Grass Starter,SHIPSANITY, +2880,Farm,Shipsanity: Hops Starter,SHIPSANITY, +2881,Farm,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Farm,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Farm,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Farm,Shipsanity: Maple Seed,SHIPSANITY, +2885,Farm,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Farm,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Farm,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Farm,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Farm,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Farm,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Farm,Shipsanity: Pine Cone,SHIPSANITY, +2892,Farm,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Farm,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Farm,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Farm,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Farm,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Farm,Shipsanity: Rare Seed,SHIPSANITY, +2898,Farm,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Farm,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Farm,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Farm,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Farm,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Farm,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Farm,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Farm,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Farm,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Farm,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Farm,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Farm,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Farm,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Farm,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Farm,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Farm,Shipsanity: Broken CD,SHIPSANITY, +2914,Farm,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Farm,Shipsanity: Driftwood,SHIPSANITY, +2916,Farm,Shipsanity: Joja Cola,SHIPSANITY, +2917,Farm,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Farm,Shipsanity: Trash,SHIPSANITY, +2919,Farm,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Farm,Shipsanity: Golden Egg,SHIPSANITY, +2921,Farm,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Farm,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Farm,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Farm,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Farm,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Farm,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Farm,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Farm,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Farm,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Farm,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Farm,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Farm,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Farm,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Farm,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Farm,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Farm,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Farm,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Farm,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Farm,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Farm,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Farm,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Farm,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Farm,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Farm,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Farm,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY", +2946,Farm,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Farm,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Farm,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2949,Farm,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2950,Farm,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Farm,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2952,Farm,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2953,Farm,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2954,Farm,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Farm,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Farm,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Farm,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Farm,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY", +2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY", +2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY", +2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY", +2965,Farm,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Farm,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", +2967,Farm,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Farm,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Farm,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Farm,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY", +2971,Farm,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Farm,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Farm,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", +3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", +3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", +3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", +3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", +3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", +3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", +3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", +3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", +3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", +3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Blue Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Red Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Purple Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Yellow Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Black Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Copper Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Iron Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3110,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Dangerous Shadow Shaman,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3112,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Dangerous Shadow Brute,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3114,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3115,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Dangerous Bat,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3117,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Dangerous Frost Bat,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3119,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Dangerous Skeleton,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3123,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3124,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Dangerous Bug,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3126,Adventurer's Guild,Monster Eradication: Cave Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Dangerous Cave Fly,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3128,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3129,Adventurer's Guild,Monster Eradication: Dangerous Grub,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3130,Adventurer's Guild,Monster Eradication: Mutant Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", +3131,Adventurer's Guild,Monster Eradication: Mutant Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", +3132,Adventurer's Guild,Monster Eradication: Armored Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3133,Adventurer's Guild,Monster Eradication: Dangerous Armored Bug,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3134,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3135,Adventurer's Guild,Monster Eradication: Dangerous Duggy,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3136,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3137,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3138,Adventurer's Guild,Monster Eradication: Dangerous Dust Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3139,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3140,Adventurer's Guild,Monster Eradication: Dangerous Rock Crab,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3141,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3142,Adventurer's Guild,Monster Eradication: Dangerous Lava Crab,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3143,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3144,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3145,Adventurer's Guild,Monster Eradication: Dangerous Mummy,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3146,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3147,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3148,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3149,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill 5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic 5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic 5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic @@ -1758,26 +1759,26 @@ id,region,name,tags,mod_name 5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill 5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill 5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill 5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic 5502,Magic Altar,Analyze: Till,MANDATORY,Magic 5503,Magic Altar,Analyze: Water,MANDATORY,Magic @@ -1833,16 +1834,16 @@ id,region,name,tags,mod_name 6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) 6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) 6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) -6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC 6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC 6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC @@ -1871,20 +1872,20 @@ id,region,name,tags,mod_name 6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick 6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick 6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick -6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC -6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC -6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC -6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC -6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC -6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC -6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC -6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC -6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC -6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC -6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC -6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC -6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC -6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC +6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC +6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC +6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC +6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC +6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC +6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC +6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC +6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC +6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC +6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC +6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC +6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC +6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC +6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC 6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited 6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited 6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited @@ -1913,16 +1914,16 @@ id,region,name,tags,mod_name 6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene 6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene 6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene -6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC -6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC -6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC -6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC -6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC -6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC -6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC -6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC -6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC -6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC +6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC +6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC +6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC +6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC +6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC +6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC +6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC +6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC +6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC +6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC 6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley 6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley 6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley @@ -1937,36 +1938,36 @@ id,region,name,tags,mod_name 6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley 6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley 6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley -7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack -7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod -7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods -7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods -7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods -7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods -7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods -7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods -7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods -7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods -7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods -7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods -7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods -7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods -7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods -7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods -7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods -7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods -7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods -7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator -7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator -7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator -7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator -7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator -7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator -7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator -7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack +7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod +7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods +7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods +7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods +7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods +7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods +7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods +7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods +7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods +7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods +7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods +7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods +7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods +7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods +7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods +7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods +7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods +7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods +7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator +7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator +7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator +7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator +7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator +7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator +7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator +7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator 7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) -7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC -7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC -7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC +7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) +7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC +7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC +7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 7250023f0e68..c66825ef75fe 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -68,6 +68,9 @@ class LocationTags(enum.Enum): MONSTERSANITY_PROGRESSIVE_GOALS = enum.auto() MONSTERSANITY_MONSTER = enum.auto() SHIPSANITY = enum.auto() + SHIPSANITY_CROP = enum.auto() + SHIPSANITY_FISH = enum.auto() + SHIPSANITY_FULL_SHIPMENT = enum.auto() # Skill Mods LUCK_LEVEL = enum.auto() BINNING_LEVEL = enum.auto() diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 4378c9885fb5..065c5fc71f96 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -372,7 +372,7 @@ class Monstersanity(Choice): class Shipsanity(Choice): """Locations for shipping items? None: There are no checks for shipping items - Crops: Every crop being shipped is a check + Crops: Every crop and forageable being shipped is a check Fish: Every fish being shipped is a check except legendaries Full Shipment: Every item in the Collections page is a check Full Shipment With Fish: Every item in the Collections page and every fish is a check From ae01ec33f6fc6159e00f1d5b36a6c23c575eae6e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 17 Aug 2023 21:31:15 -0400 Subject: [PATCH 047/482] - Update the locations script to take into account mod names --- worlds/stardew_valley/scripts/update_data.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/scripts/update_data.py b/worlds/stardew_valley/scripts/update_data.py index 7b31a3705c5c..ae8f7f8d5503 100644 --- a/worlds/stardew_valley/scripts/update_data.py +++ b/worlds/stardew_valley/scripts/update_data.py @@ -12,7 +12,7 @@ from worlds.stardew_valley import LocationData from worlds.stardew_valley.items import load_item_csv, Group, ItemData -from worlds.stardew_valley.locations import load_location_csv +from worlds.stardew_valley.locations import load_location_csv, LocationTags RESOURCE_PACK_CODE_OFFSET = 5000 script_folder = Path(__file__) @@ -34,14 +34,15 @@ def write_item_csv(items: List[ItemData]): def write_location_csv(locations: List[LocationData]): with open((script_folder.parent.parent / "data/locations.csv").resolve(), "w", newline="") as file: - write = csv.DictWriter(file, ["id", "region", "name", "tags"]) + write = csv.DictWriter(file, ["id", "region", "name", "tags", "mod_name"]) write.writeheader() for location in locations: location_dict = { "id": location.code_without_offset, "name": location.name, "region": location.region, - "tags": ",".join(sorted(group.name for group in location.tags)) + "tags": ",".join(sorted(group.name for group in location.tags)), + "mod_name": location.mod_name } write.writerow(location_dict) @@ -76,12 +77,11 @@ def write_location_csv(locations: List[LocationData]): location_counter = itertools.count(max(location.code_without_offset for location in loaded_locations if location.code_without_offset is not None) + 1) - locations_to_write = [] for location in loaded_locations: if location.code_without_offset is None: locations_to_write.append( - LocationData(next(location_counter), location.region, location.name, location.tags)) + LocationData(next(location_counter), location.region, location.name, location.mod_name, location.tags)) continue locations_to_write.append(location) From cafad3be5ee4c77520bd29cc75f79b4dac57557e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 17 Aug 2023 22:21:55 -0400 Subject: [PATCH 048/482] - Added shipsanity rules (now the tests are failing because many items dont have logic yet) --- worlds/stardew_valley/__init__.py | 4 + worlds/stardew_valley/data/locations.csv | 1150 +++++++++---------- worlds/stardew_valley/locations.py | 22 + worlds/stardew_valley/logic/logic.py | 11 + worlds/stardew_valley/options.py | 2 + worlds/stardew_valley/rules.py | 60 +- worlds/stardew_valley/strings/goal_names.py | 1 + worlds/stardew_valley/test/TestRules.py | 84 +- 8 files changed, 737 insertions(+), 597 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 03b3d4e0b5bd..cecc6ee64fd4 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -214,6 +214,10 @@ def setup_victory(self): self.create_event_location(location_table[Goal.protector_of_the_valley], self.logic.can_complete_all_monster_slaying_goals().simplify(), "Victory") + elif self.options[options.Goal] == options.Goal.option_full_shipment: + self.create_event_location(location_table[Goal.option_full_shipment], + self.logic.can_ship_everything().simplify(), + "Victory") elif self.options[options.Goal] == options.Goal.option_perfection: self.create_event_location(location_table[Goal.perfection], self.logic.has_everything(self.all_progression_items).simplify(), diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 660f0aee4742..a825d04536b0 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -988,8 +988,8 @@ id,region,name,tags,mod_name 2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", 2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", 2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", -2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, -2216,Field Office,Complete Island Field Office,GINGER_ISLAND, +2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, +2216,Field Office,Complete Island Field Office,GINGER_ISLAND, 2301,Farming,Harvest Amaranth,"CROPSANITY", 2302,Farming,Harvest Artichoke,"CROPSANITY", 2303,Farming,Harvest Beet,"CROPSANITY", @@ -1037,579 +1037,579 @@ id,region,name,tags,mod_name 2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", 2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", 2347,Farming,Harvest Coffee Bean,"CROPSANITY", -2401,Farm,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2402,Farm,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2403,Farm,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2404,Farm,Shipsanity: Brown Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2405,Farm,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2406,Farm,Shipsanity: L. Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2407,Farm,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2408,Farm,Shipsanity: Large Brown Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2409,Farm,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2410,Farm,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2411,Farm,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2412,Farm,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2413,Farm,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2414,Farm,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2415,Farm,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2416,Farm,Shipsanity: Anchor,SHIPSANITY, -2417,Farm,Shipsanity: Ancient Doll,SHIPSANITY, -2418,Farm,Shipsanity: Ancient Drum,SHIPSANITY, -2419,Farm,Shipsanity: Ancient Seed,SHIPSANITY, -2420,Farm,Shipsanity: Ancient Sword,SHIPSANITY, -2421,Farm,Shipsanity: Arrowhead,SHIPSANITY, -2422,Farm,Shipsanity: Artifact Trove,SHIPSANITY, -2423,Farm,Shipsanity: Bone Flute,SHIPSANITY, -2424,Farm,Shipsanity: Chewing Stick,SHIPSANITY, -2425,Farm,Shipsanity: Chicken Statue,SHIPSANITY, -2426,Farm,Shipsanity: Chipped Amphora,SHIPSANITY, -2427,Farm,Shipsanity: Dinosaur Egg,SHIPSANITY, -2428,Farm,Shipsanity: Dried Starfish,SHIPSANITY, -2429,Farm,Shipsanity: Dwarf Gadget,SHIPSANITY, -2430,Farm,Shipsanity: Dwarf Scroll I,SHIPSANITY, -2431,Farm,Shipsanity: Dwarf Scroll II,SHIPSANITY, -2432,Farm,Shipsanity: Dwarf Scroll III,SHIPSANITY, -2433,Farm,Shipsanity: Dwarf Scroll IV,SHIPSANITY, -2434,Farm,Shipsanity: Dwarvish Helm,SHIPSANITY, -2435,Farm,Shipsanity: Elvish Jewelry,SHIPSANITY, -2436,Farm,Shipsanity: Glass Shards,SHIPSANITY, -2437,Farm,Shipsanity: Golden Mask,SHIPSANITY, -2438,Farm,Shipsanity: Golden Relic,SHIPSANITY, -2439,Farm,Shipsanity: Ornamental Fan,SHIPSANITY, -2440,Farm,Shipsanity: Prehistoric Handaxe,SHIPSANITY, -2441,Farm,Shipsanity: Prehistoric Tool,SHIPSANITY, -2442,Farm,Shipsanity: Rare Disc,SHIPSANITY, -2443,Farm,Shipsanity: Rusty Cog,SHIPSANITY, -2444,Farm,Shipsanity: Rusty Spoon,SHIPSANITY, -2445,Farm,Shipsanity: Rusty Spur,SHIPSANITY, -2446,Farm,Shipsanity: Strange Doll,SHIPSANITY, -2447,Farm,Shipsanity: Strange Doll (Green),SHIPSANITY, -2448,Farm,Shipsanity: Treasure Chest,SHIPSANITY, -2449,Farm,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2450,Farm,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2451,Farm,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2452,Farm,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2453,Farm,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2454,Farm,Shipsanity: Coffee,SHIPSANITY, -2455,Farm,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2456,Farm,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2457,Farm,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2458,Farm,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2459,Farm,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2460,Farm,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2461,Farm,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2462,Farm,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2463,Farm,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2464,Farm,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2465,Farm,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2466,Farm,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2467,Farm,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2468,Farm,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2469,Farm,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2470,Farm,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2471,Farm,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2472,Farm,Shipsanity: Algae Soup,SHIPSANITY, -2473,Farm,Shipsanity: Artichoke Dip,SHIPSANITY, -2474,Farm,Shipsanity: Autumn's Bounty,SHIPSANITY, -2475,Farm,Shipsanity: Baked Fish,SHIPSANITY, -2476,Farm,Shipsanity: Bean Hotpot,SHIPSANITY, -2477,Farm,Shipsanity: Blackberry Cobbler,SHIPSANITY, -2478,Farm,Shipsanity: Blueberry Tart,SHIPSANITY, -2479,Farm,Shipsanity: Bread,SHIPSANITY, -2480,Farm,Shipsanity: Bruschetta,SHIPSANITY, -2481,Farm,Shipsanity: Carp Surprise,SHIPSANITY, -2482,Farm,Shipsanity: Cheese Cauliflower,SHIPSANITY, -2483,Farm,Shipsanity: Chocolate Cake,SHIPSANITY, -2484,Farm,Shipsanity: Chowder,SHIPSANITY, -2485,Farm,Shipsanity: Coleslaw,SHIPSANITY, -2486,Farm,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Farm,Shipsanity: Cookie,SHIPSANITY, -2488,Farm,Shipsanity: Crab Cakes,SHIPSANITY, -2489,Farm,Shipsanity: Cranberry Candy,SHIPSANITY, -2490,Farm,Shipsanity: Cranberry Sauce,SHIPSANITY, -2491,Farm,Shipsanity: Crispy Bass,SHIPSANITY, -2492,Farm,Shipsanity: Dish O' The Sea,SHIPSANITY, -2493,Farm,Shipsanity: Eggplant Parmesan,SHIPSANITY, -2494,Farm,Shipsanity: Escargot,SHIPSANITY, -2495,Farm,Shipsanity: Farmer's Lunch,SHIPSANITY, -2496,Farm,Shipsanity: Fiddlehead Risotto,SHIPSANITY, -2497,Farm,Shipsanity: Fish Stew,SHIPSANITY, -2498,Farm,Shipsanity: Fish Taco,SHIPSANITY, -2499,Farm,Shipsanity: Fried Calamari,SHIPSANITY, -2500,Farm,Shipsanity: Fried Eel,SHIPSANITY, -2501,Farm,Shipsanity: Fried Egg,SHIPSANITY, -2502,Farm,Shipsanity: Fried Mushroom,SHIPSANITY, -2503,Farm,Shipsanity: Fruit Salad,SHIPSANITY, -2504,Farm,Shipsanity: Glazed Yams,SHIPSANITY, -2505,Farm,Shipsanity: Hashbrowns,SHIPSANITY, -2506,Farm,Shipsanity: Ice Cream,SHIPSANITY, -2507,Farm,Shipsanity: Lobster Bisque,SHIPSANITY, -2508,Farm,Shipsanity: Lucky Lunch,SHIPSANITY, -2509,Farm,Shipsanity: Maki Roll,SHIPSANITY, -2510,Farm,Shipsanity: Maple Bar,SHIPSANITY, -2511,Farm,Shipsanity: Miner's Treat,SHIPSANITY, -2512,Farm,Shipsanity: Omelet,SHIPSANITY, -2513,Farm,Shipsanity: Pale Broth,SHIPSANITY, -2514,Farm,Shipsanity: Pancakes,SHIPSANITY, -2515,Farm,Shipsanity: Parsnip Soup,SHIPSANITY, -2516,Farm,Shipsanity: Pepper Poppers,SHIPSANITY, -2517,Farm,Shipsanity: Pink Cake,SHIPSANITY, -2518,Farm,Shipsanity: Pizza,SHIPSANITY, -2519,Farm,Shipsanity: Plum Pudding,SHIPSANITY, -2520,Farm,Shipsanity: Poppyseed Muffin,SHIPSANITY, -2521,Farm,Shipsanity: Pumpkin Pie,SHIPSANITY, -2522,Farm,Shipsanity: Pumpkin Soup,SHIPSANITY, -2523,Farm,Shipsanity: Radish Salad,SHIPSANITY, -2524,Farm,Shipsanity: Red Plate,SHIPSANITY, -2525,Farm,Shipsanity: Rhubarb Pie,SHIPSANITY, -2526,Farm,Shipsanity: Rice Pudding,SHIPSANITY, -2527,Farm,Shipsanity: Roasted Hazelnuts,SHIPSANITY, -2528,Farm,Shipsanity: Roots Platter,SHIPSANITY, -2529,Farm,Shipsanity: Salad,SHIPSANITY, -2530,Farm,Shipsanity: Salmon Dinner,SHIPSANITY, -2531,Farm,Shipsanity: Sashimi,SHIPSANITY, -2532,Farm,Shipsanity: Seafoam Pudding,SHIPSANITY, -2533,Farm,Shipsanity: Shrimp Cocktail,SHIPSANITY, -2534,Farm,Shipsanity: Spaghetti,SHIPSANITY, -2535,Farm,Shipsanity: Spicy Eel,SHIPSANITY, -2536,Farm,Shipsanity: Squid Ink Ravioli,SHIPSANITY, -2537,Farm,Shipsanity: Stir Fry,SHIPSANITY, -2538,Farm,Shipsanity: Strange Bun,SHIPSANITY, -2539,Farm,Shipsanity: Stuffing,SHIPSANITY, -2540,Farm,Shipsanity: Super Meal,SHIPSANITY, -2541,Farm,Shipsanity: Survival Burger,SHIPSANITY, -2542,Farm,Shipsanity: Tom Kha Soup,SHIPSANITY, -2543,Farm,Shipsanity: Tortilla,SHIPSANITY, -2544,Farm,Shipsanity: Triple Shot Espresso,SHIPSANITY, -2545,Farm,Shipsanity: Trout Soup,SHIPSANITY, -2546,Farm,Shipsanity: Vegetable Medley,SHIPSANITY, -2547,Farm,Shipsanity: Bait,SHIPSANITY, -2548,Farm,Shipsanity: Barbed Hook,SHIPSANITY, -2549,Farm,Shipsanity: Basic Fertilizer,SHIPSANITY, -2550,Farm,Shipsanity: Basic Retaining Soil,SHIPSANITY, -2551,Farm,Shipsanity: Blue Slime Egg,SHIPSANITY, -2552,Farm,Shipsanity: Bomb,SHIPSANITY, -2553,Farm,Shipsanity: Brick Floor,SHIPSANITY, -2554,Farm,Shipsanity: Bug Steak,SHIPSANITY, -2555,Farm,Shipsanity: Cherry Bomb,SHIPSANITY, -2556,Farm,Shipsanity: Cobblestone Path,SHIPSANITY, -2557,Farm,Shipsanity: Cookout Kit,SHIPSANITY, -2558,Farm,Shipsanity: Cork Bobber,SHIPSANITY, -2559,Farm,Shipsanity: Crab Pot,SHIPSANITY, -2560,Farm,Shipsanity: Crystal Floor,SHIPSANITY, -2561,Farm,Shipsanity: Crystal Path,SHIPSANITY, -2562,Farm,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, -2563,Farm,Shipsanity: Dressed Spinner,SHIPSANITY, -2564,Farm,Shipsanity: Drum Block,SHIPSANITY, -2565,Farm,Shipsanity: Explosive Ammo,SHIPSANITY, -2566,Farm,Shipsanity: Fiber Seeds,SHIPSANITY, -2567,Farm,Shipsanity: Field Snack,SHIPSANITY, -2568,Farm,Shipsanity: Flute Block,SHIPSANITY, -2569,Farm,Shipsanity: Gate,SHIPSANITY, -2570,Farm,Shipsanity: Gravel Path,SHIPSANITY, -2571,Farm,Shipsanity: Green Slime Egg,SHIPSANITY, -2572,Farm,Shipsanity: Hardwood Fence,SHIPSANITY, -2573,Farm,Shipsanity: Iridium Sprinkler,SHIPSANITY, -2574,Farm,Shipsanity: Iron Fence,SHIPSANITY, -2575,Farm,Shipsanity: Jack-O-Lantern,SHIPSANITY, -2576,Farm,Shipsanity: Lead Bobber,SHIPSANITY, -2577,Farm,Shipsanity: Life Elixir,SHIPSANITY, -2578,Farm,Shipsanity: Magnet,SHIPSANITY, -2579,Farm,Shipsanity: Mega Bomb,SHIPSANITY, -2580,Farm,Shipsanity: Monster Musk,SHIPSANITY, -2581,Farm,Shipsanity: Oil of Garlic,SHIPSANITY, -2582,Farm,Shipsanity: Purple Slime Egg,SHIPSANITY, -2583,Farm,Shipsanity: Quality Bobber,SHIPSANITY, -2584,Farm,Shipsanity: Quality Fertilizer,SHIPSANITY, -2585,Farm,Shipsanity: Quality Retaining Soil,SHIPSANITY, -2586,Farm,Shipsanity: Quality Sprinkler,SHIPSANITY, -2587,Farm,Shipsanity: Rain Totem,SHIPSANITY, -2588,Farm,Shipsanity: Red Slime Egg,SHIPSANITY, -2589,Farm,Shipsanity: Rustic Plank Floor,SHIPSANITY, -2590,Farm,Shipsanity: Speed-Gro,SHIPSANITY, -2591,Farm,Shipsanity: Spinner,SHIPSANITY, -2592,Farm,Shipsanity: Sprinkler,SHIPSANITY, -2593,Farm,Shipsanity: Stepping Stone Path,SHIPSANITY, -2594,Farm,Shipsanity: Stone Fence,SHIPSANITY, -2595,Farm,Shipsanity: Stone Floor,SHIPSANITY, -2596,Farm,Shipsanity: Stone Walkway Floor,SHIPSANITY, -2597,Farm,Shipsanity: Straw Floor,SHIPSANITY, -2598,Farm,Shipsanity: Torch,SHIPSANITY, -2599,Farm,Shipsanity: Trap Bobber,SHIPSANITY, -2600,Farm,Shipsanity: Treasure Hunter,SHIPSANITY, -2601,Farm,Shipsanity: Tree Fertilizer,SHIPSANITY, -2602,Farm,Shipsanity: Warp Totem: Beach,SHIPSANITY, -2603,Farm,Shipsanity: Warp Totem: Desert,SHIPSANITY, -2604,Farm,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Farm,Shipsanity: Warp Totem: Island,SHIPSANITY, -2606,Farm,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Farm,Shipsanity: Weathered Floor,SHIPSANITY, -2608,Farm,Shipsanity: Wild Bait,SHIPSANITY, -2609,Farm,Shipsanity: Wood Fence,SHIPSANITY, -2610,Farm,Shipsanity: Wood Floor,SHIPSANITY, -2611,Farm,Shipsanity: Wood Path,SHIPSANITY, -2612,Farm,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2613,Farm,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2614,Farm,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2615,Farm,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2616,Farm,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2617,Farm,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2618,Farm,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2619,Farm,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2620,Farm,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2621,Farm,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2622,Farm,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2623,Farm,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2624,Farm,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2625,Farm,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2626,Farm,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2627,Farm,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2628,Farm,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2629,Farm,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2630,Farm,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2631,Farm,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2632,Farm,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2633,Farm,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2634,Farm,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2635,Farm,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2636,Farm,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2637,Farm,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2638,Farm,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2639,Farm,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2640,Farm,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2641,Farm,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2642,Farm,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2643,Farm,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2644,Farm,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2645,Farm,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2646,Farm,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2647,Farm,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2648,Farm,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2649,Farm,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2650,Farm,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2651,Farm,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2652,Farm,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2653,Farm,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2654,Farm,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2655,Farm,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", -2656,Farm,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", -2657,Farm,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", -2658,Farm,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", -2659,Farm,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", -2660,Farm,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", -2661,Farm,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", -2662,Farm,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", -2663,Farm,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", -2664,Farm,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", -2665,Farm,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", -2666,Farm,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", -2667,Farm,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", -2668,Farm,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", -2669,Farm,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", -2670,Farm,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", -2671,Farm,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", -2672,Farm,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", -2673,Farm,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", -2674,Farm,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", -2675,Farm,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", -2676,Farm,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2677,Farm,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", -2678,Farm,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", -2679,Farm,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", -2680,Farm,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", -2681,Farm,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", -2682,Farm,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", -2683,Farm,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", -2684,Farm,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", -2685,Farm,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", -2686,Farm,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", -2687,Farm,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", -2688,Farm,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", -2689,Farm,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", -2690,Farm,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", -2691,Farm,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", -2692,Farm,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", -2693,Farm,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", -2694,Farm,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2695,Farm,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", -2696,Farm,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", -2697,Farm,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", -2698,Farm,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2699,Farm,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", -2700,Farm,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", -2701,Farm,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", -2702,Farm,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2703,Farm,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", -2704,Farm,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", -2705,Farm,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", -2706,Farm,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", -2707,Farm,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", -2708,Farm,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", -2709,Farm,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2710,Farm,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", -2711,Farm,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", -2712,Farm,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", -2713,Farm,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2714,Farm,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", -2715,Farm,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", -2716,Farm,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2717,Farm,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2718,Farm,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2719,Farm,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2720,Farm,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2721,Farm,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2722,Farm,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2723,Farm,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2724,Farm,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2725,Farm,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2726,Farm,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2727,Farm,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2728,Farm,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2729,Farm,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2730,Farm,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2731,Farm,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2732,Farm,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2733,Farm,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2734,Farm,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2735,Farm,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2736,Farm,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2737,Farm,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2738,Farm,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2739,Farm,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2740,Farm,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2741,Farm,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2742,Farm,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2743,Farm,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2744,Farm,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2745,Farm,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2746,Farm,Shipsanity: Tea Set,SHIPSANITY, -2747,Farm,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2748,Farm,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2749,Farm,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2750,Farm,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2751,Farm,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2752,Farm,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2753,Farm,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2754,Farm,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2755,Farm,Shipsanity: Oil,SHIPSANITY, -2756,Farm,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2757,Farm,Shipsanity: Rice,SHIPSANITY, -2758,Farm,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2759,Farm,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2760,Farm,Shipsanity: Sugar,SHIPSANITY, -2761,Farm,Shipsanity: Vinegar,SHIPSANITY, -2762,Farm,Shipsanity: Wheat Flour,SHIPSANITY, -2763,Farm,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2764,Farm,Shipsanity: Aerinite,SHIPSANITY, -2765,Farm,Shipsanity: Alamite,SHIPSANITY, -2766,Farm,Shipsanity: Amethyst,SHIPSANITY, -2767,Farm,Shipsanity: Amphibian Fossil,SHIPSANITY, -2768,Farm,Shipsanity: Aquamarine,SHIPSANITY, -2769,Farm,Shipsanity: Baryte,SHIPSANITY, -2770,Farm,Shipsanity: Basalt,SHIPSANITY, -2771,Farm,Shipsanity: Bixite,SHIPSANITY, -2772,Farm,Shipsanity: Calcite,SHIPSANITY, -2773,Farm,Shipsanity: Celestine,SHIPSANITY, -2774,Farm,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2775,Farm,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2776,Farm,Shipsanity: Diamond,SHIPSANITY, -2777,Farm,Shipsanity: Dolomite,SHIPSANITY, -2778,Farm,Shipsanity: Earth Crystal,SHIPSANITY, -2779,Farm,Shipsanity: Emerald,SHIPSANITY, -2780,Farm,Shipsanity: Esperite,SHIPSANITY, -2781,Farm,Shipsanity: Fairy Stone,SHIPSANITY, -2782,Farm,Shipsanity: Fire Opal,SHIPSANITY, -2783,Farm,Shipsanity: Fire Quartz,SHIPSANITY, -2784,Farm,Shipsanity: Fluorapatite,SHIPSANITY, -2785,Farm,Shipsanity: Frozen Geode,SHIPSANITY, -2786,Farm,Shipsanity: Frozen Tear,SHIPSANITY, -2787,Farm,Shipsanity: Geminite,SHIPSANITY, -2788,Farm,Shipsanity: Geode,SHIPSANITY, -2789,Farm,Shipsanity: Ghost Crystal,SHIPSANITY, -2790,Farm,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2791,Farm,Shipsanity: Granite,SHIPSANITY, -2792,Farm,Shipsanity: Helvite,SHIPSANITY, -2793,Farm,Shipsanity: Hematite,SHIPSANITY, -2794,Farm,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2795,Farm,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2796,Farm,Shipsanity: Jade,SHIPSANITY, -2797,Farm,Shipsanity: Jagoite,SHIPSANITY, -2798,Farm,Shipsanity: Jamborite,SHIPSANITY, -2799,Farm,Shipsanity: Jasper,SHIPSANITY, -2800,Farm,Shipsanity: Kyanite,SHIPSANITY, -2801,Farm,Shipsanity: Lemon Stone,SHIPSANITY, -2802,Farm,Shipsanity: Limestone,SHIPSANITY, -2803,Farm,Shipsanity: Lunarite,SHIPSANITY, -2804,Farm,Shipsanity: Magma Geode,SHIPSANITY, -2805,Farm,Shipsanity: Malachite,SHIPSANITY, -2806,Farm,Shipsanity: Marble,SHIPSANITY, -2807,Farm,Shipsanity: Mudstone,SHIPSANITY, -2808,Farm,Shipsanity: Nautilus Fossil,SHIPSANITY, -2809,Farm,Shipsanity: Nekoite,SHIPSANITY, -2810,Farm,Shipsanity: Neptunite,SHIPSANITY, -2811,Farm,Shipsanity: Obsidian,SHIPSANITY, -2812,Farm,Shipsanity: Ocean Stone,SHIPSANITY, -2813,Farm,Shipsanity: Omni Geode,SHIPSANITY, -2814,Farm,Shipsanity: Opal,SHIPSANITY, -2815,Farm,Shipsanity: Orpiment,SHIPSANITY, -2816,Farm,Shipsanity: Palm Fossil,SHIPSANITY, -2817,Farm,Shipsanity: Petrified Slime,SHIPSANITY, -2818,Farm,Shipsanity: Prehistoric Rib,SHIPSANITY, -2819,Farm,Shipsanity: Prehistoric Scapula,SHIPSANITY, -2820,Farm,Shipsanity: Prehistoric Skull,SHIPSANITY, -2821,Farm,Shipsanity: Prehistoric Tibia,SHIPSANITY, -2822,Farm,Shipsanity: Prehistoric Vertebra,SHIPSANITY, -2823,Farm,Shipsanity: Prismatic Shard,SHIPSANITY, -2824,Farm,Shipsanity: Pyrite,SHIPSANITY, -2825,Farm,Shipsanity: Quartz,SHIPSANITY, -2826,Farm,Shipsanity: Ruby,SHIPSANITY, -2827,Farm,Shipsanity: Sandstone,SHIPSANITY, -2828,Farm,Shipsanity: Skeletal Hand,SHIPSANITY, -2829,Farm,Shipsanity: Skeletal Tail,SHIPSANITY, -2830,Farm,Shipsanity: Slate,SHIPSANITY, -2831,Farm,Shipsanity: Soapstone,SHIPSANITY, -2832,Farm,Shipsanity: Star Shards,SHIPSANITY, -2833,Farm,Shipsanity: Thunder Egg,SHIPSANITY, -2834,Farm,Shipsanity: Tigerseye,SHIPSANITY, -2835,Farm,Shipsanity: Topaz,SHIPSANITY, -2836,Farm,Shipsanity: Trilobite,SHIPSANITY, -2837,Farm,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Farm,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2839,Farm,Shipsanity: Curiosity Lure,SHIPSANITY, -2840,Farm,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2841,Farm,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2842,Farm,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2843,Farm,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2844,Farm,Shipsanity: Bouquet,SHIPSANITY, -2845,Farm,Shipsanity: Energy Tonic,SHIPSANITY, -2846,Farm,Shipsanity: Golden Pumpkin,SHIPSANITY, -2847,Farm,Shipsanity: Green Algae,SHIPSANITY, -2848,Farm,Shipsanity: Hay,SHIPSANITY, -2849,Farm,Shipsanity: Magic Rock Candy,SHIPSANITY, -2850,Farm,Shipsanity: Muscle Remedy,SHIPSANITY, -2851,Farm,Shipsanity: Pearl,SHIPSANITY, -2852,Farm,Shipsanity: Rotten Plant,SHIPSANITY, -2853,Farm,Shipsanity: Seaweed,SHIPSANITY, -2854,Farm,Shipsanity: Void Ghost Pendant,SHIPSANITY, -2855,Farm,Shipsanity: White Algae,SHIPSANITY, -2856,Farm,Shipsanity: Wilted Bouquet,SHIPSANITY, -2857,Farm,Shipsanity: Secret Note,SHIPSANITY, -2858,Farm,Shipsanity: Acorn,SHIPSANITY, -2859,Farm,Shipsanity: Amaranth Seeds,SHIPSANITY, -2860,Farm,Shipsanity: Ancient Seeds,SHIPSANITY, -2861,Farm,Shipsanity: Apple Sapling,SHIPSANITY, -2862,Farm,Shipsanity: Apricot Sapling,SHIPSANITY, -2863,Farm,Shipsanity: Artichoke Seeds,SHIPSANITY, -2864,Farm,Shipsanity: Bean Starter,SHIPSANITY, -2865,Farm,Shipsanity: Beet Seeds,SHIPSANITY, -2866,Farm,Shipsanity: Blueberry Seeds,SHIPSANITY, -2867,Farm,Shipsanity: Bok Choy Seeds,SHIPSANITY, -2868,Farm,Shipsanity: Cactus Seeds,SHIPSANITY, -2869,Farm,Shipsanity: Cauliflower Seeds,SHIPSANITY, -2870,Farm,Shipsanity: Cherry Sapling,SHIPSANITY, -2871,Farm,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2872,Farm,Shipsanity: Corn Seeds,SHIPSANITY, -2873,Farm,Shipsanity: Cranberry Seeds,SHIPSANITY, -2874,Farm,Shipsanity: Eggplant Seeds,SHIPSANITY, -2875,Farm,Shipsanity: Fairy Seeds,SHIPSANITY, -2876,Farm,Shipsanity: Fall Seeds,SHIPSANITY, -2877,Farm,Shipsanity: Garlic Seeds,SHIPSANITY, -2878,Farm,Shipsanity: Grape Starter,SHIPSANITY, -2879,Farm,Shipsanity: Grass Starter,SHIPSANITY, -2880,Farm,Shipsanity: Hops Starter,SHIPSANITY, -2881,Farm,Shipsanity: Jazz Seeds,SHIPSANITY, -2882,Farm,Shipsanity: Kale Seeds,SHIPSANITY, -2883,Farm,Shipsanity: Mahogany Seed,SHIPSANITY, -2884,Farm,Shipsanity: Maple Seed,SHIPSANITY, -2885,Farm,Shipsanity: Melon Seeds,SHIPSANITY, -2886,Farm,Shipsanity: Mixed Seeds,SHIPSANITY, -2887,Farm,Shipsanity: Orange Sapling,SHIPSANITY, -2888,Farm,Shipsanity: Parsnip Seeds,SHIPSANITY, -2889,Farm,Shipsanity: Peach Sapling,SHIPSANITY, -2890,Farm,Shipsanity: Pepper Seeds,SHIPSANITY, -2891,Farm,Shipsanity: Pine Cone,SHIPSANITY, -2892,Farm,Shipsanity: Pomegranate Sapling,SHIPSANITY, -2893,Farm,Shipsanity: Poppy Seeds,SHIPSANITY, -2894,Farm,Shipsanity: Potato Seeds,SHIPSANITY, -2895,Farm,Shipsanity: Pumpkin Seeds,SHIPSANITY, -2896,Farm,Shipsanity: Radish Seeds,SHIPSANITY, -2897,Farm,Shipsanity: Rare Seed,SHIPSANITY, -2898,Farm,Shipsanity: Red Cabbage Seeds,SHIPSANITY, -2899,Farm,Shipsanity: Rhubarb Seeds,SHIPSANITY, -2900,Farm,Shipsanity: Rice Shoot,SHIPSANITY, -2901,Farm,Shipsanity: Spangle Seeds,SHIPSANITY, -2902,Farm,Shipsanity: Spring Seeds,SHIPSANITY, -2903,Farm,Shipsanity: Starfruit Seeds,SHIPSANITY, -2904,Farm,Shipsanity: Strawberry Seeds,SHIPSANITY, -2905,Farm,Shipsanity: Summer Seeds,SHIPSANITY, -2906,Farm,Shipsanity: Sunflower Seeds,SHIPSANITY, -2907,Farm,Shipsanity: Tea Sapling,SHIPSANITY, -2908,Farm,Shipsanity: Tomato Seeds,SHIPSANITY, -2909,Farm,Shipsanity: Tulip Bulb,SHIPSANITY, -2910,Farm,Shipsanity: Wheat Seeds,SHIPSANITY, -2911,Farm,Shipsanity: Winter Seeds,SHIPSANITY, -2912,Farm,Shipsanity: Yam Seeds,SHIPSANITY, -2913,Farm,Shipsanity: Broken CD,SHIPSANITY, -2914,Farm,Shipsanity: Broken Glasses,SHIPSANITY, -2915,Farm,Shipsanity: Driftwood,SHIPSANITY, -2916,Farm,Shipsanity: Joja Cola,SHIPSANITY, -2917,Farm,Shipsanity: Soggy Newspaper,SHIPSANITY, -2918,Farm,Shipsanity: Trash,SHIPSANITY, -2919,Farm,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2920,Farm,Shipsanity: Golden Egg,SHIPSANITY, -2921,Farm,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2922,Farm,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", -2923,Farm,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", -2924,Farm,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", -2925,Farm,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", -2926,Farm,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", -2927,Farm,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", -2928,Farm,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", -2929,Farm,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", -2930,Farm,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", -2931,Farm,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", -2932,Farm,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", -2933,Farm,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", -2934,Farm,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", -2935,Farm,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", -2936,Farm,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", -2937,Farm,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", -2938,Farm,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", -2939,Farm,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", -2940,Farm,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", -2941,Farm,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", -2942,Farm,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2943,Farm,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2944,Farm,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Farm,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY", -2946,Farm,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2947,Farm,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Farm,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2949,Farm,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2950,Farm,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Farm,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2952,Farm,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2953,Farm,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2954,Farm,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2955,Farm,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2956,Farm,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2957,Farm,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2958,Farm,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY", -2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY", -2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY", -2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY", -2965,Farm,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Farm,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", -2967,Farm,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", -2968,Farm,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", -2969,Farm,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Farm,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY", -2971,Farm,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", -2972,Farm,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", -2973,Farm,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +2401,Farm,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Farm,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Farm,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Farm,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Farm,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Farm,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Farm,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Farm,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Farm,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Farm,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Farm,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Farm,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Farm,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Farm,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Farm,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Farm,Shipsanity: Anchor,SHIPSANITY, +2417,Farm,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Farm,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Farm,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Farm,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Farm,Shipsanity: Arrowhead,SHIPSANITY, +2422,Farm,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Farm,Shipsanity: Bone Flute,SHIPSANITY, +2424,Farm,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Farm,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Farm,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Farm,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Farm,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Farm,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Farm,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Farm,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Farm,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Farm,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Farm,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Farm,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Farm,Shipsanity: Glass Shards,SHIPSANITY, +2437,Farm,Shipsanity: Golden Mask,SHIPSANITY, +2438,Farm,Shipsanity: Golden Relic,SHIPSANITY, +2439,Farm,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Farm,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Farm,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Farm,Shipsanity: Rare Disc,SHIPSANITY, +2443,Farm,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Farm,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Farm,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Farm,Shipsanity: Strange Doll,SHIPSANITY, +2447,Farm,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Farm,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Farm,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Farm,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Farm,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Farm,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Farm,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Farm,Shipsanity: Coffee,SHIPSANITY, +2455,Farm,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Farm,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Farm,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Farm,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Farm,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Farm,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Farm,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Farm,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Farm,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Farm,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Farm,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Farm,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Farm,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Farm,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Farm,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Farm,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Farm,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Farm,Shipsanity: Algae Soup,SHIPSANITY, +2473,Farm,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Farm,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Farm,Shipsanity: Baked Fish,SHIPSANITY, +2476,Farm,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Farm,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Farm,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Farm,Shipsanity: Bread,SHIPSANITY, +2480,Farm,Shipsanity: Bruschetta,SHIPSANITY, +2481,Farm,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Farm,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Farm,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Farm,Shipsanity: Chowder,SHIPSANITY, +2485,Farm,Shipsanity: Coleslaw,SHIPSANITY, +2486,Farm,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Farm,Shipsanity: Cookie,SHIPSANITY, +2488,Farm,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Farm,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Farm,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Farm,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Farm,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Farm,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Farm,Shipsanity: Escargot,SHIPSANITY, +2495,Farm,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Farm,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Farm,Shipsanity: Fish Stew,SHIPSANITY, +2498,Farm,Shipsanity: Fish Taco,SHIPSANITY, +2499,Farm,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Farm,Shipsanity: Fried Eel,SHIPSANITY, +2501,Farm,Shipsanity: Fried Egg,SHIPSANITY, +2502,Farm,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Farm,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Farm,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Farm,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Farm,Shipsanity: Ice Cream,SHIPSANITY, +2507,Farm,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Farm,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Farm,Shipsanity: Maki Roll,SHIPSANITY, +2510,Farm,Shipsanity: Maple Bar,SHIPSANITY, +2511,Farm,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Farm,Shipsanity: Omelet,SHIPSANITY, +2513,Farm,Shipsanity: Pale Broth,SHIPSANITY, +2514,Farm,Shipsanity: Pancakes,SHIPSANITY, +2515,Farm,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Farm,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Farm,Shipsanity: Pink Cake,SHIPSANITY, +2518,Farm,Shipsanity: Pizza,SHIPSANITY, +2519,Farm,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Farm,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Farm,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Farm,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Farm,Shipsanity: Radish Salad,SHIPSANITY, +2524,Farm,Shipsanity: Red Plate,SHIPSANITY, +2525,Farm,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Farm,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Farm,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Farm,Shipsanity: Roots Platter,SHIPSANITY, +2529,Farm,Shipsanity: Salad,SHIPSANITY, +2530,Farm,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Farm,Shipsanity: Sashimi,SHIPSANITY, +2532,Farm,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Farm,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Farm,Shipsanity: Spaghetti,SHIPSANITY, +2535,Farm,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Farm,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Farm,Shipsanity: Stir Fry,SHIPSANITY, +2538,Farm,Shipsanity: Strange Bun,SHIPSANITY, +2539,Farm,Shipsanity: Stuffing,SHIPSANITY, +2540,Farm,Shipsanity: Super Meal,SHIPSANITY, +2541,Farm,Shipsanity: Survival Burger,SHIPSANITY, +2542,Farm,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Farm,Shipsanity: Tortilla,SHIPSANITY, +2544,Farm,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Farm,Shipsanity: Trout Soup,SHIPSANITY, +2546,Farm,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Farm,Shipsanity: Bait,SHIPSANITY, +2548,Farm,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Farm,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Farm,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Farm,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Farm,Shipsanity: Bomb,SHIPSANITY, +2553,Farm,Shipsanity: Brick Floor,SHIPSANITY, +2554,Farm,Shipsanity: Bug Steak,SHIPSANITY, +2555,Farm,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Farm,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Farm,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Farm,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Farm,Shipsanity: Crab Pot,SHIPSANITY, +2560,Farm,Shipsanity: Crystal Floor,SHIPSANITY, +2561,Farm,Shipsanity: Crystal Path,SHIPSANITY, +2562,Farm,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Farm,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Farm,Shipsanity: Drum Block,SHIPSANITY, +2565,Farm,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Farm,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Farm,Shipsanity: Field Snack,SHIPSANITY, +2568,Farm,Shipsanity: Flute Block,SHIPSANITY, +2569,Farm,Shipsanity: Gate,SHIPSANITY, +2570,Farm,Shipsanity: Gravel Path,SHIPSANITY, +2571,Farm,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Farm,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Farm,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Farm,Shipsanity: Iron Fence,SHIPSANITY, +2575,Farm,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Farm,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Farm,Shipsanity: Life Elixir,SHIPSANITY, +2578,Farm,Shipsanity: Magnet,SHIPSANITY, +2579,Farm,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Farm,Shipsanity: Monster Musk,SHIPSANITY, +2581,Farm,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Farm,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Farm,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Farm,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Farm,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Farm,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Farm,Shipsanity: Rain Totem,SHIPSANITY, +2588,Farm,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Farm,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Farm,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Farm,Shipsanity: Spinner,SHIPSANITY, +2592,Farm,Shipsanity: Sprinkler,SHIPSANITY, +2593,Farm,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Farm,Shipsanity: Stone Fence,SHIPSANITY, +2595,Farm,Shipsanity: Stone Floor,SHIPSANITY, +2596,Farm,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Farm,Shipsanity: Straw Floor,SHIPSANITY, +2598,Farm,Shipsanity: Torch,SHIPSANITY, +2599,Farm,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Farm,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Farm,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Farm,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Farm,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Farm,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Farm,Shipsanity: Warp Totem: Island,SHIPSANITY, +2606,Farm,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Farm,Shipsanity: Weathered Floor,SHIPSANITY, +2608,Farm,Shipsanity: Wild Bait,SHIPSANITY, +2609,Farm,Shipsanity: Wood Fence,SHIPSANITY, +2610,Farm,Shipsanity: Wood Floor,SHIPSANITY, +2611,Farm,Shipsanity: Wood Path,SHIPSANITY, +2612,Farm,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Farm,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Farm,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Farm,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Farm,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Farm,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Farm,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Farm,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Farm,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Farm,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Farm,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Farm,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Farm,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Farm,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Farm,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Farm,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Farm,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Farm,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Farm,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Farm,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Farm,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Farm,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Farm,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Farm,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Farm,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Farm,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Farm,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Farm,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Farm,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Farm,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Farm,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Farm,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Farm,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Farm,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Farm,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Farm,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Farm,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Farm,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Farm,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Farm,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Farm,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Farm,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Farm,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Farm,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Farm,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Farm,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Farm,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Farm,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Farm,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Farm,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Farm,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Farm,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Farm,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Farm,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Farm,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Farm,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Farm,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Farm,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Farm,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Farm,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Farm,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Farm,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Farm,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Farm,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Farm,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Farm,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Farm,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Farm,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Farm,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Farm,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Farm,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Farm,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Farm,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Farm,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Farm,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Farm,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Farm,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Farm,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Farm,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Farm,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Farm,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Farm,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Farm,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Farm,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Farm,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Farm,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Farm,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Farm,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Farm,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Farm,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Farm,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Farm,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Farm,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Farm,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Farm,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Farm,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Farm,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Farm,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Farm,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Farm,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Farm,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Farm,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Farm,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Farm,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Farm,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Farm,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Farm,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Farm,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Farm,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Farm,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Farm,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Farm,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Farm,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Farm,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Farm,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Farm,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Farm,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Farm,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Farm,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Farm,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Farm,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Farm,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Farm,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Farm,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Farm,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Farm,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Farm,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Farm,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Farm,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Farm,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Farm,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Farm,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Farm,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Farm,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Farm,Shipsanity: Tea Set,SHIPSANITY, +2747,Farm,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Farm,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Farm,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Farm,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Farm,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Farm,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Farm,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Farm,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Farm,Shipsanity: Oil,SHIPSANITY, +2756,Farm,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Farm,Shipsanity: Rice,SHIPSANITY, +2758,Farm,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Farm,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Farm,Shipsanity: Sugar,SHIPSANITY, +2761,Farm,Shipsanity: Vinegar,SHIPSANITY, +2762,Farm,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Farm,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Farm,Shipsanity: Aerinite,SHIPSANITY, +2765,Farm,Shipsanity: Alamite,SHIPSANITY, +2766,Farm,Shipsanity: Amethyst,SHIPSANITY, +2767,Farm,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Farm,Shipsanity: Aquamarine,SHIPSANITY, +2769,Farm,Shipsanity: Baryte,SHIPSANITY, +2770,Farm,Shipsanity: Basalt,SHIPSANITY, +2771,Farm,Shipsanity: Bixite,SHIPSANITY, +2772,Farm,Shipsanity: Calcite,SHIPSANITY, +2773,Farm,Shipsanity: Celestine,SHIPSANITY, +2774,Farm,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Farm,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Farm,Shipsanity: Diamond,SHIPSANITY, +2777,Farm,Shipsanity: Dolomite,SHIPSANITY, +2778,Farm,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Farm,Shipsanity: Emerald,SHIPSANITY, +2780,Farm,Shipsanity: Esperite,SHIPSANITY, +2781,Farm,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Farm,Shipsanity: Fire Opal,SHIPSANITY, +2783,Farm,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Farm,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Farm,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Farm,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Farm,Shipsanity: Geminite,SHIPSANITY, +2788,Farm,Shipsanity: Geode,SHIPSANITY, +2789,Farm,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Farm,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Farm,Shipsanity: Granite,SHIPSANITY, +2792,Farm,Shipsanity: Helvite,SHIPSANITY, +2793,Farm,Shipsanity: Hematite,SHIPSANITY, +2794,Farm,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Farm,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Farm,Shipsanity: Jade,SHIPSANITY, +2797,Farm,Shipsanity: Jagoite,SHIPSANITY, +2798,Farm,Shipsanity: Jamborite,SHIPSANITY, +2799,Farm,Shipsanity: Jasper,SHIPSANITY, +2800,Farm,Shipsanity: Kyanite,SHIPSANITY, +2801,Farm,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Farm,Shipsanity: Limestone,SHIPSANITY, +2803,Farm,Shipsanity: Lunarite,SHIPSANITY, +2804,Farm,Shipsanity: Magma Geode,SHIPSANITY, +2805,Farm,Shipsanity: Malachite,SHIPSANITY, +2806,Farm,Shipsanity: Marble,SHIPSANITY, +2807,Farm,Shipsanity: Mudstone,SHIPSANITY, +2808,Farm,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Farm,Shipsanity: Nekoite,SHIPSANITY, +2810,Farm,Shipsanity: Neptunite,SHIPSANITY, +2811,Farm,Shipsanity: Obsidian,SHIPSANITY, +2812,Farm,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Farm,Shipsanity: Omni Geode,SHIPSANITY, +2814,Farm,Shipsanity: Opal,SHIPSANITY, +2815,Farm,Shipsanity: Orpiment,SHIPSANITY, +2816,Farm,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Farm,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Farm,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Farm,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Farm,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Farm,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Farm,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Farm,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Farm,Shipsanity: Pyrite,SHIPSANITY, +2825,Farm,Shipsanity: Quartz,SHIPSANITY, +2826,Farm,Shipsanity: Ruby,SHIPSANITY, +2827,Farm,Shipsanity: Sandstone,SHIPSANITY, +2828,Farm,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Farm,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Farm,Shipsanity: Slate,SHIPSANITY, +2831,Farm,Shipsanity: Soapstone,SHIPSANITY, +2832,Farm,Shipsanity: Star Shards,SHIPSANITY, +2833,Farm,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Farm,Shipsanity: Tigerseye,SHIPSANITY, +2835,Farm,Shipsanity: Topaz,SHIPSANITY, +2836,Farm,Shipsanity: Trilobite,SHIPSANITY, +2837,Farm,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Farm,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2839,Farm,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Farm,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Farm,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Farm,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Farm,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Farm,Shipsanity: Bouquet,SHIPSANITY, +2845,Farm,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Farm,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Farm,Shipsanity: Green Algae,SHIPSANITY, +2848,Farm,Shipsanity: Hay,SHIPSANITY, +2849,Farm,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Farm,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Farm,Shipsanity: Pearl,SHIPSANITY, +2852,Farm,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Farm,Shipsanity: Seaweed,SHIPSANITY, +2854,Farm,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Farm,Shipsanity: White Algae,SHIPSANITY, +2856,Farm,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Farm,Shipsanity: Secret Note,SHIPSANITY, +2858,Farm,Shipsanity: Acorn,SHIPSANITY, +2859,Farm,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Farm,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Farm,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Farm,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Farm,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Farm,Shipsanity: Bean Starter,SHIPSANITY, +2865,Farm,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Farm,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Farm,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Farm,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Farm,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Farm,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Farm,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Farm,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Farm,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Farm,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Farm,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Farm,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Farm,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Farm,Shipsanity: Grape Starter,SHIPSANITY, +2879,Farm,Shipsanity: Grass Starter,SHIPSANITY, +2880,Farm,Shipsanity: Hops Starter,SHIPSANITY, +2881,Farm,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Farm,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Farm,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Farm,Shipsanity: Maple Seed,SHIPSANITY, +2885,Farm,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Farm,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Farm,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Farm,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Farm,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Farm,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Farm,Shipsanity: Pine Cone,SHIPSANITY, +2892,Farm,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Farm,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Farm,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Farm,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Farm,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Farm,Shipsanity: Rare Seed,SHIPSANITY, +2898,Farm,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Farm,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Farm,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Farm,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Farm,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Farm,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Farm,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Farm,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Farm,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Farm,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Farm,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Farm,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Farm,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Farm,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Farm,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Farm,Shipsanity: Broken CD,SHIPSANITY, +2914,Farm,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Farm,Shipsanity: Driftwood,SHIPSANITY, +2916,Farm,Shipsanity: Joja Cola,SHIPSANITY, +2917,Farm,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Farm,Shipsanity: Trash,SHIPSANITY, +2919,Farm,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Farm,Shipsanity: Golden Egg,SHIPSANITY, +2921,Farm,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Farm,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Farm,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Farm,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Farm,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Farm,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Farm,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Farm,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Farm,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Farm,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Farm,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Farm,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Farm,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Farm,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Farm,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Farm,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Farm,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Farm,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Farm,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Farm,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Farm,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Farm,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Farm,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Farm,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Farm,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY", +2946,Farm,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Farm,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Farm,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2949,Farm,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2950,Farm,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Farm,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2952,Farm,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2953,Farm,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2954,Farm,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Farm,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Farm,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Farm,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Farm,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY", +2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY", +2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY", +2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY", +2965,Farm,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Farm,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", +2967,Farm,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Farm,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Farm,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Farm,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY", +2971,Farm,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Farm,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Farm,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", 3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", 3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", 3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index c66825ef75fe..5b23d28f55f7 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -126,6 +126,7 @@ def load_location_csv() -> List[LocationData]: LocationData(None, Region.farm_house, Goal.full_house), LocationData(None, Region.island_west, Goal.greatest_walnut_hunter), LocationData(None, Region.adventurer_guild, Goal.protector_of_the_valley), + LocationData(None, Region.farm, Goal.full_shipment), LocationData(None, Region.qi_walnut_room, Goal.perfection), ] @@ -322,6 +323,26 @@ def extend_monstersanity_locations(randomized_locations: List[LocationData], wor randomized_locations.extend(filtered_progressive_goal_locations) +def extend_shipsanity_locations(randomized_locations: List[LocationData], world_options): + shipsanity = world_options[options.Shipsanity] + if shipsanity == options.Shipsanity.option_none: + return + if shipsanity == options.Shipsanity.option_everything: + ship_locations = [location for location in locations_by_tag[LocationTags.SHIPSANITY]] + filtered_ship_locations = filter_disabled_locations(world_options, ship_locations) + randomized_locations.extend(filtered_ship_locations) + return + shipsanity_locations = set() + if shipsanity == options.Shipsanity.option_fish or shipsanity == options.Shipsanity.option_full_shipment_with_fish: + shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_FISH]}) + if shipsanity == options.Shipsanity.option_crops: + shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_CROP]}) + if shipsanity == options.Shipsanity.option_full_shipment or shipsanity == options.Shipsanity.option_full_shipment_with_fish: + shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]}) + + filtered_shipsanity_locations = filter_disabled_locations(world_options, list(shipsanity_locations)) + randomized_locations.extend(filtered_shipsanity_locations) + def create_locations(location_collector: StardewLocationCollector, options: StardewValleyOptions, @@ -363,6 +384,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_walnut_purchase_locations(randomized_locations, options) extend_monstersanity_locations(randomized_locations, world_options) + extend_shipsanity_locations(randomized_locations, world_options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 436c8f3a450f..1920939b8fbb 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -29,6 +29,7 @@ from .wallet_logic import WalletLogic from ..data.crops_data import crops_by_name from ..data.monster_data import all_monsters_by_category +from ..locations import LocationTags, locations_by_tag from ..mods.logic.mod_logic import ModLogic from .. import options from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops @@ -816,3 +817,13 @@ def has_all_rarecrows(self) -> StardewRule: rules.append(self.received(f"Rarecrow #{rarecrow_number}")) return And(rules) + def can_ship(self, item: str) -> StardewRule: + return self.buildings.has_building(Building.shipping_bin) & self.has(item) + + def can_ship_everything(self) -> StardewRule: + shipsanity_prefix = "Shipsanity: " + all_items_to_ship = [] + for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: + all_items_to_ship.append(location.name[len(shipsanity_prefix):]) + return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) + diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 065c5fc71f96..6d3dc2fc5219 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -16,6 +16,7 @@ class Goal(Choice): Full House: Get married and have two children. Pairs well with Friendsanity. Greatest Walnut Hunter: Find all 130 Golden Walnuts Protector of the Valley: Complete all the monster slayer goals. Pairs well with Monstersanity + Full Shipment: Ship every item in the collection tab. Pairs well with Shipsanity Perfection: Attain Perfection, based on the vanilla definition. """ internal_name = "goal" @@ -30,6 +31,7 @@ class Goal(Choice): option_full_house = 6 option_greatest_walnut_hunter = 7 option_protector_of_the_valley = 8 + option_full_shipment = 9 # option_junimo_kart = # option_prairie_king = # option_fector_challenge = diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index d222c5f9540d..062f2df1f51d 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -39,25 +39,33 @@ def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOption set_ginger_island_rules(logic, multi_world, player, world_options) # 36.281 - 38.453 - set_tool_rules(logic, multiworld, player, world_options) - set_skills_rules(logic, multiworld, player, world_options) - set_bundle_rules(current_bundles, logic, multiworld, player) - set_building_rules(logic, multiworld, player, world_options) - set_cropsanity_rules(all_location_names, logic, multiworld, player, world_options) - set_story_quests_rules(all_location_names, logic, multiworld, player, world_options) - set_special_order_rules(all_location_names, logic, multiworld, player, world_options) - set_help_wanted_quests_rules(logic, multiworld, player, world_options) - set_fishsanity_rules(all_location_names, logic, multiworld, player) - set_museumsanity_rules(all_location_names, logic, multiworld, player, world_options) - set_friendsanity_rules(all_location_names, logic, multiworld, player) - set_backpack_rules(logic, multiworld, player, world_options) - set_festival_rules(all_location_names, logic, multiworld, player) - set_monstersanity_rules(all_location_names, logic, multiworld, player, world_options) - set_isolated_locations_rules(logic, multiworld, player) - set_traveling_merchant_rules(logic, multiworld, player) - set_arcade_machine_rules(logic, multiworld, player, world_options) - set_deepwoods_rules(logic, multiworld, player, world_options) - set_magic_spell_rules(logic, multiworld, player, world_options) + set_tool_rules(logic, multi_world, player, world_options) + # 36.980 - 37.228 + + set_skills_rules(logic, multi_world, player, world_options) + set_bundle_rules(current_bundles, logic, multi_world, player) + set_building_rules(logic, multi_world, player, world_options) + set_cropsanity_rules(all_location_names, logic, multi_world, player, world_options) + set_story_quests_rules(all_location_names, logic, multi_world, player, world_options) + # 1min09 - 1min14 + + set_special_order_rules(all_location_names, logic, multi_world, player, world_options) + set_help_wanted_quests_rules(logic, multi_world, player, world_options) + set_fishsanity_rules(all_location_names, logic, multi_world, player) + set_museumsanity_rules(all_location_names, logic, multi_world, player, world_options) + # 1min34 - 1min46 + + set_friendsanity_rules(all_location_names, logic, multi_world, player) + set_backpack_rules(logic, multi_world, player, world_options) + set_festival_rules(all_location_names, logic, multi_world, player) + set_monstersanity_rules(all_location_names, logic, multi_world, player, world_options) + set_shipsanity_rules(all_location_names, logic, multi_world, player, world_options) + set_isolated_locations_rules(logic, multi_world, player) + set_traveling_merchant_rules(logic, multi_world, player) + set_arcade_machine_rules(logic, multi_world, player, world_options) + + set_deepwoods_rules(logic, multi_world, player, world_options) + set_magic_spell_rules(logic, multi_world, player, world_options) # 1min52 - 1min53 # These times are for TestOptions # 1min36 - 1min38 # After the combat not duplicating a bunch of stuff # 1min28 - 1min30 # with the caching of combat rules @@ -687,6 +695,20 @@ def set_monstersanity_category_rules(all_location_names: List[str], logic: Stard MultiWorldRules.set_rule(location, rule.simplify()) +def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): + shipsanity_option = world_options[options.Shipsanity] + if shipsanity_option == options.Monstersanity.option_none: + return + + shipsanity_prefix = "Shipsanity: " + for location in locations.locations_by_tag[LocationTags.SHIPSANITY]: + if location.name not in all_location_names: + continue + item_to_ship = location.name[len(shipsanity_prefix):] + MultiWorldRules.set_rule(multi_world.get_location(location.name, player), + logic.can_ship(item_to_ship)) + + def set_traveling_merchant_day_rules(logic: StardewLogic, multi_world: MultiWorld, player: int): for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" diff --git a/worlds/stardew_valley/strings/goal_names.py b/worlds/stardew_valley/strings/goal_names.py index 0356c3ccdabe..f2de1b82700b 100644 --- a/worlds/stardew_valley/strings/goal_names.py +++ b/worlds/stardew_valley/strings/goal_names.py @@ -8,4 +8,5 @@ class Goal: full_house = "Full House" greatest_walnut_hunter = "Greatest Walnut Hunter" protector_of_the_valley = "Protector of the Valley" + full_shipment = "Full Shipment" perfection = "Perfection" diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index f5af277a8eff..31379202f8fb 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -410,7 +410,7 @@ def test_cannot_make_any_donation_without_museum_access(self): 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(guild_item), event=True) + self.multiworld.state.collect(self.world.create_item(guild_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)) @@ -430,7 +430,7 @@ def test_cannot_make_any_donation_without_museum_access(self): 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(guild_item), event=True) + self.multiworld.state.collect(self.world.create_item(guild_item), event=False) for donation in donation_locations: self.assertTrue(self.world.logic.region.can_reach_location(donation.name)(self.multiworld.state)) @@ -449,7 +449,7 @@ def test_cannot_make_any_donation_without_museum_access(self): 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(guild_item), event=True) + self.multiworld.state.collect(self.world.create_item(guild_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)) @@ -528,3 +528,81 @@ def assert_can_reach_heart_up_to(self, npc: str, max_reachable: int, step: int): can_reach = self.world.logic.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 = { + options.Shipsanity.internal_name: options.Shipsanity.option_none + } + + def test_no_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event: + self.assertFalse("Shipsanity" in location.name) + self.assertNotIn(LocationTags.SHIPSANITY, location_table[location.name].tags) + + +class TestShipsanityCrops(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_crops + } + + def test_only_crop_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + self.assertIn(LocationTags.SHIPSANITY_CROP, location_table[location.name].tags) + + +class TestShipsanityFish(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_fish + } + + def test_only_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + self.assertIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + +class TestShipsanityFullShipment(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment + } + + def test_only_full_shipment_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and 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 = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish + } + + def test_only_full_shipment_and_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and 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 = { + options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive + } + + def test_all_shipsanity_locations_require_shipping_bin(self): + bin_item = "Shipping Bin" + collect_all_except(self.multiworld, bin_item) + shipsanity_locations = [location for location in self.multiworld.get_locations() if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags] + + for location in shipsanity_locations: + self.assertFalse(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item(bin_item), event=False) + + for location in shipsanity_locations: + self.assertTrue(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) From e03b05892758523de33f6fd2b6d5a4f1890fa945 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:27:52 -0500 Subject: [PATCH 049/482] - Progress on new items for logic --- worlds/stardew_valley/data/crops.csv | 1 + worlds/stardew_valley/data/fish_data.py | 28 +- worlds/stardew_valley/data/locations.csv | 383 ++++++++++--------- worlds/stardew_valley/data/recipe_data.py | 5 + worlds/stardew_valley/locations.py | 37 +- worlds/stardew_valley/logic/artisan_logic.py | 3 + worlds/stardew_valley/logic/logic.py | 374 +++++++++--------- worlds/stardew_valley/logic/skill_logic.py | 14 +- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/strings/fish_names.py | 26 +- worlds/stardew_valley/strings/food_names.py | 43 ++- worlds/stardew_valley/strings/seed_names.py | 1 + worlds/stardew_valley/test/TestGeneration.py | 340 ++++++++++++++++ worlds/stardew_valley/test/TestRules.py | 17 +- 14 files changed, 833 insertions(+), 441 deletions(-) diff --git a/worlds/stardew_valley/data/crops.csv b/worlds/stardew_valley/data/crops.csv index e3d2dc8256db..c6cdf71733c2 100644 --- a/worlds/stardew_valley/data/crops.csv +++ b/worlds/stardew_valley/data/crops.csv @@ -23,6 +23,7 @@ Parsnip,Spring,Parsnip Seeds,Spring,"Pierre's General Store,JojaMart" Pineapple,Summer,Pineapple Seeds,Summer,"Island Trader" Poppy,Summer,Poppy Seeds,Summer,"Pierre's General Store,JojaMart" Potato,Spring,Potato Seeds,Spring,"Pierre's General Store,JojaMart" +Qi Fruit,"Spring,Summer,Fall,Winter",Qi Bean,"Spring,Summer,Fall,Winter","Qi's Walnut Room" Pumpkin,Fall,Pumpkin Seeds,Fall,"Pierre's General Store,JojaMart" Radish,Summer,Radish Seeds,Summer,"Pierre's General Store,JojaMart" Red Cabbage,Summer,Red Cabbage Seeds,Summer,"Pierre's General Store,JojaMart" diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 91a4431c6552..b94157d696d6 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -3,6 +3,7 @@ from . import season_data as season from .game_item import GameItem +from ..strings.fish_names import Fish from ..strings.region_names import Region @@ -11,6 +12,8 @@ class FishItem(GameItem): locations: Tuple[str] seasons: Tuple[str] difficulty: int + legendary: bool + extended_family: bool mod_name: Optional[str] def __repr__(self): @@ -43,11 +46,11 @@ def __repr__(self): def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Union[str, Tuple[str, ...]], - difficulty: int, mod_name: Optional[str] = None) -> FishItem: + difficulty: int, legendary: bool = False, extended_family: bool = False, mod_name: Optional[str] = None) -> FishItem: if isinstance(seasons, str): seasons = (seasons,) - fish_item = FishItem(name, item_id, locations, seasons, difficulty, mod_name) + fish_item = FishItem(name, item_id, locations, seasons, difficulty, legendary, extended_family, mod_name) all_fish.append(fish_item) return fish_item @@ -57,7 +60,7 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un blue_discus = create_fish("Blue Discus", 838, ginger_island_river, season.all_seasons, 60) bream = create_fish("Bream", 132, town_river + forest_river, season.all_seasons, 35) bullhead = create_fish("Bullhead", 700, mountain_lake, season.all_seasons, 46) -carp = create_fish("Carp", 142, mountain_lake + secret_woods + sewers + mutant_bug_lair, season.not_winter, 15) +carp = create_fish(Fish.carp, 142, mountain_lake + secret_woods + sewers + mutant_bug_lair, season.not_winter, 15) catfish = create_fish("Catfish", 143, town_river + forest_river + secret_woods, (season.spring, season.fall), 75) chub = create_fish("Chub", 702, forest_river + mountain_lake, season.all_seasons, 35) dorado = create_fish("Dorado", 704, forest_river, season.summer, 78) @@ -106,11 +109,17 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un midnight_squid = create_fish("Midnight Squid", 798, night_market, season.winter, 55) spook_fish = create_fish("Spook Fish", 799, night_market, season.winter, 60) -angler = create_fish("Angler", 160, town_river, season.fall, 85) -crimsonfish = create_fish("Crimsonfish", 159, ocean, season.summer, 95) -glacierfish = create_fish("Glacierfish", 775, forest_river, season.winter, 100) -legend = create_fish("Legend", 163, mountain_lake, season.spring, 110) -mutant_carp = create_fish("Mutant Carp", 682, sewers, season.all_seasons, 80) +angler = create_fish(Fish.angler, 160, town_river, season.fall, 85, True, False) +crimsonfish = create_fish(Fish.crimsonfish, 159, ocean, season.summer, 95, True, False) +glacierfish = create_fish(Fish.glacierfish, 775, forest_river, season.winter, 100, True, False) +legend = create_fish(Fish.legend, 163, mountain_lake, season.spring, 110, True, False) +mutant_carp = create_fish(Fish.mutant_carp, 682, sewers, season.all_seasons, 80, True, False) + +ms_angler = create_fish(Fish.ms_angler, 160, town_river, season.fall, 85, True, True) +son_of_crimsonfish = create_fish(Fish.son_of_crimsonfish, 159, ocean, season.summer, 95, True, True) +glacierfish_jr = create_fish(Fish.glacierfish_jr, 775, forest_river, season.winter, 100, True, True) +legend_ii = create_fish(Fish.legend_ii, 163, mountain_lake, season.spring, 110, True, True) +radioactive_carp = create_fish(Fish.radioactive_carp, 682, sewers, season.all_seasons, 80, True, True) clam = create_fish("Clam", 372, ocean, season.all_seasons, -1) cockle = create_fish("Cockle", 718, ocean, season.all_seasons, -1) @@ -123,7 +132,8 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un shrimp = create_fish("Shrimp", 720, ocean, season.all_seasons, -1) snail = create_fish("Snail", 721, fresh_water, season.all_seasons, -1) -legendary_fish = [crimsonfish, angler, legend, glacierfish, mutant_carp] +legendary_fish = [angler, crimsonfish, glacierfish, legend, mutant_carp] +extended_family = [ms_angler, son_of_crimsonfish, glacierfish_jr, legend_ii, radioactive_carp] special_fish = [*legendary_fish, blob_fish, lava_eel, octopus, scorpion_carp, ice_pip, super_cucumber, dorado] island_fish = [lionfish, blue_discus, stingray] diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a825d04536b0..97c15b2d3207 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -384,186 +384,191 @@ id,region,name,tags,mod_name 1063,Beach,Fishsanity: Mussel,FISHSANITY, 1064,Beach,Fishsanity: Shrimp,FISHSANITY, 1065,Beach,Fishsanity: Oyster,FISHSANITY, -1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, -1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, -1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, -1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, -1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, -1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, -1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, -1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, -1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, -1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, -1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, -1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, -1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, -1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, -1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, -1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, -1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, -1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, -1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, -1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, -1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, -1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, -1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, -1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, -1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, -1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, -1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, -1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, -1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, -1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, -1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, -1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, -1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, -1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, -1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, -1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, -1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, -1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, -1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, -1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, -1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, -1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, -1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, -1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, -1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, -1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, -1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", -1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, -1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, -1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, -1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, -1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, -1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, -1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, -1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, -1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, -1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, -1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, -1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, -1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, -1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, -1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, -1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, -1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, -1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, -1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, -1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, -1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, -1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, -1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, -1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, -1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, -1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, -1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, -1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, -1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, -1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, -1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, -1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, -1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, -1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, -1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, -1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, -1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, -1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, -1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, -1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, -1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, -1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, -1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, -1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, -1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, -1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, -1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, -1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, -1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, -1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, -1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, -1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, -1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, -1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, -1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, -1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, -1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, -1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, -1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, -1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, -1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, -1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, -1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, -1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, -1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, -1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, -1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, -1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, -1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, -1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, -1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, -1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, -1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, -1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, -1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, -1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, -1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, -1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, -1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, -1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, -1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, -1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, -1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, -1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, -1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, -1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, -1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, -1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, -1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, -1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, -1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, -1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, -1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, -1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, -1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, -1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, -1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, -1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, -1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, -1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, -1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, -1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, -1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, -1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, -1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, -1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, -1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, -1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, -1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, -1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, -1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, -1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, -1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, -1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, -1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, -1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, -1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, -1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, -1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, -1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, -1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, -1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, -1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, -1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, -1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, -1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, -1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, -1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, -1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, -1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, -1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, -1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, -1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, +1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, +1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, +1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, +1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, +1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, +1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, +1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, +1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, +1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, +1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, +1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, +1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, +1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, +1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, +1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, +1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, +1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, +1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, +1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, +1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, +1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, +1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, +1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, +1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, +1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, +1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, +1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, +1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, +1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, +1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, +1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, +1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, +1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, +1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, +1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, +1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, +1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, +1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, +1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, +1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, +1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, +1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, +1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, +1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, +1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, +1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, +1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", +1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, +1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, +1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, +1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, +1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, +1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, +1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, +1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, +1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, +1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, +1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, +1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, +1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, +1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, +1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, +1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, +1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, +1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, +1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, +1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, +1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, +1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, +1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, +1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, +1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, +1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, +1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, +1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, +1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, +1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, +1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, +1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, +1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, +1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, +1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, +1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, +1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, +1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, +1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, +1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, +1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, +1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, +1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, +1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, +1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, +1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, +1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, +1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, +1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, +1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, +1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, +1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, +1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, +1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, +1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, +1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, +1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, +1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, +1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, +1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, +1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, +1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, +1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, +1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, +1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, +1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, +1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, +1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, +1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, +1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, +1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, +1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, +1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, +1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, +1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, +1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, +1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, +1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, +1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, +1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, +1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, +1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, +1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, +1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, +1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, +1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, +1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, +1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, +1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, +1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, +1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, +1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, +1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, +1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, +1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, +1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, +1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, +1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, +1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, +1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, +1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, +1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, +1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, +1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, +1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, +1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, +1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, +1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, +1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, +1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, +1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, +1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, +1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, +1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, +1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, +1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, +1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, +1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, +1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, +1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, +1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, +1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, +1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, +1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, +1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, +1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, +1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, +1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, +1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, +1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, +1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, +1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, +1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, 1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, 1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, 1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, @@ -1474,7 +1479,7 @@ id,region,name,tags,mod_name 2835,Farm,Shipsanity: Topaz,SHIPSANITY, 2836,Farm,Shipsanity: Trilobite,SHIPSANITY, 2837,Farm,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Farm,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Farm,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", 2839,Farm,Shipsanity: Curiosity Lure,SHIPSANITY, 2840,Farm,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2841,Farm,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", @@ -1581,23 +1586,23 @@ id,region,name,tags,mod_name 2942,Farm,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", 2943,Farm,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", 2944,Farm,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Farm,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY", +2945,Farm,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", 2946,Farm,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", 2947,Farm,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Farm,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2949,Farm,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Farm,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2949,Farm,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", 2950,Farm,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Farm,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2952,Farm,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2953,Farm,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Farm,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2952,Farm,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2953,Farm,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", 2954,Farm,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", 2955,Farm,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", 2956,Farm,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", 2957,Farm,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2958,Farm,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", 2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY", -2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", 2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY", 2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY", 2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY", diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 029de15fdfda..aaec40d0c6bf 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -134,17 +134,22 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) algae_soup = friendship_recipe(Meal.algae_soup, NPC.clint, 3, {WaterItem.green_algae: 4}) artichoke_dip = queen_of_sauce_recipe(Meal.artichoke_dip, 1, Season.fall, 28, {Vegetable.artichoke: 1, AnimalProduct.cow_milk: 1}) +autumn_bounty = friendship_recipe(Meal.autumn_bounty, NPC.demetrius, 7, {Vegetable.yam: 1, Vegetable.pumpkin: 1}) baked_fish = queen_of_sauce_recipe(Meal.baked_fish, 1, Season.summer, 7, {Fish.sunfish: 1, Fish.bream: 1, Ingredient.wheat_flour: 1}) bean_hotpot = friendship_recipe(Meal.bean_hotpot, NPC.clint, 7, {Vegetable.green_bean: 2}) blackberry_cobbler_ingredients = {Forageable.blackberry: 2, Ingredient.sugar: 1, Ingredient.wheat_flour: 1} blackberry_cobbler_qos = queen_of_sauce_recipe(Meal.blackberry_cobbler, 2, Season.fall, 14, blackberry_cobbler_ingredients) blueberry_tart = friendship_recipe(Meal.blueberry_tart, NPC.pierre, 3, {Fruit.blueberry: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.any_egg: 1}) bread = queen_of_sauce_recipe(Meal.bread, 1, Season.summer, 28, {Ingredient.wheat_flour: 1}) +bruschetta = queen_of_sauce_recipe(Meal.bruschetta, 2, Season.winter, 21, {Meal.bread: 1, Ingredient.oil: 1, Vegetable.tomato: 1}) +carp_surprise = queen_of_sauce_recipe(Meal.carp_surprise, 2, Season.summer, 7, {Fish.carp: 4}) cheese_cauliflower = friendship_recipe(Meal.cheese_cauliflower, NPC.pam, 3, {Vegetable.cauliflower: 1, ArtisanGood.cheese: 1}) chocolate_cake_ingredients = {Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.chicken_egg: 1} chocolate_cake_qos = queen_of_sauce_recipe(Meal.chocolate_cake, 1, Season.winter, 14, chocolate_cake_ingredients) chowder = friendship_recipe(Meal.chowder, NPC.willy, 3, {WaterItem.clam: 1, AnimalProduct.cow_milk: 1}) +coleslaw = queen_of_sauce_recipe(Meal.coleslaw, 14, Season.spring, 14, {Vegetable.red_cabbage: 1, Ingredient.vinegar: 1, ArtisanGood.mayonnaise: 1}) complete_breakfast = queen_of_sauce_recipe(Meal.complete_breakfast, 2, Season.spring, 21, {Meal.fried_egg: 1, AnimalProduct.milk: 1, Meal.hashbrowns: 1, Meal.pancakes: 1}) +cookie = friendship_recipe(Meal.cookie, NPC.evelyn, 4, {Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.chicken_egg: 1}) crab_cakes_ingredients = {Fish.crab: 1, Ingredient.wheat_flour: 1, AnimalProduct.chicken_egg: 1, Ingredient.oil: 1} crab_cakes_qos = queen_of_sauce_recipe(Meal.crab_cakes, 2, Season.fall, 21, crab_cakes_ingredients) cranberry_candy = queen_of_sauce_recipe(Meal.cranberry_candy, 1, Season.winter, 28, {Fruit.cranberries: 1, Fruit.apple: 1, Ingredient.sugar: 1}) diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 5b23d28f55f7..35e930be254d 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -60,6 +60,7 @@ class LocationTags(enum.Enum): FESTIVAL_HARD = enum.auto() SPECIAL_ORDER_BOARD = enum.auto() SPECIAL_ORDER_QI = enum.auto() + REQUIRES_QI_ORDERS = enum.auto() GINGER_ISLAND = enum.auto() WALNUT_PURCHASE = enum.auto() REQUIRES_MUSEUM = enum.auto() @@ -180,19 +181,19 @@ def extend_fishsanity_locations(randomized_locations: List[LocationData], option randomized_locations.extend(location_table[f"{prefix}{special.name}"] for special in special_fish) elif options.fishsanity == Fishsanity.option_randomized: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if random.random() < 0.4] - randomized_locations.extend(filter_ginger_island(options, fish_locations)) - elif options.fishsanity == Fishsanity.option_all: + randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) + elif world_options[options.Fishsanity] == options.Fishsanity.option_all: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish] - randomized_locations.extend(filter_ginger_island(options, fish_locations)) - elif options.fishsanity == Fishsanity.option_exclude_legendaries: + randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) + elif world_options[options.Fishsanity] == options.Fishsanity.option_exclude_legendaries: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish not in legendary_fish] - randomized_locations.extend(filter_ginger_island(options, fish_locations)) - elif options.fishsanity == Fishsanity.option_exclude_hard_fish: + randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) + elif world_options[options.Fishsanity] == options.Fishsanity.option_exclude_hard_fish: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish.difficulty < 80] - randomized_locations.extend(filter_ginger_island(options, fish_locations)) - elif options.fishsanity == Fishsanity.option_only_easy_fish: + randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) + elif world_options[options.Fishsanity] == options.Fishsanity.option_only_easy_fish: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish.difficulty < 50] - randomized_locations.extend(filter_ginger_island(options, fish_locations)) + randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) def extend_museumsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, random: Random): @@ -400,13 +401,19 @@ def filter_ginger_island(options: StardewValleyOptions, locations: List[Location return [location for location in locations if include_island or LocationTags.GINGER_ISLAND not in location.tags] -def filter_modded_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: - current_mod_names = options.mods +def filter_qi_order_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: + include_qi_orders = world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_qi + return [location for location in locations if include_qi_orders or LocationTags.REQUIRES_QI_ORDERS not in location.tags] + + +def filter_modded_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: + current_mod_names = world_options[options.Mods] return [location for location in locations if location.mod_name is None or location.mod_name in current_mod_names] -def filter_disabled_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: - locations_museum_filter = filter_museum_locations(options, locations) - locations_island_filter = filter_ginger_island(options, locations_museum_filter) - locations_mod_filter = filter_modded_locations(options, locations_island_filter) +def filter_disabled_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: + locations_museum_filter = filter_museum_locations(world_options, locations) + locations_island_filter = filter_ginger_island(world_options, locations_museum_filter) + locations_qi_filter = filter_qi_order_locations(world_options, locations_island_filter) + locations_mod_filter = filter_modded_locations(world_options, locations_qi_filter) return locations_mod_filter diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 64e6b572065c..388a8bc7fbef 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -61,3 +61,6 @@ def can_age(self, item: Union[str, StardewRule], quality: str) -> StardewRule: else: rule: StardewRule = item return self.has(Machine.cask) & self.time.has_lived_months(months) & rule + + def can_mayonnaise(self, item: str) -> StardewRule: + return self.has(Machine.mayonnaise_machine) & self.has(item) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 1920939b8fbb..b3994a71dd67 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -34,7 +34,7 @@ from .. import options from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops from ..data.bundle_data import BundleItem -from ..data.fish_data import island_fish +from ..data.fish_data import island_fish, legendary_fish from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..options import StardewOptions @@ -180,222 +180,216 @@ def __post_init__(self): }) self.item_rules.update({ - ArtisanGood.aged_roe: self.artisan.can_preserves_jar(AnimalProduct.roe), + "Energy Tonic": self.money.can_spend_at(Region.hospital, 1000), + "Fishing Chest": self.fishing.can_fish_chests(), + "Hot Java Ring": self.region.can_reach(Region.volcano_floor_10), + "JotPK Big Buff": self.arcade.has_jotpk_power_level(7), + "JotPK Max Buff": self.arcade.has_jotpk_power_level(9), + "JotPK Medium Buff": self.arcade.has_jotpk_power_level(4), + "JotPK Small Buff": self.arcade.has_jotpk_power_level(2), + "Junimo Kart Big Buff": self.arcade.has_junimo_kart_power_level(6), + "Junimo Kart Max Buff": self.arcade.has_junimo_kart_power_level(8), + "Junimo Kart Medium Buff": self.arcade.has_junimo_kart_power_level(4), + "Junimo Kart Small Buff": self.arcade.has_junimo_kart_power_level(2), + "Magic Rock Candy": self.region.can_reach(Region.desert) & self.has("Prismatic Shard"), + "Muscle Remedy": self.money.can_spend_at(Region.hospital, 1000), + # self.has(Ingredient.vinegar)), + # self.received("Deluxe Fertilizer Recipe") & self.has(MetalBar.iridium) & self.has(SVItem.sap), + # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.emily, 3) & self.has(Forageable.leek) & self.has(Forageable.dandelion) & + # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)), + Animal.chicken: self.can_buy_animal(Animal.chicken), + Animal.cow: self.can_buy_animal(Animal.cow), + Animal.dinosaur: self.buildings.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), + Animal.duck: self.can_buy_animal(Animal.duck), + Animal.goat: self.can_buy_animal(Animal.goat), + Animal.ostrich: self.buildings.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), + Animal.pig: self.can_buy_animal(Animal.pig), + Animal.rabbit: self.can_buy_animal(Animal.rabbit), + Animal.sheep: self.can_buy_animal(Animal.sheep), AnimalProduct.any_egg: self.has(AnimalProduct.chicken_egg) | self.has(AnimalProduct.duck_egg), - Fish.any: Or([self.can_catch_fish(fish) for fish in all_fish]), - Geode.artifact_trove: self.has(Geode.omni) & self.region.can_reach(Region.desert), + AnimalProduct.brown_egg: self.has_animal(Animal.chicken), + AnimalProduct.chicken_egg: self.has([AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg], 1), + AnimalProduct.cow_milk: self.has(AnimalProduct.milk) | self.has(AnimalProduct.large_milk), + AnimalProduct.duck_egg: self.has_animal(Animal.duck), + AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), + AnimalProduct.egg: self.has_animal(Animal.chicken), + AnimalProduct.goat_milk: self.has(Animal.goat), + AnimalProduct.large_brown_egg: self.has_happy_animal(Animal.chicken), + AnimalProduct.large_egg: self.has_happy_animal(Animal.chicken), + AnimalProduct.large_goat_milk: self.has_happy_animal(Animal.goat), + AnimalProduct.large_milk: self.has_happy_animal(Animal.cow), + AnimalProduct.milk: self.has_animal(Animal.cow), + AnimalProduct.ostrich_egg: self.tool.can_forage(Generic.any, Region.island_north, True), + AnimalProduct.rabbit_foot: self.has_happy_animal(Animal.rabbit), + AnimalProduct.roe: self.skill.can_fish() & self.buildings.has_building(Building.fish_pond), + AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.squid)), + AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.buildings.has_building(Building.fish_pond), + AnimalProduct.truffle: self.has_animal(Animal.pig) & self.season.has_any_not_winter(), + AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), + AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), + ArtisanGood.aged_roe: self.artisan.can_preserves_jar(AnimalProduct.roe), + ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.season.has_any_not_winter()) | self.has(Machine.solar_panel), + ArtisanGood.caviar: self.artisan.can_preserves_jar(AnimalProduct.sturgeon_roe), + ArtisanGood.cheese: (self.has(AnimalProduct.cow_milk) & self.has(Machine.cheese_press)) | (self.region.can_reach(Region.desert) & self.has(Mineral.emerald)), + ArtisanGood.cloth: (self.has(AnimalProduct.wool) & self.has(Machine.loom)) | (self.region.can_reach(Region.desert) & self.has(Mineral.aquamarine)), + ArtisanGood.dinosaur_mayonnaise: self.artisan.can_mayonnaise(AnimalProduct.dinosaur_egg), + ArtisanGood.duck_mayonnaise: self.artisan.can_mayonnaise(AnimalProduct.duck_egg), + ArtisanGood.goat_cheese: self.has(AnimalProduct.goat_milk) & self.has(Machine.cheese_press), + ArtisanGood.green_tea: self.artisan.can_keg(Vegetable.tea_leaves), + ArtisanGood.honey: self.money.can_spend_at(Region.oasis, 200) | (self.has(Machine.bee_house) & self.season.has_any_not_winter()), + ArtisanGood.jelly: self.artisan.has_jelly(), + ArtisanGood.juice: self.artisan.has_juice(), + ArtisanGood.maple_syrup: self.has(Machine.tapper), + ArtisanGood.mayonnaise: self.artisan.can_mayonnaise(AnimalProduct.chicken_egg), + ArtisanGood.mead: self.artisan.can_keg(ArtisanGood.honey), + ArtisanGood.oak_resin: self.has(Machine.tapper), + ArtisanGood.pale_ale: self.artisan.can_keg(Vegetable.hops), + ArtisanGood.pickles: self.artisan.has_pickle(), + ArtisanGood.pine_tar: self.has(Machine.tapper), + ArtisanGood.truffle_oil: self.has(AnimalProduct.truffle) & self.has(Machine.oil_maker), + ArtisanGood.void_mayonnaise: (self.skill.can_fish(Region.witch_swamp)) | (self.artisan.can_mayonnaise(AnimalProduct.void_egg)), + ArtisanGood.wine: self.artisan.has_wine(), + Beverage.beer: self.artisan.can_keg(Vegetable.wheat) | self.money.can_spend_at(Region.saloon, 400), + Beverage.coffee: self.artisan.can_keg(Seed.coffee) | self.has(Machine.coffee_maker) | (self.money.can_spend_at(Region.saloon, 300)) | self.has("Hot Java Ring"), + Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600), + Beverage.triple_shot_espresso: self.has("Hot Java Ring"), Craftable.bait: (self.skill.has_level(Skill.fishing, 2) & self.has(Loot.bug_meat)) | self.has(Machine.worm_bin), + Craftable.bomb: self.skill.has_level(Skill.mining, 6) & self.has(Material.coal) & self.has(Ore.iron), + Craftable.cherry_bomb: self.skill.has_level(Skill.mining, 1) & self.has(Material.coal) & self.has(Ore.copper), + Craftable.flute_block: self.relationship.has_hearts(NPC.robin, 6) & self.region.can_reach(Region.carpenter) & self.has(Material.wood) & self.has(Ore.copper) & self.has(Material.fiber), + Craftable.life_elixir: self.skill.has_level(Skill.combat, 2) & self.has(Forageable.red_mushroom) & self.has(Forageable.purple_mushroom) & self.has(Forageable.morel) & self.has(Forageable.chanterelle), + Craftable.mega_bomb: self.skill.has_level(Skill.mining, 8) & self.has(Ore.gold) & self.has(Loot.solar_essence) & self.has(Loot.void_essence), + Craftable.monster_musk: self.has_prismatic_jelly_reward_access() & self.has(Loot.slime) & self.has(Loot.bat_wing), + Craftable.oil_of_garlic: (self.skill.has_level(Skill.combat, 6) & self.has(Vegetable.garlic) & self.has(Ingredient.oil)) | (self.money.can_spend_at(Region.mines_dwarf_shop, 3000)), + Craftable.rain_totem: self.skill.has_level(Skill.foraging, 9) & self.has(Material.hardwood) & self.has(ArtisanGood.truffle_oil) & self.has(ArtisanGood.pine_tar), + Craftable.scarecrow: self.skill.has_farming_level(1) & self.has(Material.wood) & self.has(Material.coal) & self.has(Material.fiber), + Craftable.staircase: self.skill.has_level(Skill.mining, 2) & self.has(Material.stone), Fertilizer.basic: (self.has(Material.sap) & self.skill.has_farming_level(1)) | (self.time.has_lived_months(1) & self.money.can_spend_at(Region.pierre_store, 100)), - Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), Fertilizer.deluxe: False_(), - # self.received("Deluxe Fertilizer Recipe") & self.has(MetalBar.iridium) & self.has(SVItem.sap), + Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), - Loot.bat_wing: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), - ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.season.has_any_not_winter()) | self.has(Machine.solar_panel), - Machine.bee_house: self.skill.has_farming_level(3) & self.has(MetalBar.iron) & self.has(ArtisanGood.maple_syrup) & self.has(Material.coal) & self.has(Material.wood), - Beverage.beer: self.artisan.can_keg(Vegetable.wheat) | self.money.can_spend_at(Region.saloon, 400), + Fish.any: Or([self.can_catch_fish(fish) for fish in all_fish]), + Fish.crab: self.skill.can_crab_pot(Region.beach), + Fish.crayfish: self.skill.can_crab_pot(Region.town), + Fish.lobster: self.skill.can_crab_pot(Region.beach), + Fish.mussel: self.tool.can_forage(Generic.any, Region.beach) or self.has(Fish.mussel_node), + Fish.mussel_node: self.region.can_reach(Region.island_west), + Fish.oyster: self.tool.can_forage(Generic.any, Region.beach), + Fish.periwinkle: self.skill.can_crab_pot(Region.town), + Fish.shrimp: self.skill.can_crab_pot(Region.beach), + Fish.snail: self.skill.can_crab_pot(Region.town), Forageable.blackberry: self.tool.can_forage(Season.fall), - Craftable.bomb: self.skill.has_level(Skill.mining, 6) & self.has(Material.coal) & self.has(Ore.iron), - Fossil.bone_fragment: self.region.can_reach(Region.dig_site), - Gift.bouquet: self.relationship.has_hearts(Generic.bachelor, 8) & self.money.can_spend_at(Region.pierre_store, 100), - Meal.bread: self.money.can_spend_at(Region.saloon, 120), - Trash.broken_cd: self.skill.can_crab_pot(), - Trash.broken_glasses: self.skill.can_crab_pot(), - Loot.bug_meat: self.mine.can_mine_in_the_mines_floor_1_40(), Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), - Machine.cask: self.buildings.has_house(3) & self.region.can_reach(Region.cellar) & self.has(Material.wood) & self.has(Material.hardwood), Forageable.cave_carrot: self.tool.can_forage(Generic.any, Region.mines_floor_10, True), - ArtisanGood.caviar: self.artisan.can_preserves_jar(AnimalProduct.sturgeon_roe), Forageable.chanterelle: self.tool.can_forage(Season.fall, Region.secret_woods), - Machine.cheese_press: self.skill.has_farming_level(6) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.hardwood) & self.has(MetalBar.copper), - ArtisanGood.cheese: (self.has(AnimalProduct.cow_milk) & self.has(Machine.cheese_press)) | (self.region.can_reach(Region.desert) & self.has(Mineral.emerald)), - Craftable.cherry_bomb: self.skill.has_level(Skill.mining, 1) & self.has(Material.coal) & self.has(Ore.copper), - Animal.chicken: self.can_buy_animal(Animal.chicken), - AnimalProduct.chicken_egg: self.has([AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg], 1), - Material.cinder_shard: self.region.can_reach(Region.volcano_floor_5), - WaterItem.clam: self.tool.can_forage(Generic.any, Region.beach), - Material.clay: self.region.can_reach_any([Region.farm, Region.beach, Region.quarry]) & self.tool.has_tool(Tool.hoe), - ArtisanGood.cloth: (self.has(AnimalProduct.wool) & self.has(Machine.loom)) | (self.region.can_reach(Region.desert) & self.has(Mineral.aquamarine)), - Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.action.can_do_panning(), - WaterItem.cockle: self.tool.can_forage(Generic.any, Region.beach), Forageable.coconut: self.tool.can_forage(Generic.any, Region.desert), - Beverage.coffee: self.artisan.can_keg(Seed.coffee) | self.has(Machine.coffee_maker) | (self.money.can_spend_at(Region.saloon, 300)) | self.has("Hot Java Ring"), - Machine.coffee_maker: self.received(Machine.coffee_maker), Forageable.common_mushroom: self.tool.can_forage(Season.fall) | (self.tool.can_forage(Season.spring, Region.secret_woods)), - MetalBar.copper: self.can_smelt(Ore.copper), - Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), - WaterItem.coral: self.tool.can_forage(Generic.any, Region.tide_pools) | self.tool.can_forage(Season.summer, Region.beach), - Animal.cow: self.can_buy_animal(Animal.cow), - AnimalProduct.cow_milk: self.has(AnimalProduct.milk) | self.has(AnimalProduct.large_milk), - Fish.crab: self.skill.can_crab_pot(Region.beach), - Machine.crab_pot: self.skill.has_level(Skill.fishing, 3) & (self.money.can_spend_at(Region.fish_shop, 1500) | (self.has(MetalBar.iron) & self.has(Material.wood))), - Fish.crayfish: self.skill.can_crab_pot(Region.town), Forageable.crocus: self.tool.can_forage(Season.winter), Forageable.crystal_fruit: self.tool.can_forage(Season.winter), Forageable.daffodil: self.tool.can_forage(Season.spring), Forageable.dandelion: self.tool.can_forage(Season.spring), - Animal.dinosaur: self.buildings.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), Forageable.dragon_tooth: self.tool.can_forage(Generic.any, Region.volcano_floor_10), - "Dried Starfish": self.skill.can_fish() & self.region.can_reach(Region.beach), - Trash.driftwood: self.skill.can_crab_pot(), - AnimalProduct.duck_egg: self.has_animal(Animal.duck), - AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), - Animal.duck: self.can_buy_animal(Animal.duck), - AnimalProduct.egg: self.has_animal(Animal.chicken), - AnimalProduct.brown_egg: self.has_animal(Animal.chicken), - "Energy Tonic": self.region.can_reach(Region.hospital) & self.money.can_spend(1000), - Material.fiber: True_(), Forageable.fiddlehead_fern: self.tool.can_forage(Season.summer, Region.secret_woods), - "Magic Rock Candy": self.region.can_reach(Region.desert) & self.has("Prismatic Shard"), - "Fishing Chest": self.fishing.can_fish_chests(), - Craftable.flute_block: self.relationship.has_hearts(NPC.robin, 6) & self.region.can_reach(Region.carpenter) & self.has(Material.wood) & self.has(Ore.copper) & self.has(Material.fiber), - Geode.frozen: self.mine.can_mine_in_the_mines_floor_41_80(), - Machine.furnace: self.has(Material.stone) & self.has(Ore.copper), - Geode.geode: self.mine.can_mine_in_the_mines_floor_1_40(), Forageable.ginger: self.tool.can_forage(Generic.any, Region.island_west, True), - ArtisanGood.goat_cheese: self.has(AnimalProduct.goat_milk) & self.has(Machine.cheese_press), - AnimalProduct.goat_milk: self.has(Animal.goat), - Animal.goat: self.can_buy_animal(Animal.goat), - MetalBar.gold: self.can_smelt(Ore.gold), - Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), - Geode.golden_coconut: self.region.can_reach(Region.island_north), - Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), - WaterItem.green_algae: self.fishing.can_fish_in_freshwater(), - ArtisanGood.green_tea: self.artisan.can_keg(Vegetable.tea_leaves), - Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_west)), Forageable.hay: self.buildings.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), Forageable.hazelnut: self.tool.can_forage(Season.fall), Forageable.holly: self.tool.can_forage(Season.winter), - ArtisanGood.honey: self.money.can_spend_at(Region.oasis, 200) | (self.has(Machine.bee_house) & self.season.has_any_not_winter()), - "Hot Java Ring": self.region.can_reach(Region.volcano_floor_10), - Meal.ice_cream: (self.season.has(Season.summer) & self.money.can_spend_at(Region.town, 250)) | self.money.can_spend_at(Region.oasis, 240), - # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)), - MetalBar.iridium: self.can_smelt(Ore.iridium), - Ore.iridium: self.mine.can_mine_in_the_skull_cavern(), - MetalBar.iron: self.can_smelt(Ore.iron), - Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), - ArtisanGood.jelly: self.artisan.has_jelly(), - Trash.joja_cola: self.money.can_spend_at(Region.saloon, 75), - "JotPK Small Buff": self.arcade.has_jotpk_power_level(2), - "JotPK Medium Buff": self.arcade.has_jotpk_power_level(4), - "JotPK Big Buff": self.arcade.has_jotpk_power_level(7), - "JotPK Max Buff": self.arcade.has_jotpk_power_level(9), - ArtisanGood.juice: self.artisan.has_juice(), - "Junimo Kart Small Buff": self.arcade.has_junimo_kart_power_level(2), - "Junimo Kart Medium Buff": self.arcade.has_junimo_kart_power_level(4), - "Junimo Kart Big Buff": self.arcade.has_junimo_kart_power_level(6), - "Junimo Kart Max Buff": self.arcade.has_junimo_kart_power_level(8), - Machine.keg: self.skill.has_farming_level(8) & self.has(Material.wood) & self.has(MetalBar.iron) & self.has(MetalBar.copper) & self.has(ArtisanGood.oak_resin), - AnimalProduct.large_egg: self.has_happy_animal(Animal.chicken), - AnimalProduct.large_brown_egg: self.has_happy_animal(Animal.chicken), - AnimalProduct.large_goat_milk: self.has_happy_animal(Animal.goat), - AnimalProduct.large_milk: self.has_happy_animal(Animal.cow), Forageable.leek: self.tool.can_forage(Season.spring), - Craftable.life_elixir: self.skill.has_level(Skill.combat, 2) & self.has(Forageable.red_mushroom) & self.has(Forageable.purple_mushroom) & self.has(Forageable.morel) & self.has(Forageable.chanterelle), - Machine.lightning_rod: self.skill.has_level(Skill.foraging, 6) & self.has(MetalBar.iron) & self.has(MetalBar.quartz) & self.has(Loot.bat_wing), - Fish.lobster: self.skill.can_crab_pot(Region.beach), - Machine.loom: self.skill.has_farming_level(7) & self.has(Material.wood) & self.has(Material.fiber) & self.has(ArtisanGood.pine_tar), Forageable.magma_cap: self.tool.can_forage(Generic.any, Region.volcano_floor_5), - Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.buildings.has_building(Building.fish_pond)), - ArtisanGood.maple_syrup: self.has(Machine.tapper), - ArtisanGood.mayonnaise: self.has(Machine.mayonnaise_machine) & self.has(AnimalProduct.chicken_egg), - Machine.mayonnaise_machine: self.skill.has_farming_level(2) & self.has(Material.wood) & self.has(Material.stone) & self.has("Earth Crystal") & self.has(MetalBar.copper), - ArtisanGood.mead: self.artisan.can_keg(ArtisanGood.honey), - Craftable.mega_bomb: self.skill.has_level(Skill.mining, 8) & self.has(Ore.gold) & self.has(Loot.solar_essence) & self.has(Loot.void_essence), - Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Craftable.rain_totem), - AnimalProduct.milk: self.has_animal(Animal.cow), - Craftable.monster_musk: self.has_prismatic_jelly_reward_access() & self.has(Loot.slime) & self.has(Loot.bat_wing), Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods), - "Muscle Remedy": self.region.can_reach(Region.hospital) & self.money.can_spend(1000), - Fish.mussel: self.tool.can_forage(Generic.any, Region.beach) or self.has(Fish.mussel_node), - Fish.mussel_node: self.region.can_reach(Region.island_west), - WaterItem.nautilus_shell: self.tool.can_forage(Season.winter, Region.beach), - ArtisanGood.oak_resin: self.has(Machine.tapper), - Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), - Machine.oil_maker: self.skill.has_farming_level(8) & self.has(Loot.slime) & self.has(Material.hardwood) & self.has(MetalBar.gold), - Craftable.oil_of_garlic: (self.skill.has_level(Skill.combat, 6) & self.has(Vegetable.garlic) & self.has(Ingredient.oil)) | (self.money.can_spend_at(Region.mines_dwarf_shop, 3000)), - Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_do_panning() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.buildings.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), - Animal.ostrich: self.buildings.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), - AnimalProduct.ostrich_egg: self.tool.can_forage(Generic.any, Region.island_north, True), - Machine.ostrich_incubator: self.received("Ostrich Incubator Recipe") & self.has(Fossil.bone_fragment) & self.has(Material.hardwood) & self.has(Material.cinder_shard), - Fish.oyster: self.tool.can_forage(Generic.any, Region.beach), - ArtisanGood.pale_ale: self.artisan.can_keg(Vegetable.hops), - Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), - Fish.periwinkle: self.skill.can_crab_pot(Region.town), - ArtisanGood.pickles: self.artisan.has_pickle(), - Animal.pig: self.can_buy_animal(Animal.pig), - Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600), - ArtisanGood.pine_tar: self.has(Machine.tapper), - Meal.pizza: self.money.can_spend_at(Region.saloon, 600), - Machine.preserves_jar: self.skill.has_farming_level(4) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.coal), Forageable.purple_mushroom: self.tool.can_forage(Generic.any, Region.mines_floor_95) | self.tool.can_forage(Generic.any, Region.skull_cavern_25), - Animal.rabbit: self.can_buy_animal(Animal.rabbit), - AnimalProduct.rabbit_foot: self.has_happy_animal(Animal.rabbit), - MetalBar.radioactive: self.can_smelt(Ore.radioactive), - Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), Forageable.rainbow_shell: self.tool.can_forage(Season.summer, Region.beach), - Craftable.rain_totem: self.skill.has_level(Skill.foraging, 9) & self.has(Material.hardwood) & self.has(ArtisanGood.truffle_oil) & self.has(ArtisanGood.pine_tar), - Machine.recycling_machine: self.skill.has_level(Skill.fishing, 4) & self.has(Material.wood) & self.has(Material.stone) & self.has(MetalBar.iron), Forageable.red_mushroom: self.tool.can_forage(Season.summer, Region.secret_woods) | self.tool.can_forage(Season.fall, Region.secret_woods), - MetalBar.quartz: self.can_smelt("Quartz") | self.can_smelt("Fire Quartz") | - (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), - Ingredient.rice: self.money.can_spend_at(Region.pierre_store, 200) | ( - self.buildings.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), - AnimalProduct.roe: self.skill.can_fish() & self.buildings.has_building(Building.fish_pond), - Meal.salad: self.money.can_spend_at(Region.saloon, 220), - # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.emily, 3) & self.has(Forageable.leek) & self.has(Forageable.dandelion) & - # self.has(Ingredient.vinegar)), Forageable.salmonberry: self.tool.can_forage(Season.spring), - Material.sap: self.ability.can_chop_trees(), - Craftable.scarecrow: self.skill.has_farming_level(1) & self.has(Material.wood) & self.has(Material.coal) & self.has(Material.fiber), - WaterItem.sea_urchin: self.tool.can_forage(Generic.any, Region.tide_pools), - WaterItem.seaweed: (self.skill.can_fish() & self.region.can_reach(Region.beach)) | self.region.can_reach( - Region.tide_pools), Forageable.secret_note: self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), - Machine.seed_maker: self.skill.has_farming_level(9) & self.has(Material.wood) & self.has(MetalBar.gold) & self.has( - Material.coal), - Animal.sheep: self.can_buy_animal(Animal.sheep), - Fish.shrimp: self.skill.can_crab_pot(Region.beach), - Loot.slime: self.mine.can_mine_in_the_mines_floor_1_40(), - Fish.snail: self.skill.can_crab_pot(Region.town), Forageable.snow_yam: self.tool.can_forage(Season.winter, Region.beach, True), - Trash.soggy_newspaper: self.skill.can_crab_pot(), - Loot.solar_essence: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), - Machine.solar_panel: self.received("Solar Panel Recipe") & self.has(MetalBar.quartz) & self.has( - MetalBar.iron) & self.has(MetalBar.gold), - Meal.spaghetti: self.money.can_spend_at(Region.saloon, 240), Forageable.spice_berry: self.tool.can_forage(Season.summer), Forageable.spring_onion: self.tool.can_forage(Season.spring), - AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.squid)), - Craftable.staircase: self.skill.has_level(Skill.mining, 2) & self.has(Material.stone), - Material.stone: self.tool.has_tool(Tool.pickaxe), - Meal.strange_bun: self.relationship.has_hearts(NPC.shane, 7) & self.has(Ingredient.wheat_flour) & self.has(Fish.periwinkle) & self.has(ArtisanGood.void_mayonnaise), - AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.buildings.has_building(Building.fish_pond), - Ingredient.sugar: self.money.can_spend_at(Region.pierre_store, 100) | ( - self.buildings.has_building(Building.mill) & self.has(Vegetable.beet)), Forageable.sweet_pea: self.tool.can_forage(Season.summer), - Machine.tapper: self.skill.has_level(Skill.foraging, 3) & self.has(Material.wood) & self.has(MetalBar.copper), - Vegetable.tea_leaves: self.has(Sapling.tea) & self.time.has_lived_months(2) & self.season.has_any_not_winter(), - Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), - Trash.trash: self.skill.can_crab_pot(), - Beverage.triple_shot_espresso: self.has("Hot Java Ring"), - ArtisanGood.truffle_oil: self.has(AnimalProduct.truffle) & self.has(Machine.oil_maker), - AnimalProduct.truffle: self.has_animal(Animal.pig) & self.season.has_any_not_winter(), - Ingredient.vinegar: self.money.can_spend_at(Region.pierre_store, 200), - AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), - Loot.void_essence: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern(), - ArtisanGood.void_mayonnaise: (self.region.can_reach(Region.witch_swamp) & self.skill.can_fish()) | (self.has(Machine.mayonnaise_machine) & self.has(AnimalProduct.void_egg)), - Ingredient.wheat_flour: self.money.can_spend_at(Region.pierre_store, 100) | - (self.buildings.has_building(Building.mill) & self.has(Vegetable.wheat)), - WaterItem.white_algae: self.skill.can_fish() & self.region.can_reach(Region.mines_floor_20), Forageable.wild_horseradish: self.tool.can_forage(Season.spring), Forageable.wild_plum: self.tool.can_forage(Season.fall), - Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), - ArtisanGood.wine: self.artisan.has_wine(), Forageable.winter_root: self.tool.can_forage(Season.winter, Region.forest, True), - Material.wood: self.tool.has_tool(Tool.axe), - AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), + Fossil.bone_fragment: self.region.can_reach(Region.dig_site), + Geode.artifact_trove: self.has(Geode.omni) & self.region.can_reach(Region.desert), + Geode.frozen: self.mine.can_mine_in_the_mines_floor_41_80(), + Geode.geode: self.mine.can_mine_in_the_mines_floor_1_40(), + Geode.golden_coconut: self.region.can_reach(Region.island_north), + Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.buildings.has_building(Building.fish_pond)), + Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_do_panning() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.buildings.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), + Gift.bouquet: self.relationship.has_hearts(Generic.bachelor, 8) & self.money.can_spend_at(Region.pierre_store, 100), + Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), + Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Craftable.rain_totem), + Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), + Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), + Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), + Ingredient.rice: self.money.can_spend_at(Region.pierre_store, 200) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), + Ingredient.sugar: self.money.can_spend_at(Region.pierre_store, 100) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.beet)), + Ingredient.vinegar: self.money.can_spend_at(Region.pierre_store, 200), + Ingredient.wheat_flour: self.money.can_spend_at(Region.pierre_store, 100) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.wheat)), + Loot.bat_wing: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), + Loot.bug_meat: self.mine.can_mine_in_the_mines_floor_1_40(), + Loot.slime: self.mine.can_mine_in_the_mines_floor_1_40(), + Loot.solar_essence: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), + Loot.void_essence: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern(), + Machine.bee_house: self.skill.has_farming_level(3) & self.has(MetalBar.iron) & self.has(ArtisanGood.maple_syrup) & self.has(Material.coal) & self.has(Material.wood), + Machine.cask: self.buildings.has_house(3) & self.region.can_reach(Region.cellar) & self.has(Material.wood) & self.has(Material.hardwood), + Machine.cheese_press: self.skill.has_farming_level(6) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.hardwood) & self.has(MetalBar.copper), + Machine.coffee_maker: self.received(Machine.coffee_maker), + Machine.crab_pot: self.skill.has_level(Skill.fishing, 3) & (self.money.can_spend_at(Region.fish_shop, 1500) | (self.has(MetalBar.iron) & self.has(Material.wood))), + Machine.furnace: self.has(Material.stone) & self.has(Ore.copper), + Machine.keg: self.skill.has_farming_level(8) & self.has(Material.wood) & self.has(MetalBar.iron) & self.has(MetalBar.copper) & self.has(ArtisanGood.oak_resin), + Machine.lightning_rod: self.skill.has_level(Skill.foraging, 6) & self.has(MetalBar.iron) & self.has(MetalBar.quartz) & self.has(Loot.bat_wing), + Machine.loom: self.skill.has_farming_level(7) & self.has(Material.wood) & self.has(Material.fiber) & self.has(ArtisanGood.pine_tar), + Machine.mayonnaise_machine: self.skill.has_farming_level(2) & self.has(Material.wood) & self.has(Material.stone) & self.has("Earth Crystal") & self.has(MetalBar.copper), + Machine.oil_maker: self.skill.has_farming_level(8) & self.has(Loot.slime) & self.has(Material.hardwood) & self.has(MetalBar.gold), + Machine.ostrich_incubator: self.received("Ostrich Incubator Recipe") & self.has(Fossil.bone_fragment) & self.has(Material.hardwood) & self.has(Material.cinder_shard), + Machine.preserves_jar: self.skill.has_farming_level(4) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.coal), + Machine.recycling_machine: self.skill.has_level(Skill.fishing, 4) & self.has(Material.wood) & self.has(Material.stone) & self.has(MetalBar.iron), + Machine.seed_maker: self.skill.has_farming_level(9) & self.has(Material.wood) & self.has(MetalBar.gold) & self.has(Material.coal), + Machine.solar_panel: self.received("Solar Panel Recipe") & self.has(MetalBar.quartz) & self.has(MetalBar.iron) & self.has(MetalBar.gold), + Machine.tapper: self.skill.has_level(Skill.foraging, 3) & self.has(Material.wood) & self.has(MetalBar.copper), Machine.worm_bin: self.skill.has_level(Skill.fishing, 8) & self.has(Material.hardwood) & self.has(MetalBar.gold) & self.has(MetalBar.iron) & self.has(Material.fiber), + Material.cinder_shard: self.region.can_reach(Region.volcano_floor_5), + Material.clay: self.region.can_reach_any([Region.farm, Region.beach, Region.quarry]) & self.tool.has_tool(Tool.hoe), + Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.action.can_do_panning(), + Material.fiber: True_(), + Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_west)), + Material.sap: self.ability.can_chop_trees(), + Material.stone: self.tool.has_tool(Tool.pickaxe), + Material.wood: self.tool.has_tool(Tool.axe), + Meal.bread: self.money.can_spend_at(Region.saloon, 120), + Meal.ice_cream: (self.season.has(Season.summer) & self.money.can_spend_at(Region.town, 250)) | self.money.can_spend_at(Region.oasis, 240), + Meal.pizza: self.money.can_spend_at(Region.saloon, 600), + Meal.salad: self.money.can_spend_at(Region.saloon, 220), + Meal.spaghetti: self.money.can_spend_at(Region.saloon, 240), + Meal.strange_bun: self.relationship.has_hearts(NPC.shane, 7) & self.has(Ingredient.wheat_flour) & self.has(Fish.periwinkle) & self.has(ArtisanGood.void_mayonnaise), + MetalBar.copper: self.can_smelt(Ore.copper), + MetalBar.gold: self.can_smelt(Ore.gold), + MetalBar.iridium: self.can_smelt(Ore.iridium), + MetalBar.iron: self.can_smelt(Ore.iron), + MetalBar.quartz: self.can_smelt("Quartz") | self.can_smelt("Fire Quartz") | (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), + MetalBar.radioactive: self.can_smelt(Ore.radioactive), + Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + Ore.iridium: self.mine.can_mine_in_the_skull_cavern(), + Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), + Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), + Trash.broken_cd: self.skill.can_crab_pot(), + Trash.broken_glasses: self.skill.can_crab_pot(), + Trash.driftwood: self.skill.can_crab_pot(), + Trash.joja_cola: self.money.can_spend_at(Region.saloon, 75), + Trash.soggy_newspaper: self.skill.can_crab_pot(), + Trash.trash: self.skill.can_crab_pot(), + Vegetable.tea_leaves: self.has(Sapling.tea) & self.time.has_lived_months(2) & self.season.has_any_not_winter(), + WaterItem.clam: self.tool.can_forage(Generic.any, Region.beach), + WaterItem.cockle: self.tool.can_forage(Generic.any, Region.beach), + WaterItem.coral: self.tool.can_forage(Generic.any, Region.tide_pools) | self.tool.can_forage(Season.summer, Region.beach), + WaterItem.green_algae: self.fishing.can_fish_in_freshwater(), + WaterItem.nautilus_shell: self.tool.can_forage(Season.winter, Region.beach), + WaterItem.sea_urchin: self.tool.can_forage(Generic.any, Region.tide_pools), + WaterItem.seaweed: self.skill.can_fish(Region.beach) | self.region.can_reach(Region.tide_pools), + WaterItem.white_algae: self.skill.can_fish(Region.mines_floor_20), }) self.item_rules.update(self.fish_rules) self.item_rules.update(self.museum_rules) @@ -511,7 +505,7 @@ def can_complete_quest(self, quest: str) -> StardewRule: return Has(quest, self.quest_rules) def can_buy_seed(self, seed: SeedItem) -> StardewRule: - if self.options[options.Cropsanity] == options.Cropsanity.option_disabled: + if self.options[options.Cropsanity] == options.Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() else: item_rule = self.received(seed.name) @@ -542,13 +536,16 @@ def can_buy_sapling(self, fruit: str) -> StardewRule: return allowed_buy_sapling & can_buy_sapling def can_catch_fish(self, fish: FishItem) -> StardewRule: + quest_rule = True_() + if fish.extended_family: + quest_rule = self.can_start_extended_family_quest() region_rule = self.region.can_reach_any(fish.locations) season_rule = self.season.has_any(fish.seasons) if fish.difficulty == -1: difficulty_rule = self.skill.can_crab_pot() else: - difficulty_rule = self.skill.can_fish(fish.difficulty) - return region_rule & season_rule & difficulty_rule + difficulty_rule = self.skill.can_fish([], 120 if fish.legendary else fish.difficulty) + return quest_rule & region_rule & season_rule & difficulty_rule def can_catch_every_fish(self) -> StardewRule: rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] @@ -559,6 +556,13 @@ def can_catch_every_fish(self) -> StardewRule: rules.append(self.can_catch_fish(fish)) return And(rules) + def can_start_extended_family_quest(self) -> StardewRule: + if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + return False_() + if self.options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_board_qi: + return False_() + return self.region.can_reach(Region.qi_walnut_room) & And([self.can_catch_fish(fish) for fish in legendary_fish]) + def can_smelt(self, item: str) -> StardewRule: return self.has(Machine.furnace) & self.has(item) @@ -687,7 +691,7 @@ def can_succeed_grange_display(self) -> StardewRule: animal_rule = self.has_animal(Generic.any) artisan_rule = self.artisan.can_keg(Generic.any) | self.artisan.can_preserves_jar(Generic.any) cooking_rule = True_() # Salads at the bar are good enough - fish_rule = self.skill.can_fish(50) + fish_rule = self.skill.can_fish([], 50) forage_rule = True_() # Hazelnut always available since the grange display is in fall mineral_rule = self.action.can_open_geode(Generic.any) # More than half the minerals are good enough good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, @@ -702,7 +706,7 @@ def can_succeed_grange_display(self) -> StardewRule: forage_rule & fruit_rule & mineral_rule & vegetable_rule def can_win_fishing_competition(self) -> StardewRule: - return self.skill.can_fish(60) + return self.skill.can_fish([], 60) def can_buy_animal(self, animal: str) -> StardewRule: price = 0 diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index fc1b872d2869..8613b66588e9 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -1,4 +1,4 @@ -from typing import Iterable +from typing import Iterable, List, Union from .combat_logic import CombatLogic from .crop_logic import CropLogic @@ -141,13 +141,17 @@ def can_get_fishing_xp(self) -> StardewRule: return self.can_fish() - def can_fish(self, difficulty: int = 0) -> StardewRule: - skill_required = max(0, int((difficulty / 10) - 1)) + def can_fish(self, regions: Union[str, List[str]] = None, difficulty: int = 0) -> StardewRule: + if isinstance(regions, str): + regions = [regions] + if regions is None or len(regions) == 0: + regions = fishing_regions + skill_required = min(10, max(0, int((difficulty / 10) - 1))) if difficulty <= 40: skill_required = 0 skill_rule = self.has_level(Skill.fishing, skill_required) - region_rule = self.region.can_reach_any(fishing_regions) - number_fishing_rod_required = 1 if difficulty < 50 else 2 + region_rule = self.region.can_reach_any(regions) + number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule def can_crab_pot(self, region: str = Generic.any) -> StardewRule: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 062f2df1f51d..d5a551d977cb 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -824,7 +824,7 @@ def set_magic_spell_rules(logic: StardewLogic, multi_world: MultiWorld, player: & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & logic.has("Coffee") & logic.has("Life Elixir") & logic.ability.can_mine_perfectly() & logic.has("Earth Crystal") & - logic.has("Fire Quartz") & logic.skill.can_fish(85) & + logic.has("Fire Quartz") & logic.skill.can_fish([], 85) & logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()) diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 8ee778103752..1b47756210d6 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -1,41 +1,47 @@ class Fish: + albacore = "Albacore" angler = "Angler" any = "Any Fish" blobfish = "Blobfish" blue_discus = "Blue Discus" bream = "Bream" + carp = "Carp" catfish = "Catfish" crab = "Crab" crayfish = "Crayfish" crimsonfish = "Crimsonfish" dorado = "Dorado" + eel = "Eel" glacierfish = "Glacierfish" + glacierfish_jr = "Glacierfish Jr." + largemouth_bass = "Largemouth Bass" lava_eel = "Lava Eel" legend = "Legend" + legend_ii = "Legend II" lionfish = "Lionfish" lobster = "Lobster" + ms_angler = "Ms. Angler" mussel = "Mussel" mussel_node = "Mussel Node" mutant_carp = "Mutant Carp" octopus = "Octopus" oyster = "Oyster" + periwinkle = "Periwinkle" pufferfish = "Pufferfish" + radioactive_carp = "Radioactive Carp" + salmon = "Salmon" + sardine = "Sardine" + shrimp = "Shrimp" + smallmouth_bass = "Smallmouth Bass" + snail = "Snail" + son_of_crimsonfish = "Son of Crimsonfish" spookfish = "Spook Fish" squid = "Squid" stingray = "Stingray" sturgeon = "Sturgeon" sunfish = "Sunfish" - void_salmon = "Void Salmon" - albacore = "Albacore" - largemouth_bass = "Largemouth Bass" - smallmouth_bass = "Smallmouth Bass" - sardine = "Sardine" - periwinkle = "Periwinkle" - shrimp = "Shrimp" - snail = "Snail" tuna = "Tuna" - eel = "Eel" - salmon = "Salmon" + void_salmon = "Void Salmon" class WaterItem: diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index 55e3ef0a7bd3..670751e703f4 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -1,31 +1,20 @@ class Meal: - blueberry_tart = "Blueberry Tart" - bread = "Bread" - fiddlehead_risotto = "Fiddlehead Risotto" - complete_breakfast = "Complete Breakfast" - fried_egg = "Fried Egg" - hashbrowns = "Hashbrowns" - pancakes = "Pancakes" - ice_cream = "Ice Cream" - maki_roll = "Maki Roll" - miners_treat = "Miner's Treat" - omelet = "Omelet" - parsnip_soup = "Parsnip Soup" - pink_cake = "Pink Cake" - pizza = "Pizza" - pumpkin_pie = "Pumpkin Pie" - roasted_hazelnuts = "Roasted Hazelnuts" - salad = "Salad" - spaghetti = "Spaghetti" - tortilla = "Tortilla" algae_soup = "Algae Soup" artichoke_dip = "Artichoke Dip" + autumn_bounty = "Autumn's Bounty" baked_fish = "Baked Fish" bean_hotpot = "Bean Hotpot" blackberry_cobbler = "Blackberry Cobbler" + blueberry_tart = "Blueberry Tart" + bread = "Bread" + bruschetta = "Bruschetta" + carp_surprise = "Carp Surprise" cheese_cauliflower = "Cheese Cauliflower" chocolate_cake = "Chocolate Cake" chowder = "Chowder" + coleslaw = "Coleslaw" + complete_breakfast = "Complete Breakfast" + cookie = "Cookie" crab_cakes = "Crab Cakes" cranberry_candy = "Cranberry Candy" crispy_bass = "Crispy Bass" @@ -33,27 +22,43 @@ class Meal: eggplant_parmesan = "Eggplant Parmesan" escargot = "Escargot" farmer_lunch = "Farmer's Lunch" + fiddlehead_risotto = "Fiddlehead Risotto" fish_taco = "Fish Taco" fried_calamari = "Fried Calamari" fried_eel = "Fried Eel" + fried_egg = "Fried Egg" fried_mushroom = "Fried Mushroom" fruit_salad = "Fruit Salad" glazed_yams = "Glazed Yams" + hashbrowns = "Hashbrowns" + ice_cream = "Ice Cream" + maki_roll = "Maki Roll" maple_bar = "Maple Bar" + miners_treat = "Miner's Treat" + omelet = "Omelet" pale_broth = "Pale Broth" + pancakes = "Pancakes" + parsnip_soup = "Parsnip Soup" pepper_poppers = "Pepper Poppers" + pink_cake = "Pink Cake" + pizza = "Pizza" plum_pudding = "Plum Pudding" poppyseed_muffin = "Poppyseed Muffin" + pumpkin_pie = "Pumpkin Pie" red_plate = "Red Plate" rhubarb_pie = "Rhubarb Pie" rice_pudding = "Rice Pudding" + roasted_hazelnuts = "Roasted Hazelnuts" roots_platter = "Roots Platter" + salad = "Salad" salmon_dinner = "Salmon Dinner" sashimi = "Sashimi" + spaghetti = "Spaghetti" stir_fry = "Stir Fry" strange_bun = "Strange Bun" stuffing = "Stuffing" survival_burger = "Survival Burger" + tortilla = "Tortilla" tropical_curry = "Tropical Curry" vegetable_medley = "Vegetable Medley" diff --git a/worlds/stardew_valley/strings/seed_names.py b/worlds/stardew_valley/strings/seed_names.py index 080bdf854006..6d8fe3f3defb 100644 --- a/worlds/stardew_valley/strings/seed_names.py +++ b/worlds/stardew_valley/strings/seed_names.py @@ -7,3 +7,4 @@ class Seed: pineapple = "Pineapple Seeds" taro = "Taro Tuber" coffee = "Coffee Bean" + qi_bean = "Qi Bean" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 417032062046..85934e6998e0 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -604,3 +604,343 @@ def check_locations_are_valid(self): self.assertTrue(hearts == 5 or hearts == 10 or hearts == 14) else: self.assertTrue(hearts == 5 or hearts == 10) + + +class TestShipsanityNone(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_none + } + + def test_no_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event: + with self.subTest(location.name): + self.assertFalse("Shipsanity" in location.name) + self.assertNotIn(LocationTags.SHIPSANITY, location_table[location.name].tags) + + +class TestShipsanityCrops(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_crops, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + } + + def test_only_crop_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_CROP, location_table[location.name].tags) + + def test_include_island_crop_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Banana", location_names) + self.assertIn("Shipsanity: Mango", location_names) + self.assertIn("Shipsanity: Pineapple", location_names) + self.assertIn("Shipsanity: Taro Root", location_names) + self.assertIn("Shipsanity: Ginger", location_names) + self.assertIn("Shipsanity: Magma Cap", location_names) + self.assertIn("Shipsanity: Qi Fruit", location_names) + + +class TestShipsanityCropsExcludeIsland(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_crops, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + } + + def test_only_crop_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_CROP, location_table[location.name].tags) + + def test_only_mainland_crop_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertNotIn("Shipsanity: Banana", location_names) + self.assertNotIn("Shipsanity: Mango", location_names) + self.assertNotIn("Shipsanity: Pineapple", location_names) + self.assertNotIn("Shipsanity: Taro Root", location_names) + self.assertNotIn("Shipsanity: Ginger", location_names) + self.assertNotIn("Shipsanity: Magma Cap", location_names) + self.assertNotIn("Shipsanity: Qi Fruit", location_names) + + +class TestShipsanityCropsNoQiCropWithoutSpecialOrders(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_crops, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_only + } + + def test_only_crop_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_CROP, location_table[location.name].tags) + + def test_island_crops_without_qi_fruit_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Banana", location_names) + self.assertIn("Shipsanity: Mango", location_names) + self.assertIn("Shipsanity: Pineapple", location_names) + self.assertIn("Shipsanity: Taro Root", location_names) + self.assertIn("Shipsanity: Ginger", location_names) + self.assertIn("Shipsanity: Magma Cap", location_names) + self.assertNotIn("Shipsanity: Qi Fruit", location_names) + + +class TestShipsanityFish(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_fish, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + } + + def test_only_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + def test_include_island_fish_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Blue Discus", location_names) + self.assertIn("Shipsanity: Lionfish", location_names) + self.assertIn("Shipsanity: Stingray", location_names) + self.assertIn("Shipsanity: Glacierfish Jr.", location_names) + self.assertIn("Shipsanity: Legend II", location_names) + self.assertIn("Shipsanity: Ms. Angler", location_names) + self.assertIn("Shipsanity: Radioactive Carp", location_names) + self.assertIn("Shipsanity: Son of Crimsonfish", location_names) + + +class TestShipsanityFishExcludeIsland(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_fish, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + } + + def test_only_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + def test_exclude_island_fish_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertNotIn("Shipsanity: Blue Discus", location_names) + self.assertNotIn("Shipsanity: Lionfish", location_names) + self.assertNotIn("Shipsanity: Stingray", location_names) + self.assertNotIn("Shipsanity: Glacierfish Jr.", location_names) + self.assertNotIn("Shipsanity: Legend II", location_names) + self.assertNotIn("Shipsanity: Ms. Angler", location_names) + self.assertNotIn("Shipsanity: Radioactive Carp", location_names) + self.assertNotIn("Shipsanity: Son of Crimsonfish", location_names) + + +class TestShipsanityFishExcludeQiOrders(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_fish, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_only + } + + def test_only_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + def test_include_island_fish_no_extended_family_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Blue Discus", location_names) + self.assertIn("Shipsanity: Lionfish", location_names) + self.assertIn("Shipsanity: Stingray", location_names) + self.assertNotIn("Shipsanity: Glacierfish Jr.", location_names) + self.assertNotIn("Shipsanity: Legend II", location_names) + self.assertNotIn("Shipsanity: Ms. Angler", location_names) + self.assertNotIn("Shipsanity: Radioactive Carp", location_names) + self.assertNotIn("Shipsanity: Son of Crimsonfish", location_names) + + +class TestShipsanityFullShipment(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + } + + def test_only_full_shipment_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_FULL_SHIPMENT, location_table[location.name].tags) + self.assertNotIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + def test_include_island_items_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Cinder Shard", location_names) + self.assertIn("Shipsanity: Bone Fragment", location_names) + self.assertIn("Shipsanity: Radioactive Ore", location_names) + self.assertIn("Shipsanity: Radioactive Bar", location_names) + self.assertIn("Shipsanity: Banana", location_names) + self.assertIn("Shipsanity: Mango", location_names) + self.assertIn("Shipsanity: Pineapple", location_names) + self.assertIn("Shipsanity: Taro Root", location_names) + self.assertIn("Shipsanity: Ginger", location_names) + self.assertIn("Shipsanity: Magma Cap", location_names) + + +class TestShipsanityFullShipmentExcludeIsland(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + } + + def test_only_full_shipment_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_FULL_SHIPMENT, location_table[location.name].tags) + self.assertNotIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + def test_exclude_island_items_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertNotIn("Shipsanity: Cinder Shard", location_names) + self.assertNotIn("Shipsanity: Bone Fragment", location_names) + self.assertNotIn("Shipsanity: Radioactive Ore", location_names) + self.assertNotIn("Shipsanity: Radioactive Bar", location_names) + self.assertNotIn("Shipsanity: Banana", location_names) + self.assertNotIn("Shipsanity: Mango", location_names) + self.assertNotIn("Shipsanity: Pineapple", location_names) + self.assertNotIn("Shipsanity: Taro Root", location_names) + self.assertNotIn("Shipsanity: Ginger", location_names) + self.assertNotIn("Shipsanity: Magma Cap", location_names) + + +class TestShipsanityFullShipmentExcludeQiBoard(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_disabled + } + + def test_only_full_shipment_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertIn(LocationTags.SHIPSANITY_FULL_SHIPMENT, location_table[location.name].tags) + self.assertNotIn(LocationTags.SHIPSANITY_FISH, location_table[location.name].tags) + + def test_exclude_qi_board_items_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Cinder Shard", location_names) + self.assertIn("Shipsanity: Bone Fragment", location_names) + self.assertNotIn("Shipsanity: Radioactive Ore", location_names) + self.assertNotIn("Shipsanity: Radioactive Bar", location_names) + self.assertIn("Shipsanity: Banana", location_names) + self.assertIn("Shipsanity: Mango", location_names) + self.assertIn("Shipsanity: Pineapple", location_names) + self.assertIn("Shipsanity: Taro Root", location_names) + self.assertIn("Shipsanity: Ginger", location_names) + self.assertIn("Shipsanity: Magma Cap", location_names) + + +class TestShipsanityFullShipmentWithFish(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + } + + def test_only_full_shipment_and_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertTrue(LocationTags.SHIPSANITY_FULL_SHIPMENT in location_table[location.name].tags or + LocationTags.SHIPSANITY_FISH in location_table[location.name].tags) + + def test_include_island_items_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Cinder Shard", location_names) + self.assertIn("Shipsanity: Bone Fragment", location_names) + self.assertIn("Shipsanity: Radioactive Ore", location_names) + self.assertIn("Shipsanity: Radioactive Bar", location_names) + self.assertIn("Shipsanity: Banana", location_names) + self.assertIn("Shipsanity: Mango", location_names) + self.assertIn("Shipsanity: Pineapple", location_names) + self.assertIn("Shipsanity: Taro Root", location_names) + self.assertIn("Shipsanity: Ginger", location_names) + self.assertIn("Shipsanity: Magma Cap", location_names) + self.assertIn("Shipsanity: Blue Discus", location_names) + self.assertIn("Shipsanity: Lionfish", location_names) + self.assertIn("Shipsanity: Stingray", location_names) + self.assertIn("Shipsanity: Glacierfish Jr.", location_names) + self.assertIn("Shipsanity: Legend II", location_names) + self.assertIn("Shipsanity: Ms. Angler", location_names) + self.assertIn("Shipsanity: Radioactive Carp", location_names) + self.assertIn("Shipsanity: Son of Crimsonfish", location_names) + + +class TestShipsanityFullShipmentWithFishExcludeIsland(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + } + + def test_only_full_shipment_and_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertTrue(LocationTags.SHIPSANITY_FULL_SHIPMENT in location_table[location.name].tags or + LocationTags.SHIPSANITY_FISH in location_table[location.name].tags) + + def test_exclude_island_items_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertNotIn("Shipsanity: Cinder Shard", location_names) + self.assertNotIn("Shipsanity: Bone Fragment", location_names) + self.assertNotIn("Shipsanity: Radioactive Ore", location_names) + self.assertNotIn("Shipsanity: Radioactive Bar", location_names) + self.assertNotIn("Shipsanity: Banana", location_names) + self.assertNotIn("Shipsanity: Mango", location_names) + self.assertNotIn("Shipsanity: Pineapple", location_names) + self.assertNotIn("Shipsanity: Taro Root", location_names) + self.assertNotIn("Shipsanity: Ginger", location_names) + self.assertNotIn("Shipsanity: Magma Cap", location_names) + self.assertNotIn("Shipsanity: Blue Discus", location_names) + self.assertNotIn("Shipsanity: Lionfish", location_names) + self.assertNotIn("Shipsanity: Stingray", location_names) + self.assertNotIn("Shipsanity: Glacierfish Jr.", location_names) + self.assertNotIn("Shipsanity: Legend II", location_names) + self.assertNotIn("Shipsanity: Ms. Angler", location_names) + self.assertNotIn("Shipsanity: Radioactive Carp", location_names) + self.assertNotIn("Shipsanity: Son of Crimsonfish", location_names) + + +class TestShipsanityFullShipmentWithFishExcludeQiBoard(SVTestBase): + options = { + options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_only + } + + def test_only_full_shipment_and_fish_shipsanity_locations(self): + for location in self.multiworld.get_locations(self.player): + if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags: + with self.subTest(location.name): + self.assertTrue(LocationTags.SHIPSANITY_FULL_SHIPMENT in location_table[location.name].tags or + LocationTags.SHIPSANITY_FISH in location_table[location.name].tags) + + def test_exclude_qi_board_items_shipsanity_locations(self): + location_names = [location.name for location in self.multiworld.get_locations(self.player)] + self.assertIn("Shipsanity: Cinder Shard", location_names) + self.assertIn("Shipsanity: Bone Fragment", location_names) + self.assertNotIn("Shipsanity: Radioactive Ore", location_names) + self.assertNotIn("Shipsanity: Radioactive Bar", location_names) + self.assertIn("Shipsanity: Banana", location_names) + self.assertIn("Shipsanity: Mango", location_names) + self.assertIn("Shipsanity: Pineapple", location_names) + self.assertIn("Shipsanity: Taro Root", location_names) + self.assertIn("Shipsanity: Ginger", location_names) + self.assertIn("Shipsanity: Magma Cap", location_names) + self.assertIn("Shipsanity: Blue Discus", location_names) + self.assertIn("Shipsanity: Lionfish", location_names) + self.assertIn("Shipsanity: Stingray", location_names) + self.assertNotIn("Shipsanity: Glacierfish Jr.", location_names) + self.assertNotIn("Shipsanity: Legend II", location_names) + self.assertNotIn("Shipsanity: Ms. Angler", location_names) + self.assertNotIn("Shipsanity: Radioactive Carp", location_names) + self.assertNotIn("Shipsanity: Son of Crimsonfish", location_names) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 31379202f8fb..01ed2481d386 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -595,14 +595,15 @@ class TestShipsanityEverything(SVTestBase): } def test_all_shipsanity_locations_require_shipping_bin(self): - bin_item = "Shipping Bin" - collect_all_except(self.multiworld, bin_item) + bin_name = "Shipping Bin" + collect_all_except(self.multiworld, bin_name) shipsanity_locations = [location for location in self.multiworld.get_locations() if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags] - + bin_item = self.world.create_item(bin_name) for location in shipsanity_locations: - self.assertFalse(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) - - self.multiworld.state.collect(self.world.create_item(bin_item), event=False) + 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) + self.assertTrue(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) + self.remove(bin_item) - for location in shipsanity_locations: - self.assertTrue(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) From 97e9a22cbacae2c8af401ba5cf4f680dede30951 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 21 Aug 2023 17:25:39 -0400 Subject: [PATCH 050/482] - Shipsanity new logic, all craftable rules, more cooking rules, etc etc --- worlds/stardew_valley/__init__.py | 4 +- worlds/stardew_valley/data/craftable_data.py | 241 ++++++++++++++++++ worlds/stardew_valley/data/fish_data.py | 2 +- worlds/stardew_valley/data/items.csv | 33 ++- worlds/stardew_valley/data/locations.csv | 12 +- worlds/stardew_valley/data/recipe_data.py | 106 +++----- worlds/stardew_valley/data/recipe_source.py | 108 ++++++++ worlds/stardew_valley/data/villagers_data.py | 4 +- worlds/stardew_valley/items.py | 22 +- worlds/stardew_valley/logic/action_logic.py | 7 +- worlds/stardew_valley/logic/cooking_logic.py | 17 +- worlds/stardew_valley/logic/crafting_logic.py | 66 +++++ worlds/stardew_valley/logic/fishing_logic.py | 3 + worlds/stardew_valley/logic/logic.py | 115 ++++++--- worlds/stardew_valley/logic/money_logic.py | 22 +- worlds/stardew_valley/logic/museum_logic.py | 2 +- worlds/stardew_valley/logic/skill_logic.py | 4 +- .../mods/logic/deepwoods_logic.py | 4 +- .../stardew_valley/mods/logic/skills_logic.py | 4 +- .../mods/logic/special_orders_logic.py | 6 +- worlds/stardew_valley/rules.py | 4 +- .../strings/animal_product_names.py | 34 ++- .../stardew_valley/strings/craftable_names.py | 137 +++++++++- worlds/stardew_valley/strings/crop_names.py | 1 + .../stardew_valley/strings/currency_names.py | 8 + .../strings/decoration_names.py | 2 + worlds/stardew_valley/strings/fish_names.py | 9 + worlds/stardew_valley/strings/flower_names.py | 2 + worlds/stardew_valley/strings/food_names.py | 18 +- worlds/stardew_valley/strings/gift_names.py | 6 +- .../strings/ingredient_names.py | 1 + .../stardew_valley/strings/machine_names.py | 13 +- worlds/stardew_valley/strings/metal_names.py | 20 +- worlds/stardew_valley/strings/seed_names.py | 25 +- worlds/stardew_valley/test/TestGeneration.py | 4 +- worlds/stardew_valley/test/TestLogic.py | 7 +- worlds/stardew_valley/test/TestRules.py | 4 +- worlds/stardew_valley/test/mods/TestMods.py | 18 +- 38 files changed, 888 insertions(+), 207 deletions(-) create mode 100644 worlds/stardew_valley/data/craftable_data.py create mode 100644 worlds/stardew_valley/data/recipe_source.py create mode 100644 worlds/stardew_valley/logic/crafting_logic.py create mode 100644 worlds/stardew_valley/strings/currency_names.py create mode 100644 worlds/stardew_valley/strings/decoration_names.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index cecc6ee64fd4..6532eb2f2898 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -215,7 +215,7 @@ def setup_victory(self): self.logic.can_complete_all_monster_slaying_goals().simplify(), "Victory") elif self.options[options.Goal] == options.Goal.option_full_shipment: - self.create_event_location(location_table[Goal.option_full_shipment], + self.create_event_location(location_table[Goal.full_shipment], self.logic.can_ship_everything().simplify(), "Victory") elif self.options[options.Goal] == options.Goal.option_perfection: @@ -260,6 +260,8 @@ def force_first_month_once_all_early_items_are_found(self): This patches the issue, by adding a dependency to the first month end on all early items, so all the locations that depends on it will not be considered early. This requires at least one early item to be progression, or it just won't work... + + We do this for all early items, not just ours, to avoid them getting stuck behind late stardew months and not feeling early at all """ early_items = [] diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py new file mode 100644 index 000000000000..5b1471890d31 --- /dev/null +++ b/worlds/stardew_valley/data/craftable_data.py @@ -0,0 +1,241 @@ +from typing import Dict, List + +from .recipe_source import RecipeSource, StarterSource, QueenOfSauceSource, ShopSource, SkillSource, FriendshipSource, ShopTradeSource, CutsceneSource, \ + ArchipelagoSource, LogicSource +from ..strings.artisan_good_names import ArtisanGood +from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, Fishing, Ring, Consumable, Edible, Lighting, Storage, Furniture, Sign, Craftable +from ..strings.crop_names import Fruit, Vegetable +from ..strings.currency_names import Currency +from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro +from ..strings.fish_names import Fish, WaterItem +from ..strings.flower_names import Flower +from ..strings.forageable_names import Forageable +from ..strings.ingredient_names import Ingredient +from ..strings.machine_names import Machine +from ..strings.material_names import Material +from ..strings.metal_names import Ore, MetalBar, Fossil, Artifact, Mineral +from ..strings.monster_drop_names import Loot +from ..strings.region_names import Region +from ..strings.seed_names import Seed, TreeSeed +from ..strings.skill_names import Skill +from ..strings.villager_names import NPC + + +class CraftingRecipe: + item: str + ingredients: Dict[str, int] + source: RecipeSource + + def __init__(self, item: str, ingredients: Dict[str, int], source: RecipeSource): + self.item = item + self.ingredients = ingredients + self.source = source + + def __repr__(self): + return f"{self.item} (Source: {self.source} |" \ + f" Ingredients: {self.ingredients})" + + +all_crafting_recipes: List[CraftingRecipe] = [] + + +def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = FriendshipSource(friend, hearts) + return create_recipe(name, ingredients, source) + + +def cutscene_recipe(name: str, region: str, friend: str, hearts: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = CutsceneSource(region, friend, hearts) + return create_recipe(name, ingredients, source) + + +def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = SkillSource(skill, level) + return create_recipe(name, ingredients, source) + + +def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = ShopSource(region, price) + return create_recipe(name, ingredients, source) + + +def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = ShopTradeSource(region, currency, price) + return create_recipe(name, ingredients, source) + + +def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = QueenOfSauceSource(year, season, day) + return create_recipe(name, ingredients, source) + + +def starter_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe: + source = StarterSource() + return create_recipe(name, ingredients, source) + + +def ap_recipe(name: str, ingredients: Dict[str, int], ap_item: str = None) -> CraftingRecipe: + if ap_item is None: + ap_item = f"{name} Recipe" + source = ArchipelagoSource(ap_item) + return create_recipe(name, ingredients, source) + + +def cellar_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe: + source = LogicSource("Cellar") + return create_recipe(name, ingredients, source) + + +def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) -> CraftingRecipe: + recipe = CraftingRecipe(name, ingredients, source) + all_crafting_recipes.append(recipe) + return recipe + + +cherry_bomb = skill_recipe(Bomb.cherry_bomb, Skill.mining, 1, {Ore.copper: 4, Material.coal: 1}) +bomb = skill_recipe(Bomb.bomb, Skill.mining, 6, {Ore.iron: 4, Material.coal: 1}) +mega_bomb = skill_recipe(Bomb.mega_bomb, Skill.mining, 8, {Ore.gold: 4, Loot.solar_essence: 1, Loot.void_essence: 1}) + +gate = starter_recipe(Fence.gate, {Material.wood: 10}) +wood_fence = starter_recipe(Fence.wood, {Material.wood: 2}) +stone_fence = skill_recipe(Fence.stone, Skill.farming, 2, {Material.stone: 2}) +iron_fence = skill_recipe(Fence.iron, Skill.farming, 4, {MetalBar.iron: 2}) +hardwood_fence = skill_recipe(Fence.hardwood, Skill.farming, 6, {Material.hardwood: 2}) + +sprinkler = skill_recipe(Sprinkler.basic, Skill.farming, 2, {MetalBar.copper: 1, MetalBar.iron: 1}) +quality_sprinkler = skill_recipe(Sprinkler.quality, Skill.farming, 6, {MetalBar.iron: 1, MetalBar.gold: 1, MetalBar.quartz: 1}) +iridium_sprinkler = skill_recipe(Sprinkler.iridium, Skill.farming, 9, {MetalBar.gold: 1, MetalBar.iridium: 1, ArtisanGood.battery_pack: 1}) + +bee_house = skill_recipe(Machine.bee_house, Skill.farming, 3, {Material.wood: 40, Material.coal: 8, MetalBar.iron: 1, ArtisanGood.maple_syrup: 1}) +cask = cellar_recipe(Machine.cask, {Material.wood: 40, Material.hardwood: 1}) +cheese_press = skill_recipe(Machine.cheese_press, Skill.farming, 6, {Material.wood: 45, Material.stone: 45, Material.hardwood: 10, MetalBar.copper: 1}) +keg = skill_recipe(Machine.keg, Skill.farming, 8, {Material.wood: 30, MetalBar.copper: 1, MetalBar.iron: 1, ArtisanGood.oak_resin: 1}) +loom = skill_recipe(Machine.loom, Skill.farming, 7, {Material.wood: 60, Material.fiber: 30, ArtisanGood.pine_tar: 1}) +mayonnaise_machine = skill_recipe(Machine.mayonnaise_machine, Skill.farming, 2, {Material.wood: 15, Material.stone: 15, Mineral.earth_crystal: 10, MetalBar.copper: 1}) +oil_maker = skill_recipe(Machine.oil_maker, Skill.farming, 8, {Loot.slime: 50, Material.hardwood: 20, MetalBar.gold: 1}) +preserves_jar = skill_recipe(Machine.preserves_jar, Skill.farming, 4, {Material.wood: 50, Material.stone: 40, Material.coal: 8}) + +basic_fertilizer = skill_recipe(Fertilizer.basic, Skill.farming, 1, {Material.sap: 2}) +quality_fertilizer = skill_recipe(Fertilizer.quality, Skill.farming, 9, {Material.sap: 2, Fish.any: 1}) +deluxe_fertilizer = ap_recipe(Fertilizer.deluxe, {MetalBar.iridium: 1, Material.sap: 40}) +basic_speed_gro = skill_recipe(SpeedGro.basic, Skill.farming, 3, {ArtisanGood.pine_tar: 1, WaterItem.clam: 1}) +deluxe_speed_gro = skill_recipe(SpeedGro.deluxe, Skill.farming, 8, {ArtisanGood.oak_resin: 1, WaterItem.coral: 1}) +hyper_speed_gro = ap_recipe(SpeedGro.hyper, {Ore.radioactive: 1, Fossil.bone_fragment: 3, Loot.solar_essence: 1}) +basic_retaining_soil = skill_recipe(RetainingSoil.basic, Skill.farming, 4, {Material.stone: 2}) +quality_retaining_soil = skill_recipe(RetainingSoil.quality, Skill.farming, 7, {Material.stone: 3, Material.clay: 1}) +deluxe_retaining_soil = shop_trade_recipe(RetainingSoil.deluxe, Region.island_trader, Currency.cinder_shard, 50, {Material.stone: 5, Material.fiber: 3, Material.clay: 1}) +tree_fertilizer = skill_recipe(Fertilizer.tree, Skill.foraging, 7, {Material.fiber: 5, Material.stone: 5}) + +spring_seeds = skill_recipe(WildSeeds.spring, Skill.foraging, 1, {Forageable.wild_horseradish: 1, Forageable.daffodil: 1, Forageable.leek: 1, Forageable.dandelion: 1}) +summer_seeds = skill_recipe(WildSeeds.summer, Skill.foraging, 4, {Forageable.spice_berry: 1, Fruit.grape: 1, Forageable.sweet_pea: 1}) +fall_seeds = skill_recipe(WildSeeds.fall, Skill.foraging, 6, {Forageable.common_mushroom: 1, Forageable.wild_plum: 1, Forageable.hazelnut: 1, Forageable.blackberry: 1}) +winter_seeds = skill_recipe(WildSeeds.winter, Skill.foraging, 7, {Forageable.winter_root: 1, Forageable.crystal_fruit: 1, Forageable.snow_yam: 1, Forageable.crocus: 1}) +ancient_seeds = ap_recipe(WildSeeds.ancient, {Artifact.ancient_seed: 1}) +grass_starter = shop_recipe(WildSeeds.grass_starter, Region.pierre_store, 1000, {Material.fiber: 10}) +for wild_seeds in [WildSeeds.spring, WildSeeds.summer, WildSeeds.fall, WildSeeds.winter]: + tea_sapling = cutscene_recipe(WildSeeds.tea_sapling, Region.sunroom, NPC.caroline, 2, {wild_seeds: 2, Material.fiber: 5, Material.wood: 5}) +fiber_seeds = ap_recipe(WildSeeds.fiber, {Seed.mixed: 1, Material.sap: 5, Material.clay: 1}) + +wood_floor = shop_recipe(Floor.wood, Region.carpenter, 100, {Material.wood: 1}) +rustic_floor = shop_recipe(Floor.rustic, Region.carpenter, 200, {Material.wood: 1}) +straw_floor = shop_recipe(Floor.straw, Region.carpenter, 200, {Material.wood: 1, Material.fiber: 1}) +weathered_floor = shop_recipe(Floor.weathered, Region.mines_dwarf_shop, 500, {Material.wood: 1}) +crystal_floor = shop_recipe(Floor.crystal, Region.sewer, 500, {MetalBar.quartz: 1}) +stone_floor = shop_recipe(Floor.stone, Region.carpenter, 100, {Material.stone: 1}) +stone_walkway_floor = shop_recipe(Floor.stone_walkway, Region.carpenter, 200, {Material.stone: 1}) +brick_floor = shop_recipe(Floor.brick, Region.carpenter, 500, {Material.clay: 2, Material.stone: 5}) +wood_path = starter_recipe(Floor.wood_path, {Material.wood: 1}) +gravel_path = starter_recipe(Floor.gravel_path, {Material.stone: 1}) +cobblestone_path = starter_recipe(Floor.cobblestone_path, {Material.stone: 1}) +stepping_stone_path = shop_recipe(Floor.stepping_stone_path, Region.carpenter, 100, {Material.stone: 1}) +crystal_path = shop_recipe(Floor.crystal_path, Region.carpenter, 200, {MetalBar.quartz: 1}) + +spinner = skill_recipe(Fishing.spinner, Skill.fishing, 6, {MetalBar.iron: 2}) +trap_bobber = skill_recipe(Fishing.trap_bobber, Skill.fishing, 6, {MetalBar.copper: 1, Material.sap: 10}) +cork_bobber = skill_recipe(Fishing.cork_bobber, Skill.fishing, 7, {Material.wood: 10, Material.hardwood: 5, Loot.slime: 10}) +quality_bobber = ap_recipe(Fishing.quality_bobber, {MetalBar.copper: 1, Material.sap: 20, Loot.solar_essence: 5}) +treasure_hunter = skill_recipe(Fishing.treasure_hunter, Skill.fishing, 7, {MetalBar.gold: 2}) +dressed_spinner = skill_recipe(Fishing.dressed_spinner, Skill.fishing, 8, {MetalBar.iron: 2, ArtisanGood.cloth: 1}) +barbed_hook = skill_recipe(Fishing.barbed_hook, Skill.fishing, 8, {MetalBar.copper: 1, MetalBar.iron: 1, MetalBar.gold: 1}) +magnet = skill_recipe(Fishing.magnet, Skill.fishing, 9, {MetalBar.iron: 1}) +bait = skill_recipe(Fishing.bait, Skill.fishing, 2, {Loot.bug_meat: 1}) +wild_bait = cutscene_recipe(Fishing.wild_bait, Region.tent, NPC.linus, 4, {Material.fiber: 10, Loot.bug_meat: 5, Loot.slime: 5}) +magic_bait = ap_recipe(Fishing.magic_bait, {Ore.radioactive: 1, Loot.bug_meat: 3}) +crab_pot = skill_recipe(Machine.crab_pot, Skill.fishing, 3, {Material.wood: 40, MetalBar.iron: 3}) + +sturdy_ring = skill_recipe(Ring.sturdy_ring, Skill.combat, 1, {MetalBar.copper: 2, Loot.bug_meat: 25, Loot.slime: 25}) +warrior_ring = skill_recipe(Ring.warrior_ring, Skill.combat, 4, {MetalBar.iron: 10, Material.coal: 25, Mineral.frozen_tear: 10}) +ring_of_yoba = skill_recipe(Ring.ring_of_yoba, Skill.combat, 7, {MetalBar.gold: 5, MetalBar.iron: 5, Mineral.diamond: 1}) +thorns_ring = skill_recipe(Ring.thorns_ring, Skill.combat, 7, {Fossil.bone_fragment: 50, Material.stone: 50, MetalBar.gold: 1}) +glowstone_ring = skill_recipe(Ring.glowstone_ring, Skill.mining, 4, {Loot.solar_essence: 5, MetalBar.iron: 5}) +iridium_band = skill_recipe(Ring.iridium_band, Skill.combat, 9, {MetalBar.iridium: 5, Loot.solar_essence: 50, Loot.void_essence: 50}) +wedding_ring = shop_recipe(Ring.wedding_ring, Region.traveling_cart, 500, {MetalBar.iridium: 5, Mineral.prismatic_shard: 1}) + +field_snack = skill_recipe(Edible.field_snack, Skill.foraging, 1, {TreeSeed.acorn: 1, TreeSeed.maple: 1, TreeSeed.pine: 1}) +bug_steak = skill_recipe(Edible.bug_steak, Skill.combat, 1, {Loot.bug_meat: 10}) +life_elixir = skill_recipe(Edible.life_elixir, Skill.combat, 2, {Forageable.red_mushroom: 1, Forageable.purple_mushroom: 1, Forageable.morel: 1, Forageable.chanterelle: 1}) +oil_of_garlic = skill_recipe(Edible.oil_of_garlic, Skill.combat, 6, {Vegetable.garlic: 10, Ingredient.oil: 1}) + +monster_musk = ap_recipe(Consumable.monster_musk, {Loot.bat_wing: 30, Loot.slime: 30}) +fairy_dust = ap_recipe(Consumable.fairy_dust, {Mineral.diamond: 1, Flower.fairy_rose: 1}) +warp_totem_beach = skill_recipe(Consumable.warp_totem_beach, Skill.foraging, 6, {Material.hardwood: 1, WaterItem.coral: 2, Material.fiber: 10}) +warp_totem_mountains = skill_recipe(Consumable.warp_totem_mountains, Skill.foraging, 7, {Material.hardwood: 1, MetalBar.iron: 1, Material.stone: 25}) +warp_totem_farm = skill_recipe(Consumable.warp_totem_farm, Skill.foraging, 8, {Material.hardwood: 1, ArtisanGood.honey: 1, Material.fiber: 20}) +warp_totem_desert = shop_trade_recipe(Consumable.warp_totem_desert, Region.desert, MetalBar.iridium, 10, {Material.hardwood: 2, Forageable.coconut: 1, Ore.iridium: 4}) +warp_totem_island = shop_recipe(Consumable.warp_totem_island, Region.volcano_dwarf_shop, 10000, {Material.hardwood: 5, Forageable.dragon_tooth: 1, Forageable.ginger: 1}) +rain_totem = skill_recipe(Consumable.rain_totem, Skill.foraging, 9, {Material.hardwood: 1, ArtisanGood.truffle_oil: 1, ArtisanGood.pine_tar: 5}) + +torch = starter_recipe(Lighting.torch, {Material.wood: 1, Material.sap: 2}) +campfire = starter_recipe(Lighting.campfire, {Material.stone: 10, Material.wood: 10, Material.fiber: 10}) +wooden_brazier = shop_recipe(Lighting.wooden_brazier, Region.carpenter, 250, {Material.wood: 10, Material.coal: 1, Material.fiber: 5}) +stone_brazier = shop_recipe(Lighting.stone_brazier, Region.carpenter, 400, {Material.stone: 10, Material.coal: 1, Material.fiber: 5}) +gold_brazier = shop_recipe(Lighting.gold_brazier, Region.carpenter, 1000, {MetalBar.gold: 1, Material.coal: 1, Material.fiber: 5}) +carved_brazier = shop_recipe(Lighting.carved_brazier, Region.carpenter, 2000, {Material.hardwood: 10, Material.coal: 1}) +stump_brazier = shop_recipe(Lighting.stump_brazier, Region.carpenter, 800, {Material.hardwood: 5, Material.coal: 1}) +barrel_brazier = shop_recipe(Lighting.barrel_brazier, Region.carpenter, 800, {Material.wood: 50, Loot.solar_essence: 1, Material.coal: 1}) +skull_brazier = shop_recipe(Lighting.skull_brazier, Region.carpenter, 3000, {Fossil.bone_fragment: 10}) +marble_brazier = shop_recipe(Lighting.marble_brazier, Region.carpenter, 5000, {Mineral.marble: 1, Mineral.aquamarine: 1, Material.stone: 100}) +wood_lamp_post = shop_recipe(Lighting.wood_lamp_post, Region.carpenter, 500, {Material.wood: 50, ArtisanGood.battery_pack: 1}) +iron_lamp_post = shop_recipe(Lighting.iron_lamp_post, Region.carpenter, 1000, {MetalBar.iron: 1, ArtisanGood.battery_pack: 1}) +jack_o_lantern = ap_recipe(Lighting.jack_o_lantern, {Vegetable.pumpkin: 1, Lighting.torch: 1}) + +bone_mill = ap_recipe(Machine.bone_mill, {Fossil.bone_fragment: 10, Material.clay: 3, Material.stone: 20}) +charcoal_kiln = skill_recipe(Machine.charcoal_kiln, Skill.foraging, 4, {Material.wood: 20, MetalBar.copper: 2}) +crystalarium = skill_recipe(Machine.crystalarium, Skill.mining, 9, {Material.stone: 99, MetalBar.gold: 5, MetalBar.iridium: 2, ArtisanGood.battery_pack: 1}) +furnace = starter_recipe(Machine.furnace, {Ore.copper: 20, Material.stone: 25}) +geode_crusher = ap_recipe(Machine.geode_crusher, {MetalBar.gold: 2, Material.stone: 50, Mineral.diamond: 1}) +heavy_tapper = ap_recipe(Machine.heavy_tapper, {Material.hardwood: 30, MetalBar.radioactive: 1}) +lightning_rod = skill_recipe(Machine.lightning_rod, Skill.foraging, 6, {MetalBar.iron: 1, MetalBar.quartz: 1, Loot.bat_wing: 5}) +ostrich_incubator = ap_recipe(Machine.ostrich_incubator, {Fossil.bone_fragment: 50, Material.hardwood: 50, Currency.cinder_shard: 20}) +recycling_machine = skill_recipe(Machine.recycling_machine, Skill.fishing, 4, {Material.wood: 25, Material.stone: 25, MetalBar.iron: 1}) +seed_maker = skill_recipe(Machine.seed_maker, Skill.farming, 9, {Material.wood: 25, Material.coal: 10, MetalBar.gold: 1}) +slime_egg_press = skill_recipe(Machine.slime_egg_press, Skill.combat, 6, {Material.coal: 25, Mineral.fire_quartz: 1, ArtisanGood.battery_pack: 1}) +slime_incubator = skill_recipe(Machine.slime_incubator, Skill.combat, 8, {MetalBar.iridium: 2, Loot.slime: 100}) +solar_panel = ap_recipe(Machine.solar_panel, {MetalBar.quartz: 10, MetalBar.iron: 5, MetalBar.gold: 5}) +tapper = skill_recipe(Machine.tapper, Skill.foraging, 3, {Material.wood: 40, MetalBar.copper: 2}) +worm_bin = skill_recipe(Machine.worm_bin, Skill.fishing, 8, {Material.hardwood: 25, MetalBar.gold: 1, MetalBar.iron: 1, Material.fiber: 50}) + +tub_o_flowers = ap_recipe(Furniture.tub_o_flowers, {Material.wood: 15, Seed.tulip: 1, Seed.jazz: 1, Seed.poppy: 1, Seed.spangle: 1}) +wicked_statue = shop_recipe(Furniture.wicked_statue, Region.sewer, 1000, {Material.stone: 25, Material.coal: 5}) +flute_block = cutscene_recipe(Furniture.flute_block, Region.carpenter, NPC.robin, 6, {Material.wood: 10, Ore.copper: 2, Material.fiber: 20}) +drum_block = cutscene_recipe(Furniture.drum_block, Region.carpenter, NPC.robin, 6, {Material.stone: 10, Ore.copper: 2, Material.fiber: 20}) + +chest = starter_recipe(Storage.chest, {Material.wood: 50}) +stone_chest = ap_recipe(Storage.stone_chest, {Material.stone: 50}) + +wood_sign = starter_recipe(Sign.wood, {Material.wood: 25}) +stone_sign = starter_recipe(Sign.stone, {Material.stone: 25}) +dark_sign = friendship_recipe(Sign.dark, NPC.krobus, 3, {Loot.bat_wing: 5, Fossil.bone_fragment: 5}) + +garden_pot = ap_recipe(Craftable.garden_pot, {Material.clay: 1, Material.stone: 10, MetalBar.quartz: 1}, "Greenhouse") +scarecrow = skill_recipe(Craftable.scarecrow, Skill.farming, 1, {Material.wood: 50, Material.coal: 1, Material.fiber: 20}) +deluxe_scarecrow = ap_recipe(Craftable.deluxe_scarecrow, {Material.wood: 50, Material.fiber: 40, Ore.iridium: 1}) +staircase = skill_recipe(Craftable.staircase, Skill.mining, 2, {Material.stone: 99}) +explosive_ammo = skill_recipe(Craftable.explosive_ammo, Skill.combat, 8, {MetalBar.iron: 1, Material.coal: 2}) +transmute_fe = skill_recipe(Craftable.transmute_fe, Skill.mining, 4, {MetalBar.copper: 3}) +transmute_au = skill_recipe(Craftable.transmute_au, Skill.mining, 7, {MetalBar.iron: 2}) +mini_jukebox = cutscene_recipe(Craftable.mini_jukebox, Region.saloon, NPC.gus, 5, {MetalBar.iron: 2, ArtisanGood.battery_pack: 1}) +mini_obelisk = ap_recipe(Craftable.mini_obelisk, {Material.hardwood: 30, Loot.solar_essence: 20, MetalBar.gold: 3}) +farm_computer = ap_recipe(Craftable.farm_computer, {Artifact.dwarf_gadget: 1, ArtisanGood.battery_pack: 1, MetalBar.quartz: 10}) +hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1}) +cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 9, {Material.wood: 15, Material.fiber: 10, Material.coal: 3}) \ No newline at end of file diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index b94157d696d6..5146297c456b 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -135,6 +135,6 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un legendary_fish = [angler, crimsonfish, glacierfish, legend, mutant_carp] extended_family = [ms_angler, son_of_crimsonfish, glacierfish_jr, legend_ii, radioactive_carp] special_fish = [*legendary_fish, blob_fish, lava_eel, octopus, scorpion_carp, ice_pip, super_cucumber, dorado] -island_fish = [lionfish, blue_discus, stingray] +island_fish = [lionfish, blue_discus, stingray, *extended_family] all_fish_by_name = {fish.name: fish for fish in all_fish} diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index f651323b3ac9..ae41051e5b65 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -226,13 +226,13 @@ id,name,classification,groups,mod_name 241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", 251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", @@ -307,6 +307,18 @@ id,name,classification,groups,mod_name 322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +325,Fairy Dust Recipe,progression,"CRAFTING_RECIPE", +326,Heavy Tapper Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", +327,Hyper Speed-Gro Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", +328,Deluxe Fertilizer Recipe,progression,"CRAFTING_RECIPE", +329,Hopper Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", +330,Magic Bait Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", +331,Jack-O-Lantern Recipe,progression,"CRAFTING_RECIPE", +332,Fiber Seeds Recipe,progression,"CRAFTING_RECIPE", +333,Tub o' Flowers Recipe,progression,"CRAFTING_RECIPE", +334,Fiber Seeds Recipe,progression,"CRAFTING_RECIPE", +335,Quality Bobber Recipe,progression,"CRAFTING_RECIPE", +336,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, @@ -561,16 +573,9 @@ id,name,classification,groups,mod_name 5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", 5236,Aquatic Sanctuary,filler,RESOURCE_PACK, -5237,Heavy Tapper Recipe,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5238,Hyper Speed-Gro Recipe,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5239,Deluxe Fertilizer Recipe,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5240,Hopper Recipe,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5241,Magic Bait Recipe,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5242,Exotic Double Bed,filler,RESOURCE_PACK, 5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK", -5244,Golden Egg,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", -5246,Fairy Dust Recipe,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 97c15b2d3207..48c26ab918d1 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1246,7 +1246,7 @@ id,region,name,tags,mod_name 2602,Farm,Shipsanity: Warp Totem: Beach,SHIPSANITY, 2603,Farm,Shipsanity: Warp Totem: Desert,SHIPSANITY, 2604,Farm,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Farm,Shipsanity: Warp Totem: Island,SHIPSANITY, +2605,Farm,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", 2606,Farm,Shipsanity: Warp Totem: Mountains,SHIPSANITY, 2607,Farm,Shipsanity: Weathered Floor,SHIPSANITY, 2608,Farm,Shipsanity: Wild Bait,SHIPSANITY, @@ -1600,18 +1600,18 @@ id,region,name,tags,mod_name 2956,Farm,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", 2957,Farm,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2958,Farm,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY", +2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", 2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", 2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY", -2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY", -2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY", +2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", 2965,Farm,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", 2966,Farm,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", 2967,Farm,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", 2968,Farm,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", 2969,Farm,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Farm,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY", +2970,Farm,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", 2971,Farm,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", 2972,Farm,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", 2973,Farm,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index aaec40d0c6bf..9c9ddf135e93 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -1,5 +1,6 @@ from typing import Dict, List +from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.crop_names import Fruit, Vegetable @@ -8,80 +9,13 @@ from ..strings.forageable_names import Forageable from ..strings.ingredient_names import Ingredient from ..strings.food_names import Meal, Beverage +from ..strings.metal_names import Fossil from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.skill_names import Skill from ..strings.villager_names import NPC -class RecipeSource: - - def __repr__(self): - return f"RecipeSource" - - -class StarterSource(RecipeSource): - - def __repr__(self): - return f"StarterSource" - - -class QueenOfSauceSource(RecipeSource): - year: int - season: str - day: int - - def __init__(self, year: int, season: str, day: int): - self.year = year - self.season = season - self.day = day - - def __repr__(self): - return f"QueenOfSauceSource at year {self.year} {self.season} {self.day}" - - -class FriendshipSource(RecipeSource): - friend: str - hearts: int - - def __init__(self, friend: str, hearts: int): - self.friend = friend - self.hearts = hearts - - def __repr__(self): - return f"FriendshipSource at {self.friend} {self.hearts} <3" - - -class SkillSource(RecipeSource): - skill: str - level: int - - def __init__(self, skill: str, level: int): - self.skill = skill - self.level = level - - def __repr__(self): - return f"SkillSource at level {self.level} {self.skill}" - - -class ShopSource(RecipeSource): - region: str - price: int - - def __init__(self, region: str, price: int): - self.region = region - self.price = price - - def __repr__(self): - return f"ShopSource at {self.region} costing {self.price}g" - - -class ShopTradeSource(ShopSource): - currency: str - - def __repr__(self): - return f"ShopTradeSource at {self.region} costing {self.price} {self.currency}" - class CookingRecipe: meal: str @@ -116,6 +50,11 @@ def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) return create_recipe(name, ingredients, source) +def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int]) -> CookingRecipe: + source = ShopTradeSource(region, currency, price) + return create_recipe(name, ingredients, source) + + def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredients: Dict[str, int]) -> CookingRecipe: source = QueenOfSauceSource(year, season, day) return create_recipe(name, ingredients, source) @@ -136,10 +75,12 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) artichoke_dip = queen_of_sauce_recipe(Meal.artichoke_dip, 1, Season.fall, 28, {Vegetable.artichoke: 1, AnimalProduct.cow_milk: 1}) autumn_bounty = friendship_recipe(Meal.autumn_bounty, NPC.demetrius, 7, {Vegetable.yam: 1, Vegetable.pumpkin: 1}) baked_fish = queen_of_sauce_recipe(Meal.baked_fish, 1, Season.summer, 7, {Fish.sunfish: 1, Fish.bream: 1, Ingredient.wheat_flour: 1}) +banana_pudding = shop_trade_recipe(Meal.banana_pudding, Region.island_trader, Fossil.bone_fragment, 30, {Fruit.banana: 1, AnimalProduct.cow_milk: 1, Ingredient.sugar: 1}) bean_hotpot = friendship_recipe(Meal.bean_hotpot, NPC.clint, 7, {Vegetable.green_bean: 2}) blackberry_cobbler_ingredients = {Forageable.blackberry: 2, Ingredient.sugar: 1, Ingredient.wheat_flour: 1} blackberry_cobbler_qos = queen_of_sauce_recipe(Meal.blackberry_cobbler, 2, Season.fall, 14, blackberry_cobbler_ingredients) -blueberry_tart = friendship_recipe(Meal.blueberry_tart, NPC.pierre, 3, {Fruit.blueberry: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.any_egg: 1}) +blueberry_tart_ingredients = {Fruit.blueberry: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.any_egg: 1} +blueberry_tart = friendship_recipe(Meal.blueberry_tart, NPC.pierre, 3, blueberry_tart_ingredients) bread = queen_of_sauce_recipe(Meal.bread, 1, Season.summer, 28, {Ingredient.wheat_flour: 1}) bruschetta = queen_of_sauce_recipe(Meal.bruschetta, 2, Season.winter, 21, {Meal.bread: 1, Ingredient.oil: 1, Vegetable.tomato: 1}) carp_surprise = queen_of_sauce_recipe(Meal.carp_surprise, 2, Season.summer, 7, {Fish.carp: 4}) @@ -148,17 +89,20 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) chocolate_cake_qos = queen_of_sauce_recipe(Meal.chocolate_cake, 1, Season.winter, 14, chocolate_cake_ingredients) chowder = friendship_recipe(Meal.chowder, NPC.willy, 3, {WaterItem.clam: 1, AnimalProduct.cow_milk: 1}) coleslaw = queen_of_sauce_recipe(Meal.coleslaw, 14, Season.spring, 14, {Vegetable.red_cabbage: 1, Ingredient.vinegar: 1, ArtisanGood.mayonnaise: 1}) -complete_breakfast = queen_of_sauce_recipe(Meal.complete_breakfast, 2, Season.spring, 21, {Meal.fried_egg: 1, AnimalProduct.milk: 1, Meal.hashbrowns: 1, Meal.pancakes: 1}) +complete_breakfast_ingredients = {Meal.fried_egg: 1, AnimalProduct.milk: 1, Meal.hashbrowns: 1, Meal.pancakes: 1} +complete_breakfast = queen_of_sauce_recipe(Meal.complete_breakfast, 2, Season.spring, 21, complete_breakfast_ingredients) cookie = friendship_recipe(Meal.cookie, NPC.evelyn, 4, {Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.chicken_egg: 1}) crab_cakes_ingredients = {Fish.crab: 1, Ingredient.wheat_flour: 1, AnimalProduct.chicken_egg: 1, Ingredient.oil: 1} crab_cakes_qos = queen_of_sauce_recipe(Meal.crab_cakes, 2, Season.fall, 21, crab_cakes_ingredients) cranberry_candy = queen_of_sauce_recipe(Meal.cranberry_candy, 1, Season.winter, 28, {Fruit.cranberries: 1, Fruit.apple: 1, Ingredient.sugar: 1}) +cranberry_sauce = friendship_recipe(Meal.cranberry_sauce, NPC.gus, 7, {Fruit.cranberries: 1, Ingredient.sugar: 1}) crispy_bass = friendship_recipe(Meal.crispy_bass, NPC.kent, 3, {Fish.largemouth_bass: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}) dish_o_the_sea = skill_recipe(Meal.dish_o_the_sea, Skill.fishing, 3, {Fish.sardine: 2, Meal.hashbrowns: 1}) eggplant_parmesan = friendship_recipe(Meal.eggplant_parmesan, NPC.lewis, 7, {Vegetable.eggplant: 1, Vegetable.tomato: 1}) escargot = friendship_recipe(Meal.escargot, NPC.willy, 5, {Fish.snail: 1, Vegetable.garlic: 1}) farmer_lunch = skill_recipe(Meal.farmer_lunch, Skill.farming, 3, {Meal.omelet: 2, Vegetable.parsnip: 1}) fiddlehead_risotto = queen_of_sauce_recipe(Meal.fiddlehead_risotto, 2, Season.fall, 28, {Ingredient.oil: 1, Forageable.fiddlehead_fern: 1, Vegetable.garlic: 1}) +fish_stew = friendship_recipe(Meal.fish_stew, NPC.willy, 7, {Fish.crayfish: 1, Fish.mussel: 1, Fish.periwinkle: 1, Vegetable.tomato: 1}) fish_taco = friendship_recipe(Meal.fish_taco, NPC.linus, 7, {Fish.tuna: 1, Meal.tortilla: 1, Vegetable.red_cabbage: 1, ArtisanGood.mayonnaise: 1}) fried_calamari = friendship_recipe(Meal.fried_calamari, NPC.jodi, 3, {Fish.squid: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}) fried_eel = friendship_recipe(Meal.fried_eel, NPC.george, 3, {Fish.eel: 1, Ingredient.oil: 1}) @@ -169,7 +113,12 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) glazed_yams = queen_of_sauce_recipe(Meal.glazed_yams, 1, Season.fall, 21, {Vegetable.yam: 1, Ingredient.sugar: 1}) hashbrowns = queen_of_sauce_recipe(Meal.hashbrowns, 2, Season.spring, 14, {Vegetable.potato: 1, Ingredient.oil: 1}) ice_cream = friendship_recipe(Meal.ice_cream, NPC.jodi, 7, {AnimalProduct.cow_milk: 1, Ingredient.sugar: 1}) +lobster_bisque_ingredients = {Fish.lobster: 1, AnimalProduct.cow_milk: 1} +lobster_bisque_friend = friendship_recipe(Meal.lobster_bisque, NPC.willy, 9, lobster_bisque_ingredients) +lobster_bisque_qos = queen_of_sauce_recipe(Meal.lobster_bisque, 2, Season.winter, 14, lobster_bisque_ingredients) +lucky_lunch = queen_of_sauce_recipe(Meal.lucky_lunch, 2, Season.spring, 28, {Fish.sea_cucumber: 1, Meal.tortilla: 1, Flower.blue_jazz: 1}) maki_roll = queen_of_sauce_recipe(Meal.maki_roll, 1, Season.summer, 21, {Fish.any: 1, WaterItem.seaweed: 1, Ingredient.rice: 1}) +mango_sticky_rice = friendship_recipe(Meal.mango_sticky_rice, NPC.leo, 7, {Fruit.mango: 1, Forageable.coconut: 1, Ingredient.rice: 1}) maple_bar = queen_of_sauce_recipe(Meal.maple_bar, 2, Season.summer, 14, {ArtisanGood.maple_syrup: 1, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}) miners_treat = skill_recipe(Meal.miners_treat, Skill.mining, 3, {Forageable.cave_carrot: 2, Ingredient.sugar: 1, AnimalProduct.cow_milk: 1}) omelet = queen_of_sauce_recipe(Meal.omelet, 1, Season.spring, 28, {AnimalProduct.chicken_egg: 1, AnimalProduct.cow_milk: 1}) @@ -183,9 +132,12 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) pizza_qos = queen_of_sauce_recipe(Meal.pizza, 2, Season.spring, 7, pizza_ingredients) pizza_saloon = shop_recipe(Meal.pizza, Region.saloon, 150, pizza_ingredients) plum_pudding = queen_of_sauce_recipe(Meal.plum_pudding, 1, Season.winter, 7, {Forageable.wild_plum: 2, Ingredient.wheat_flour: 1, Ingredient.sugar: 1}) +poi = friendship_recipe(Meal.poi, NPC.leo, 3, {Vegetable.taro_root: 4}) poppyseed_muffin = queen_of_sauce_recipe(Meal.poppyseed_muffin, 2, Season.winter, 7, {Flower.poppy: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1}) pumpkin_pie_ingredients = {Vegetable.pumpkin: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.cow_milk: 1} pumpkin_pie_qos = queen_of_sauce_recipe(Meal.pumpkin_pie, 1, Season.winter, 21, pumpkin_pie_ingredients) +pumpkin_soup = friendship_recipe(Meal.pumpkin_soup, NPC.robin, 7, {Vegetable.pumpkin: 1, AnimalProduct.cow_milk: 1}) +radish_salad = queen_of_sauce_recipe(Meal.radish_salad, 1, Season.spring, 21, {Ingredient.oil: 1, Ingredient.vinegar: 1, Vegetable.radish: 1}) red_plate = friendship_recipe(Meal.red_plate, NPC.emily, 7, {Vegetable.red_cabbage: 1, Vegetable.radish: 1}) rhubarb_pie = friendship_recipe(Meal.rhubarb_pie, NPC.marnie, 7, {Fruit.rhubarb: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1}) rice_pudding = friendship_recipe(Meal.rice_pudding, NPC.evelyn, 7, {AnimalProduct.milk: 1, Ingredient.sugar: 1, Ingredient.rice: 1}) @@ -194,21 +146,21 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) salad = friendship_recipe(Meal.salad, NPC.emily, 3, {Forageable.leek: 1, Forageable.dandelion: 1, Ingredient.vinegar: 1}) salmon_dinner = friendship_recipe(Meal.salmon_dinner, NPC.gus, 3, {Fish.salmon: 1, Vegetable.amaranth: 1, Vegetable.kale: 1}) sashimi = friendship_recipe(Meal.sashimi, NPC.linus, 3, {Fish.any: 1}) +seafoam_pudding = skill_recipe(Meal.seafoam_pudding, Skill.fishing, 9, {Fish.flounder: 1, Fish.midnight_carp: 1, AnimalProduct.squid_ink: 1}) +shrimp_cocktail = queen_of_sauce_recipe(Meal.shrimp_cocktail, 2, Season.winter, 28, {Vegetable.tomato: 1, Fish.shrimp: 1, Forageable.wild_horseradish: 1}) spaghetti = friendship_recipe(Meal.spaghetti, NPC.lewis, 3, {Vegetable.tomato: 1, Ingredient.wheat_flour: 1}) +spicy_eel = friendship_recipe(Meal.spicy_eel, NPC.george, 7, {Fish.eel: 1, Fruit.hot_pepper: 1}) +squid_ink_ravioli = skill_recipe(Meal.squid_ink_ravioli, Skill.combat, 9, {AnimalProduct.squid_ink: 1, Ingredient.wheat_flour: 1, Vegetable.tomato: 1}) stir_fry_ingredients = {Forageable.cave_carrot: 1, Forageable.common_mushroom: 1, Vegetable.kale: 1, Ingredient.sugar: 1} stir_fry_qos = queen_of_sauce_recipe(Meal.stir_fry, 1, Season.spring, 7, stir_fry_ingredients) stuffing = friendship_recipe(Meal.stuffing, NPC.pam, 7, {Meal.bread: 1, Fruit.cranberries: 1, Forageable.hazelnut: 1}) +super_meal = friendship_recipe(Meal.super_meal, NPC.kent, 7, {Vegetable.bok_choy: 1, Fruit.cranberries: 1, Vegetable.artichoke: 1}) survival_burger = skill_recipe(Meal.survival_burger, Skill.foraging, 2, {Meal.bread: 1, Forageable.cave_carrot: 1, Vegetable.eggplant: 1}) +tom_kha_soup = friendship_recipe(Meal.tom_kha_soup, NPC.sandy, 7, {Forageable.coconut: 1, Fish.shrimp: 1, Forageable.common_mushroom: 1}) tortilla_ingredients = {Vegetable.corn: 1} tortilla_qos = queen_of_sauce_recipe(Meal.tortilla, 1, Season.fall, 7, tortilla_ingredients) tortilla_saloon = shop_recipe(Meal.tortilla, Region.saloon, 100, tortilla_ingredients) triple_shot_espresso = shop_recipe(Beverage.triple_shot_espresso, Region.saloon, 5000, {Beverage.coffee: 3}) tropical_curry = shop_recipe(Meal.tropical_curry, Region.island_resort, 2000, {Forageable.coconut: 1, Fruit.pineapple: 1, Fruit.hot_pepper: 1}) +trout_soup = queen_of_sauce_recipe(Meal.trout_soup, 1, Season.fall, 14, {Fish.rainbow_trout: 1, WaterItem.green_algae: 1}) vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Vegetable.tomato: 1, Vegetable.beet: 1}) - - - - - - - diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py new file mode 100644 index 000000000000..aa307b42569a --- /dev/null +++ b/worlds/stardew_valley/data/recipe_source.py @@ -0,0 +1,108 @@ +from typing import Iterable, Union, List + + +class RecipeSource: + + def __repr__(self): + return f"RecipeSource" + + +class StarterSource(RecipeSource): + + def __repr__(self): + return f"StarterSource" + + +class ArchipelagoSource(RecipeSource): + ap_item: List[str] + + def __init__(self, ap_item: Union[str, List[str]]): + if isinstance(ap_item, str): + ap_item = [ap_item] + self.ap_item = ap_item + + def __repr__(self): + return f"ArchipelagoSource {ap_item}" + + +class LogicSource(RecipeSource): + logic_rule: str + + def __init__(self, logic_rule: str): + self.logic_rule = logic_rule + + def __repr__(self): + return f"LogicSource {logic_rule}" + + +class QueenOfSauceSource(RecipeSource): + year: int + season: str + day: int + + def __init__(self, year: int, season: str, day: int): + self.year = year + self.season = season + self.day = day + + def __repr__(self): + return f"QueenOfSauceSource at year {self.year} {self.season} {self.day}" + + +class FriendshipSource(RecipeSource): + friend: str + hearts: int + + def __init__(self, friend: str, hearts: int): + self.friend = friend + self.hearts = hearts + + def __repr__(self): + return f"FriendshipSource at {self.friend} {self.hearts} <3" + + +class CutsceneSource(FriendshipSource): + region: str + + def __init__(self, region: str, friend: str, hearts: int): + super().__init__(friend, hearts) + self.region = region + + def __repr__(self): + return f"CutsceneSource at {region}" + + +class SkillSource(RecipeSource): + skill: str + level: int + + def __init__(self, skill: str, level: int): + self.skill = skill + self.level = level + + def __repr__(self): + return f"SkillSource at level {self.level} {self.skill}" + + +class ShopSource(RecipeSource): + region: str + price: int + + def __init__(self, region: str, price: int): + self.region = region + self.price = price + + def __repr__(self): + return f"ShopSource at {self.region} costing {self.price}g" + + +class ShopTradeSource(ShopSource): + currency: str + + def __init__(self, region: str, currency: str, price: int): + super().__init__(region, price) + self.currency = currency + + def __repr__(self): + return f"ShopTradeSource at {self.region} costing {self.price} {self.currency}" + diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index e858d46f34a3..c357e35ce849 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -1,5 +1,7 @@ from dataclasses import dataclass from typing import List, Tuple, Optional, Dict + +from ..strings.food_names import Beverage from ..strings.region_names import Region from ..mods.mod_data import ModNames from ..strings.season_names import Season @@ -183,7 +185,7 @@ def __repr__(self): pale_ale = ("Pale Ale",) parsnip = ("Parsnip",) # parsnip_soup = ("Parsnip Soup",) -pina_colada = ("Piña Colada",) +pina_colada = (Beverage.pina_colada,) pam_loves = beer + cactus_fruit + glazed_yams + mead + pale_ale + parsnip + pina_colada # | parsnip_soup # fried_calamari = ("Fried Calamari",) pierre_loves = () # fried_calamari diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index f4f43aca0179..c8f27b0e3fe0 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -65,6 +65,7 @@ class Group(enum.Enum): GINGER_ISLAND = enum.auto() WALNUT_PURCHASE = enum.auto() TV_CHANNEL = enum.auto() + CRAFTING_RECIPE = enum.auto() MAGIC_SPELL = enum.auto() @@ -191,10 +192,12 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_friendsanity_items(item_factory, world_options, items, random) create_festival_rewards(item_factory, world_options, items) create_babies(item_factory, items, random) - create_special_order_board_rewards(item_factory, options, items) - create_special_order_qi_rewards(item_factory, options, items) - create_walnut_purchase_rewards(item_factory, options, items) - create_magic_mod_spells(item_factory, options, items) + create_special_order_board_rewards(item_factory, world_options, items) + create_special_order_qi_rewards(item_factory, world_options, items) + create_walnut_purchase_rewards(item_factory, world_options, items) + create_crafting_recipes(item_factory, world_options, items) + create_magic_mod_spells(item_factory, world_options, items) + items.append(item_factory("Golden Egg")) return items @@ -514,8 +517,15 @@ def create_tv_channels(item_factory: StardewItemFactory, items: List[Item]): items.extend([item_factory(item) for item in items_by_group[Group.TV_CHANNEL]]) -def create_filler_festival_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions) -> List[Item]: - if options.festival_locations == FestivalLocations.option_disabled: +def create_crafting_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + if world_options[options.Shipsanity] == options.Shipsanity.option_everything: + crafting_recipes = [reward for reward in items_by_group[Group.CRAFTING_RECIPE]] + crafting_recipes = remove_excluded_packs(crafting_recipes, world_options) + items.extend([item_factory(item) for item in crafting_recipes]) + + +def create_filler_festival_rewards(item_factory: StardewItemFactory, world_options: StardewOptions) -> List[Item]: + if world_options[options.FestivalLocations] == options.FestivalLocations.option_disabled: return [] return [item_factory(item) for item in items_by_group[Group.FESTIVAL] if diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 5dd13f9d7db8..f74316f69393 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -25,8 +25,11 @@ def can_watch(self, channel: str = None): return tv_rule return self.received(channel) & tv_rule - def can_do_panning(self, item: str = Generic.any) -> StardewRule: - return self.received("Glittering Boulder Removed") + def can_pan(self) -> StardewRule: + return self.received("Glittering Boulder Removed") & self.region.can_reach(Region.mountain) + + def can_pan_at(self, region: str) -> StardewRule: + return self.region.can_reach(region) & self.can_pan() def can_open_geode(self, geode: str) -> StardewRule: blacksmith_access = self.region.can_reach(Region.blacksmith) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index a99c34685edd..34ef899eccd0 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -2,11 +2,14 @@ from .building_logic import BuildingLogic from .has_logic import HasLogic from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe +from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource from ..stardew_rule import StardewRule, True_, False_, And from ..strings.skill_names import Skill from ..strings.tv_channel_names import Channel @@ -14,7 +17,9 @@ class CookingLogic: player: int + received: ReceivedLogic has: HasLogic + region: RegionLogic season: SeasonLogic time: TimeLogic money: MoneyLogic @@ -23,10 +28,12 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, has: HasLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, - relationship: RelationshipLogic, skill: SkillLogic): + def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player + self.received = received self.has = has + self.region = region self.season = season self.time = time self.money = money @@ -49,10 +56,16 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() + if isinstance(source, ArchipelagoSource): + return self.received(source.ap_item, len(source.ap_item)) + if isinstance(source, ShopTradeSource): + return self.money.can_trade_at(source.region, source.currency, source.price) if isinstance(source, ShopSource): return self.money.can_spend_at(source.region, source.price) if isinstance(source, SkillSource): return self.skill.has_level(source.skill, source.level) + if isinstance(source, CutsceneSource): + return self.region.can_reach(source.region) & self.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, FriendshipSource): return self.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, QueenOfSauceSource): diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py new file mode 100644 index 000000000000..85cba9d190f0 --- /dev/null +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -0,0 +1,66 @@ +from .has_logic import HasLogic +from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .relationship_logic import RelationshipLogic +from .skill_logic import SkillLogic +from .time_logic import TimeLogic +from ..data.craftable_data import CraftingRecipe +from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource +from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource +from ..stardew_rule import StardewRule, True_, False_, And +from ..strings.region_names import Region + + +class CraftingLogic: + player: int + received: ReceivedLogic + has: HasLogic + region: RegionLogic + time: TimeLogic + money: MoneyLogic + relationship: RelationshipLogic + skill: SkillLogic + + def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, money: MoneyLogic, + relationship: RelationshipLogic, skill: SkillLogic): + self.player = player + self.received = received + self.has = has + self.region = region + self.time = time + self.money = money + self.relationship = relationship + self.skill = skill + + def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: + craft_rule = True_() + if recipe is None: + return craft_rule + + learn_rule = self.can_learn_recipe(recipe.source) + ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) + number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) // 10 + time_rule = self.time.has_lived_months(number_ingredients) + return craft_rule & learn_rule & ingredients_rule & time_rule + + def can_learn_recipe(self, source: RecipeSource) -> StardewRule: + if isinstance(source, StarterSource): + return True_() + if isinstance(source, ArchipelagoSource): + return self.received(source.ap_item, len(source.ap_item)) + if isinstance(source, ShopTradeSource): + return self.money.can_trade_at(source.region, source.currency, source.price) + if isinstance(source, ShopSource): + return self.money.can_spend_at(source.region, source.price) + if isinstance(source, SkillSource): + return self.skill.has_level(source.skill, source.level) + if isinstance(source, CutsceneSource): + return self.region.can_reach(source.region) & self.relationship.has_hearts(source.friend, source.hearts) + if isinstance(source, FriendshipSource): + return self.relationship.has_hearts(source.friend, source.hearts) + if isinstance(source, LogicSource): + if source.logic_rule == "Cellar": + return self.region.can_reach(Region.cellar) + + return False_() diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 06c8e18aa21c..e1fd9799479c 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -28,3 +28,6 @@ def has_max_fishing(self) -> StardewRule: def can_fish_chests(self) -> StardewRule: skill_rule = self.skill.has_level(Skill.fishing, 4) return self.tool.has_fishing_rod(4) & skill_rule + + def can_fish_at(self, region: str) -> StardewRule: + return self.skill.can_fish() & self.region.can_reach(region) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index b3994a71dd67..ffe5d7a5fedd 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -10,6 +10,7 @@ from .building_logic import BuildingLogic from .combat_logic import CombatLogic from .cooking_logic import CookingLogic +from .crafting_logic import CraftingLogic from .crop_logic import CropLogic from .fishing_logic import FishingLogic from .gift_logic import GiftLogic @@ -27,14 +28,15 @@ from .time_logic import TimeLogic from .tool_logic import ToolLogic from .wallet_logic import WalletLogic +from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name -from ..data.monster_data import all_monsters_by_category +from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..locations import LocationTags, locations_by_tag from ..mods.logic.mod_logic import ModLogic from .. import options from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops from ..data.bundle_data import BundleItem -from ..data.fish_data import island_fish, legendary_fish +from ..data.fish_data import island_fish, legendary_fish, extended_family from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..options import StardewOptions @@ -47,11 +49,13 @@ from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building from ..strings.calendar_names import Weekday -from ..strings.craftable_names import Craftable +from worlds.stardew_valley.strings.craftable_names import Craftable, Consumable, Furniture, Ring, Fishing, Lighting from ..strings.crop_names import Fruit, Vegetable +from ..strings.currency_names import Currency +from ..strings.decoration_names import Decoration from ..strings.fertilizer_names import Fertilizer from ..strings.festival_check_names import FestivalCheck -from ..strings.fish_names import Fish, Trash, WaterItem +from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest from ..strings.flower_names import Flower from ..strings.forageable_names import Forageable from ..strings.fruit_tree_names import Sapling @@ -64,15 +68,15 @@ from ..strings.food_names import Meal, Beverage from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil from ..strings.monster_drop_names import Loot +from ..strings.monster_names import Monster from ..strings.quest_names import Quest from ..strings.region_names import Region from ..strings.season_names import Season -from ..strings.seed_names import Seed +from ..strings.seed_names import Seed, TreeSeed from ..strings.skill_names import Skill from ..strings.tool_names import Tool, ToolMaterial from ..strings.villager_names import NPC from ..strings.wallet_item_names import Wallet -from ..strings.weapon_names import Weapon MISSING_ITEM = "THIS ITEM IS MISSING" @@ -89,6 +93,7 @@ class StardewLogic: tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) seed_rules: Dict[str, StardewRule] = field(default_factory=dict) cooking_rules: Dict[str, StardewRule] = field(default_factory=dict) + crafting_rules: Dict[str, StardewRule] = field(default_factory=dict) crop_rules: Dict[str, StardewRule] = field(default_factory=dict) fish_rules: Dict[str, StardewRule] = field(default_factory=dict) museum_rules: Dict[str, StardewRule] = field(default_factory=dict) @@ -101,7 +106,7 @@ def __post_init__(self): self.region = RegionLogic(self.player) self.time = TimeLogic(self.player, self.received) self.season = SeasonLogic(self.player, self.options[options.SeasonRandomization], self.received, self.time) - self.money = MoneyLogic(self.player, self.options[options.StartingMoney], self.region, self.time) + self.money = MoneyLogic(self.player, self.options[options.StartingMoney], self.received, self.has, self.region, self.time) self.action = ActionLogic(self.player, self.received, self.has, self.region) self.arcade = ArcadeLogic(self.player, self.options[options.ArcadeMachineLocations], self.received, self.region) self.artisan = ArtisanLogic(self.player, self.has, self.time) @@ -125,7 +130,8 @@ def __post_init__(self): self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.has, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.cooking = CookingLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.crafting = CraftingLogic(self.player, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.arcade, self.artisan, @@ -143,6 +149,12 @@ def __post_init__(self): can_cook_rule = can_cook_rule | self.cooking_rules[recipe.meal] self.cooking_rules[recipe.meal] = can_cook_rule + for recipe in all_crafting_recipes: + can_craft_rule = self.crafting.can_craft(recipe) + if recipe.item in self.crafting_rules: + can_craft_rule = can_craft_rule | self.crafting_rules[recipe.item] + self.crafting_rules[recipe.item] = can_craft_rule + self.sapling_rules.update({ Sapling.apple: self.can_buy_sapling(Fruit.apple), Sapling.apricot: self.can_buy_sapling(Fruit.apricot), @@ -181,8 +193,10 @@ def __post_init__(self): self.item_rules.update({ "Energy Tonic": self.money.can_spend_at(Region.hospital, 1000), - "Fishing Chest": self.fishing.can_fish_chests(), - "Hot Java Ring": self.region.can_reach(Region.volcano_floor_10), + WaterChest.fishing_chest: self.fishing.can_fish_chests(), + WaterChest.treasure: self.fishing.can_fish_chests(), + Ring.hot_java_ring: self.region.can_reach(Region.volcano_floor_10), + "Galaxy Soul": self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 40), "JotPK Big Buff": self.arcade.has_jotpk_power_level(7), "JotPK Max Buff": self.arcade.has_jotpk_power_level(9), "JotPK Medium Buff": self.arcade.has_jotpk_power_level(4), @@ -214,6 +228,7 @@ def __post_init__(self): AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), AnimalProduct.egg: self.has_animal(Animal.chicken), AnimalProduct.goat_milk: self.has(Animal.goat), + AnimalProduct.golden_egg: self.received(AnimalProduct.golden_egg) & (self.money.can_spend_at(Region.ranch, 100000) | self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 100)), AnimalProduct.large_brown_egg: self.has_happy_animal(Animal.chicken), AnimalProduct.large_egg: self.has_happy_animal(Animal.chicken), AnimalProduct.large_goat_milk: self.has_happy_animal(Animal.goat), @@ -227,6 +242,11 @@ def __post_init__(self): AnimalProduct.truffle: self.has_animal(Animal.pig) & self.season.has_any_not_winter(), AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), + AnimalProduct.slime_egg_green: self.has(Machine.slime_egg_press) & self.has(Loot.slime), + AnimalProduct.slime_egg_blue: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(3), + AnimalProduct.slime_egg_red: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(6), + AnimalProduct.slime_egg_purple: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(9), + AnimalProduct.slime_egg_tiger: self.has(Fish.lionfish) & self.buildings.has_building(Building.fish_pond), ArtisanGood.aged_roe: self.artisan.can_preserves_jar(AnimalProduct.roe), ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.season.has_any_not_winter()) | self.has(Machine.solar_panel), ArtisanGood.caviar: self.artisan.can_preserves_jar(AnimalProduct.sturgeon_roe), @@ -253,17 +273,7 @@ def __post_init__(self): Beverage.coffee: self.artisan.can_keg(Seed.coffee) | self.has(Machine.coffee_maker) | (self.money.can_spend_at(Region.saloon, 300)) | self.has("Hot Java Ring"), Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600), Beverage.triple_shot_espresso: self.has("Hot Java Ring"), - Craftable.bait: (self.skill.has_level(Skill.fishing, 2) & self.has(Loot.bug_meat)) | self.has(Machine.worm_bin), - Craftable.bomb: self.skill.has_level(Skill.mining, 6) & self.has(Material.coal) & self.has(Ore.iron), - Craftable.cherry_bomb: self.skill.has_level(Skill.mining, 1) & self.has(Material.coal) & self.has(Ore.copper), - Craftable.flute_block: self.relationship.has_hearts(NPC.robin, 6) & self.region.can_reach(Region.carpenter) & self.has(Material.wood) & self.has(Ore.copper) & self.has(Material.fiber), - Craftable.life_elixir: self.skill.has_level(Skill.combat, 2) & self.has(Forageable.red_mushroom) & self.has(Forageable.purple_mushroom) & self.has(Forageable.morel) & self.has(Forageable.chanterelle), - Craftable.mega_bomb: self.skill.has_level(Skill.mining, 8) & self.has(Ore.gold) & self.has(Loot.solar_essence) & self.has(Loot.void_essence), - Craftable.monster_musk: self.has_prismatic_jelly_reward_access() & self.has(Loot.slime) & self.has(Loot.bat_wing), - Craftable.oil_of_garlic: (self.skill.has_level(Skill.combat, 6) & self.has(Vegetable.garlic) & self.has(Ingredient.oil)) | (self.money.can_spend_at(Region.mines_dwarf_shop, 3000)), - Craftable.rain_totem: self.skill.has_level(Skill.foraging, 9) & self.has(Material.hardwood) & self.has(ArtisanGood.truffle_oil) & self.has(ArtisanGood.pine_tar), - Craftable.scarecrow: self.skill.has_farming_level(1) & self.has(Material.wood) & self.has(Material.coal) & self.has(Material.fiber), - Craftable.staircase: self.skill.has_level(Skill.mining, 2) & self.has(Material.stone), + Decoration.rotten_plant: self.has(Lighting.jack_o_lantern) & self.season.has(Season.winter), Fertilizer.basic: (self.has(Material.sap) & self.skill.has_farming_level(1)) | (self.time.has_lived_months(1) & self.money.can_spend_at(Region.pierre_store, 100)), Fertilizer.deluxe: False_(), Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), @@ -278,6 +288,8 @@ def __post_init__(self): Fish.periwinkle: self.skill.can_crab_pot(Region.town), Fish.shrimp: self.skill.can_crab_pot(Region.beach), Fish.snail: self.skill.can_crab_pot(Region.town), + Fishing.curiosity_lure: self.combat.can_kill_monster(all_monsters_by_name[Monster.mummy]), + Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200), Forageable.blackberry: self.tool.can_forage(Season.fall), Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), Forageable.cave_carrot: self.tool.can_forage(Generic.any, Region.mines_floor_10, True), @@ -309,19 +321,31 @@ def __post_init__(self): Forageable.wild_horseradish: self.tool.can_forage(Season.spring), Forageable.wild_plum: self.tool.can_forage(Season.fall), Forageable.winter_root: self.tool.can_forage(Season.winter, Region.forest, True), - Fossil.bone_fragment: self.region.can_reach(Region.dig_site), + Fossil.bone_fragment: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), + Fossil.fossilized_leg: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), + Fossil.fossilized_ribs: self.region.can_reach(Region.island_south) & self.tool.has_tool(Tool.hoe), + Fossil.fossilized_skull: self.action.can_open_geode(Geode.golden_coconut), + Fossil.fossilized_spine: self.fishing.can_fish_at(Region.dig_site), + Fossil.fossilized_tail: self.action.can_pan_at(Region.dig_site), + Fossil.mummified_bat: self.region.can_reach(Region.volcano_floor_10), + Fossil.mummified_frog: self.region.can_reach(Region.island_east) & self.tool.has_tool(Tool.scythe), + Fossil.snake_skull: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.hoe), + Fossil.snake_vertebrae: self.region.can_reach(Region.island_west) & self.tool.has_tool(Tool.hoe), Geode.artifact_trove: self.has(Geode.omni) & self.region.can_reach(Region.desert), Geode.frozen: self.mine.can_mine_in_the_mines_floor_41_80(), Geode.geode: self.mine.can_mine_in_the_mines_floor_1_40(), Geode.golden_coconut: self.region.can_reach(Region.island_north), Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.buildings.has_building(Building.fish_pond)), - Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_do_panning() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.buildings.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), + Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_pan() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.buildings.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), Gift.bouquet: self.relationship.has_hearts(Generic.bachelor, 8) & self.money.can_spend_at(Region.pierre_store, 100), Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), - Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Craftable.rain_totem), + Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Consumable.rain_totem), Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), + Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months(), + Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200), Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), + Ingredient.qi_seasoning: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 10), Ingredient.rice: self.money.can_spend_at(Region.pierre_store, 200) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), Ingredient.sugar: self.money.can_spend_at(Region.pierre_store, 100) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.beet)), Ingredient.vinegar: self.money.can_spend_at(Region.pierre_store, 200), @@ -349,9 +373,11 @@ def __post_init__(self): Machine.solar_panel: self.received("Solar Panel Recipe") & self.has(MetalBar.quartz) & self.has(MetalBar.iron) & self.has(MetalBar.gold), Machine.tapper: self.skill.has_level(Skill.foraging, 3) & self.has(Material.wood) & self.has(MetalBar.copper), Machine.worm_bin: self.skill.has_level(Skill.fishing, 8) & self.has(Material.hardwood) & self.has(MetalBar.gold) & self.has(MetalBar.iron) & self.has(Material.fiber), + Machine.enricher: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 20), + Machine.pressure_nozzle: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 20), Material.cinder_shard: self.region.can_reach(Region.volcano_floor_5), Material.clay: self.region.can_reach_any([Region.farm, Region.beach, Region.quarry]) & self.tool.has_tool(Tool.hoe), - Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.action.can_do_panning(), + Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.action.can_pan(), Material.fiber: True_(), Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_west)), Material.sap: self.ability.can_chop_trees(), @@ -369,18 +395,24 @@ def __post_init__(self): MetalBar.iron: self.can_smelt(Ore.iron), MetalBar.quartz: self.can_smelt("Quartz") | self.can_smelt("Fire Quartz") | (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), MetalBar.radioactive: self.can_smelt(Ore.radioactive), - Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), - Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), + Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.iridium: self.mine.can_mine_in_the_skull_cavern(), - Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_do_panning(), + Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), + Seed.mixed: self.tool.has_tool(Tool.scythe) & self.region.can_reach_all([Region.farm, Region.forest, Region.town]), Trash.broken_cd: self.skill.can_crab_pot(), Trash.broken_glasses: self.skill.can_crab_pot(), Trash.driftwood: self.skill.can_crab_pot(), Trash.joja_cola: self.money.can_spend_at(Region.saloon, 75), Trash.soggy_newspaper: self.skill.can_crab_pot(), Trash.trash: self.skill.can_crab_pot(), + TreeSeed.acorn: self.skill.has_level(Skill.foraging, 1) & self.ability.can_chop_trees(), + TreeSeed.mahogany: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.iron) & self.skill.has_level(Skill.foraging, 1), + TreeSeed.maple: self.skill.has_level(Skill.foraging, 1) & self.ability.can_chop_trees(), + TreeSeed.mushroom: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 5), + TreeSeed.pine: self.skill.has_level(Skill.foraging, 1) & self.ability.can_chop_trees(), Vegetable.tea_leaves: self.has(Sapling.tea) & self.time.has_lived_months(2) & self.season.has_any_not_winter(), WaterItem.clam: self.tool.can_forage(Generic.any, Region.beach), WaterItem.cockle: self.tool.can_forage(Generic.any, Region.beach), @@ -404,6 +436,12 @@ def __post_init__(self): obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() self.item_rules[recipe] = obtention_rule | cooking_rule + # For some recipes, the crafted item can be obtained directly, so we either craft it or get it + for recipe in self.crafting_rules: + crafting_rule = self.crafting_rules[recipe] + obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() + self.item_rules[recipe] = obtention_rule | crafting_rule + self.buildings.initialize_rules() self.buildings.update_rules(self.mod.buildings.get_modded_building_rules()) @@ -549,9 +587,12 @@ def can_catch_fish(self, fish: FishItem) -> StardewRule: def can_catch_every_fish(self) -> StardewRule: rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] + exclude_island = self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true + exclude_extended_family = self.options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_board_qi for fish in all_fish: - if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true and \ - fish in island_fish: + if exclude_island and fish in island_fish: + continue + if exclude_extended_family and fish in extended_family: continue rules.append(self.can_catch_fish(fish)) return And(rules) @@ -613,7 +654,7 @@ def can_complete_field_office(self) -> StardewRule: leg_and_snake_skull = dig_site ribs_and_spine = self.region.can_reach(Region.island_south) skull = self.action.can_open_geode(Geode.golden_coconut) - tail = self.action.can_do_panning() & dig_site + tail = self.action.can_pan() & dig_site frog = self.region.can_reach(Region.island_east) bat = self.region.can_reach(Region.volcano_floor_5) snake_vertebrae = self.region.can_reach(Region.island_west) @@ -690,9 +731,9 @@ def can_succeed_grange_display(self) -> StardewRule: return True_() animal_rule = self.has_animal(Generic.any) artisan_rule = self.artisan.can_keg(Generic.any) | self.artisan.can_preserves_jar(Generic.any) - cooking_rule = True_() # Salads at the bar are good enough + cooking_rule = self.money.can_spend_at(Region.saloon, 220) # Salads at the bar are good enough fish_rule = self.skill.can_fish([], 50) - forage_rule = True_() # Hazelnut always available since the grange display is in fall + forage_rule = self.region.can_reach_any([Region.forest, Region.backwoods]) # Hazelnut always available since the grange display is in fall mineral_rule = self.action.can_open_geode(Generic.any) # More than half the minerals are good enough good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, Fruit.pomegranate, @@ -802,7 +843,7 @@ def has_walnut(self, number: int) -> StardewRule: return reach_entire_island gems = [Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz] return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ - self.ability.can_fish_perfectly() & self.has(Craftable.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) + self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) def has_everything(self, all_progression_items: Set[str]) -> StardewRule: all_regions = [region.name for region in vanilla_regions] @@ -827,7 +868,11 @@ def can_ship(self, item: str) -> StardewRule: def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " all_items_to_ship = [] + include_island = self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_false + include_qi = self.options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_qi for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: - all_items_to_ship.append(location.name[len(shipsanity_prefix):]) + if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ + (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): + all_items_to_ship.append(location.name[len(shipsanity_prefix):]) return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index aaff12e2e0f8..01aa0abe8af8 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,22 +1,31 @@ from typing import Iterable +from .has_logic import HasLogic +from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic from ..stardew_rule import StardewRule, And, Or, Reach, Count, True_ +from ..strings.currency_names import Currency MONEY_PER_MONTH = 15000 DISPOSABLE_INCOME_DIVISOR = 5 +qi_gem_rewards = ["100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", "25 Qi Gems", "20 Qi Gems", "10 Qi Gems"] + class MoneyLogic: player: int starting_money_option: int + received: ReceivedLogic + has: HasLogic region: RegionLogic time: TimeLogic - def __init__(self, player: int, starting_money_option: int, region: RegionLogic, time: TimeLogic): + def __init__(self, player: int, starting_money_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): self.player = player self.starting_money_option = starting_money_option + self.received = received + self.has = has self.region = region self.time = time @@ -33,4 +42,15 @@ def can_spend(self, amount: int) -> StardewRule: def can_spend_at(self, region: str, amount: int) -> StardewRule: return self.region.can_reach(region) & self.can_spend(amount) + def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: + if amount == 0: + return True_() + if currency == Currency.money: + return self.can_spend_at(region, amount) + if currency == Currency.qi_gem: + number_rewards = min(10, max(1, (amount // 10) + 2)) + return self.received(qi_gem_rewards, number_rewards) + + return self.region.can_reach(region) & self.has(currency) + diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index ea1a3986ded8..989c60b41b48 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -45,7 +45,7 @@ def can_find_museum_item(self, item: MuseumItem) -> StardewRule: # extra_rule = True_() pan_rule = False_() if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": - pan_rule = self.action.can_do_panning() + pan_rule = self.action.can_pan() return pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule def can_find_museum_artifacts(self, number: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 8613b66588e9..705578d9e816 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -13,7 +13,7 @@ from ..mods.logic.magic_logic import MagicLogic from ..mods.logic.mod_skills_levels import get_mod_skill_levels from ..stardew_rule import StardewRule, True_, Or -from ..strings.craftable_names import Craftable +from worlds.stardew_valley.strings.craftable_names import Craftable, Fishing from ..strings.generic_names import Generic from ..strings.machine_names import Machine from ..strings.performance_names import Performance @@ -155,7 +155,7 @@ def can_fish(self, regions: Union[str, List[str]] = None, difficulty: int = 0) - return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule def can_crab_pot(self, region: str = Generic.any) -> StardewRule: - crab_pot_rule = self.has(Craftable.bait) + crab_pot_rule = self.has(Fishing.bait) if self.skill_option == options.SkillProgression.option_progressive: crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) else: diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index cf3379bdeba9..617776554d86 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -4,7 +4,7 @@ from ...logic.received_logic import ReceivedLogic from ...logic.skill_logic import SkillLogic from ...logic.tool_logic import ToolLogic -from ...strings.craftable_names import Craftable +from ...strings.craftable_names import Bomb from ...strings.performance_names import Performance from ...strings.skill_names import Skill from ...strings.tool_names import Tool, ToolMaterial @@ -40,7 +40,7 @@ def can_reach_woods_depth(self, depth: int) -> StardewRule: tier = int(depth / 25) + 1 rules = [] if depth > 10: - rules.append(self.has(Craftable.bomb) | self.tool.has_tool(Tool.axe, ToolMaterial.iridium)) + rules.append(self.has(Bomb.bomb) | self.tool.has_tool(Tool.axe, ToolMaterial.iridium)) if depth > 30: rules.append(self.received(ModTransportation.woods_obelisk)) if depth > 50: diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 801e5705e3df..8b8852f00e60 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -103,9 +103,9 @@ def can_earn_socializing_skill_level(self, level: int) -> StardewRule: def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: if level >= 6: - return self.action.can_do_panning() | self.tool.has_tool(Tool.hoe, ToolMaterial.gold) + return self.action.can_pan() | self.tool.has_tool(Tool.hoe, ToolMaterial.gold) else: - return self.action.can_do_panning() | self.tool.has_tool(Tool.hoe, ToolMaterial.basic) + return self.action.can_pan() | self.tool.has_tool(Tool.hoe, ToolMaterial.basic) def can_earn_cooking_skill_level(self, level: int) -> StardewRule: if level >= 6: diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index d1ecdca1f057..a02c52c24e56 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -4,7 +4,7 @@ from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.wallet_logic import WalletLogic -from ...strings.craftable_names import Craftable +from ...strings.craftable_names import Consumable, Edible from ...strings.food_names import Meal from ...strings.material_names import Material from ...strings.monster_drop_names import Loot @@ -37,9 +37,9 @@ def get_modded_special_orders_rules(self, vanilla_rules): ModSpecialOrder.junas_monster_mash: self.relationship.has_hearts(ModNPC.juna, 4) & vanilla_rules[SpecialOrder.a_curious_substance] & self.wallet.has_rusty_key() & - self.region.can_reach(Region.forest) & self.has(Craftable.monster_musk) & + self.region.can_reach(Region.forest) & self.has(Consumable.monster_musk) & self.has("Energy Tonic") & self.has(Material.sap) & self.has(Loot.bug_meat) & - self.has(Craftable.oil_of_garlic) & self.has(Meal.strange_bun) + self.has(Edible.oil_of_garlic) & self.has(Meal.strange_bun) }) return special_orders diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index d5a551d977cb..376e4c022c86 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -20,7 +20,7 @@ from .strings.ap_names.transport_names import Transportation from .strings.artisan_good_names import ArtisanGood from .strings.calendar_names import Weekday -from .strings.craftable_names import Craftable +from worlds.stardew_valley.strings.craftable_names import Bomb from .strings.material_names import Material from .strings.metal_names import MetalBar from .strings.season_names import Season @@ -341,7 +341,7 @@ def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_optio set_boat_repair_rules(logic, multi_world, player) set_island_parrot_rules(logic, multi_world, player) MultiWorldRules.add_rule(multi_world.get_location("Open Professor Snail Cave", player), - logic.has(Craftable.cherry_bomb).simplify()) + logic.has(Bomb.cherry_bomb).simplify()) MultiWorldRules.add_rule(multi_world.get_location("Complete Island Field Office", player), logic.can_complete_field_office().simplify()) diff --git a/worlds/stardew_valley/strings/animal_product_names.py b/worlds/stardew_valley/strings/animal_product_names.py index 6656e70e580d..f89b610ae89d 100644 --- a/worlds/stardew_valley/strings/animal_product_names.py +++ b/worlds/stardew_valley/strings/animal_product_names.py @@ -1,24 +1,30 @@ class AnimalProduct: any_egg = "Any Egg" - chicken_egg = "Chicken Egg" - egg = "Egg" brown_egg = "Egg (Brown)" - large_egg = "Large Egg" - large_brown_egg = "Large Egg (Brown)" - milk = "Milk" - large_milk = "Large Milk" + chicken_egg = "Chicken Egg" cow_milk = "Cow Milk" - wool = "Wool" - goat_milk = "Goat Milk" - large_goat_milk = "Large Goat Milk" + dinosaur_egg = "Dinosaur Egg" duck_egg = "Duck Egg" duck_feather = "Duck Feather" - void_egg = "Void Egg" - truffle = "Truffle" + egg = "Egg" + goat_milk = "Goat Milk" + golden_egg = "Golden Egg" + large_brown_egg = "Large Egg (Brown)" + large_egg = "Large Egg" + large_goat_milk = "Large Goat Milk" + large_milk = "Large Milk" + milk = "Milk" + ostrich_egg = "Ostrich Egg" rabbit_foot = "Rabbit's Foot" roe = "Roe" - sturgeon_roe = "Sturgeon Roe" - ostrich_egg = "Ostrich Egg" - dinosaur_egg = "Dinosaur Egg" + slime_egg_blue = "Blue Slime Egg" + slime_egg_green = "Green Slime Egg" + slime_egg_purple = "Purple Slime Egg" + slime_egg_red = "Red Slime Egg" + slime_egg_tiger = "Tiger Slime Egg" squid_ink = "Squid Ink" + sturgeon_roe = "Sturgeon Roe" + truffle = "Truffle" + void_egg = "Void Egg" + wool = "Wool" diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index a1ee15b12fde..bada4c6d8a20 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -1,16 +1,139 @@ -class Craftable: - bait = "Bait" +class Bomb: cherry_bomb = "Cherry Bomb" bomb = "Bomb" mega_bomb = "Mega Bomb" - staircase = "Staircase" - scarecrow = "Scarecrow" - rain_totem = "Rain Totem" - flute_block = "Flute Block" + + +class Fence: + gate = "Gate" + wood = "Wood Fence" + stone = "Stone Fence" + iron = "Iron Fence" + hardwood = "Hardwood Fence" + + +class Sprinkler: + basic = "Sprinkler" + quality = "Quality Sprinkler" + iridium = "Iridium Sprinkler" + + +class WildSeeds: + spring = "Spring Seeds" + summer = "Summer Seeds" + fall = "Fall Seeds" + winter = "Winter Seeds" + ancient = "Ancient Seeds" + grass_starter = "Grass Starter" + tea_sapling = "Tea Sapling" + fiber = "Fiber Seeds" + + +class Floor: + wood = "Wood Floor" + rustic = "Rustic Plank Floor" + straw = "Straw Floor" + weathered = "Weathered Floor" + crystal = "Crystal Floor" + stone = "Stone Floor" + stone_walkway = "Stone Walkway Floor" + brick = "Brick Floor" + wood_path = "Wood Path" + gravel_path = "Gravel Path" + cobblestone_path = "Cobblestone Path" + stepping_stone_path = "Stepping Stone Path" + crystal_path = "Crystal Path" + + +class Fishing: + spinner = "Spinner" + trap_bobber = "Trap Bobber" + cork_bobber = "Cork Bobber" + quality_bobber = "Quality Bobber" + treasure_hunter = "Treasure Hunter" + dressed_spinner = "Dressed Spinner" + barbed_hook = "Barbed Hook" + magnet = "Magnet" + bait = "Bait" + wild_bait = "Wild Bait" + magic_bait = "Magic Bait" + lead_bobber = "Lead Bobber" + curiosity_lure = "Curiosity Lure" + + +class Ring: + hot_java_ring = "Hot Java Ring" + sturdy_ring = "Sturdy Ring" + warrior_ring = "Warrior Ring" + ring_of_yoba = "Ring of Yoba" + thorns_ring = "Thorns Ring" + glowstone_ring = "Glowstone Ring" + iridium_band = "Iridium Band" + wedding_ring = "Wedding Ring" + + +class Edible: + field_snack = "Field Snack" + bug_steak = "Bug Steak" life_elixir = "Life Elixir" - monster_musk = "Monster Musk" oil_of_garlic = "Oil of Garlic" +class Consumable: + monster_musk = "Monster Musk" + fairy_dust = "Fairy Dust" + warp_totem_beach = "Warp Totem: Beach" + warp_totem_mountains = "Warp Totem: Mountains" + warp_totem_farm = "Warp Totem: Farm" + warp_totem_desert = "Warp Totem: Desert" + warp_totem_island = "Warp Totem: Island" + rain_totem = "Rain Totem" + + +class Lighting: + torch = "Torch" + campfire = "Campfire" + wooden_brazier = "Wooden Brazier" + stone_brazier = "Stone Brazier" + gold_brazier = "Gold Brazier" + carved_brazier = "Carved Brazier" + stump_brazier = "Stump Brazier" + barrel_brazier = "Barrel Brazier" + skull_brazier = "Skull Brazier" + marble_brazier = "Marble Brazier" + wood_lamp_post = "Wood Lamp-post" + iron_lamp_post = "Iron Lamp-post" + jack_o_lantern = "Jack-O-Lantern" + +class Furniture: + tub_o_flowers = "Tub o' Flowers" + wicked_statue = "Wicked Statue" + flute_block = "Flute Block" + drum_block = "Drum Block" + + +class Storage: + chest = "Chest" + stone_chest = "Stone Chest" + + +class Sign: + wood = "Wood Sign" + stone = "Stone Sign" + dark = "Dark Sign" + +class Craftable: + garden_pot = "Garden Pot" + scarecrow = "Scarecrow" + deluxe_scarecrow = "Deluxe Scarecrow" + staircase = "Staircase" + explosive_ammo = "Explosive Ammo" + transmute_fe = "Transmute (Fe)" + transmute_au = "Transmute (Au)" + mini_jukebox = "Mini-Jukebox" + mini_obelisk = "Mini-Obelisk" + farm_computer = "Farm Computer" + hopper = "Hopper" + cookout_kit = "Cookout Kit" diff --git a/worlds/stardew_valley/strings/crop_names.py b/worlds/stardew_valley/strings/crop_names.py index 2b5ea4d32768..646f19dd4bce 100644 --- a/worlds/stardew_valley/strings/crop_names.py +++ b/worlds/stardew_valley/strings/crop_names.py @@ -38,6 +38,7 @@ class Vegetable: any = "Any Vegetable" parsnip = veggie("Parsnip") garlic = veggie("Garlic") + bok_choy = "Bok Choy" wheat = "Wheat" potato = veggie("Potato") corn = veggie("Corn") diff --git a/worlds/stardew_valley/strings/currency_names.py b/worlds/stardew_valley/strings/currency_names.py new file mode 100644 index 000000000000..bb2d9f6b0fcb --- /dev/null +++ b/worlds/stardew_valley/strings/currency_names.py @@ -0,0 +1,8 @@ +class Currency: + golden_walnut = "Golden Walnut" + qi_gem = "Qi Gem" + star_token = "Star Token" + money = "Money" + cinder_shard = "Cinder Shard" + + diff --git a/worlds/stardew_valley/strings/decoration_names.py b/worlds/stardew_valley/strings/decoration_names.py new file mode 100644 index 000000000000..150a106c6a20 --- /dev/null +++ b/worlds/stardew_valley/strings/decoration_names.py @@ -0,0 +1,2 @@ +class Decoration: + rotten_plant = "Rotten Plant" diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 1b47756210d6..511745265be0 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -12,6 +12,7 @@ class Fish: crimsonfish = "Crimsonfish" dorado = "Dorado" eel = "Eel" + flounder = "Flounder" glacierfish = "Glacierfish" glacierfish_jr = "Glacierfish Jr." largemouth_bass = "Largemouth Bass" @@ -20,6 +21,7 @@ class Fish: legend_ii = "Legend II" lionfish = "Lionfish" lobster = "Lobster" + midnight_carp = "Midnight Carp" ms_angler = "Ms. Angler" mussel = "Mussel" mussel_node = "Mussel Node" @@ -29,8 +31,10 @@ class Fish: periwinkle = "Periwinkle" pufferfish = "Pufferfish" radioactive_carp = "Radioactive Carp" + rainbow_trout = "Rainbow Trout" salmon = "Salmon" sardine = "Sardine" + sea_cucumber = "Sea Cucumber" shrimp = "Shrimp" smallmouth_bass = "Smallmouth Bass" snail = "Snail" @@ -64,5 +68,10 @@ class Trash: soggy_newspaper = "Soggy Newspaper" +class WaterChest: + fishing_chest = "Fishing Chest" + treasure = "Treasure Chest" + + diff --git a/worlds/stardew_valley/strings/flower_names.py b/worlds/stardew_valley/strings/flower_names.py index a804682f1b55..934e193c89a1 100644 --- a/worlds/stardew_valley/strings/flower_names.py +++ b/worlds/stardew_valley/strings/flower_names.py @@ -1,3 +1,5 @@ class Flower: + fairy_rose = "Fairy Rose" sunflower = "Sunflower" poppy = "Poppy" + blue_jazz = "Blue Jazz" diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index 670751e703f4..cc5ff6a8edad 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -1,4 +1,7 @@ class Meal: + banana_pudding = "Banana Pudding" + poi = "Poi" + mango_sticky_rice = "Mango Sticky Rice" algae_soup = "Algae Soup" artichoke_dip = "Artichoke Dip" autumn_bounty = "Autumn's Bounty" @@ -17,12 +20,14 @@ class Meal: cookie = "Cookie" crab_cakes = "Crab Cakes" cranberry_candy = "Cranberry Candy" + cranberry_sauce = "Cranberry Sauce" crispy_bass = "Crispy Bass" dish_o_the_sea = "Dish O' The Sea" eggplant_parmesan = "Eggplant Parmesan" escargot = "Escargot" farmer_lunch = "Farmer's Lunch" fiddlehead_risotto = "Fiddlehead Risotto" + fish_stew = "Fish Stew" fish_taco = "Fish Taco" fried_calamari = "Fried Calamari" fried_eel = "Fried Eel" @@ -32,6 +37,8 @@ class Meal: glazed_yams = "Glazed Yams" hashbrowns = "Hashbrowns" ice_cream = "Ice Cream" + lobster_bisque = "Lobster Bisque" + lucky_lunch = "Lucky Lunch" maki_roll = "Maki Roll" maple_bar = "Maple Bar" miners_treat = "Miner's Treat" @@ -45,6 +52,8 @@ class Meal: plum_pudding = "Plum Pudding" poppyseed_muffin = "Poppyseed Muffin" pumpkin_pie = "Pumpkin Pie" + pumpkin_soup = "Pumpkin Soup" + radish_salad = "Radish Salad" red_plate = "Red Plate" rhubarb_pie = "Rhubarb Pie" rice_pudding = "Rice Pudding" @@ -53,18 +62,25 @@ class Meal: salad = "Salad" salmon_dinner = "Salmon Dinner" sashimi = "Sashimi" + seafoam_pudding = "Seafoam Pudding" + shrimp_cocktail = "Shrimp Cocktail" spaghetti = "Spaghetti" + spicy_eel = "Spicy Eel" + squid_ink_ravioli = "Squid Ink Ravioli" stir_fry = "Stir Fry" strange_bun = "Strange Bun" stuffing = "Stuffing" + super_meal = "Super Meal" survival_burger = "Survival Burger" + tom_kha_soup = "Tom Kha Soup" tortilla = "Tortilla" tropical_curry = "Tropical Curry" + trout_soup = "Trout Soup" vegetable_medley = "Vegetable Medley" class Beverage: - pina_colada = "Piña Colada" + pina_colada = "Pina Colada" ginger_ale = "Ginger Ale" coffee = "Coffee" triple_shot_espresso = "Triple Shot Espresso" diff --git a/worlds/stardew_valley/strings/gift_names.py b/worlds/stardew_valley/strings/gift_names.py index 0baf31d5dbfd..8b000570470c 100644 --- a/worlds/stardew_valley/strings/gift_names.py +++ b/worlds/stardew_valley/strings/gift_names.py @@ -1,6 +1,8 @@ class Gift: bouquet = "Bouquet" - wilted_bouquet = "Wilted Bouquet" - pearl = "Pearl" golden_pumpkin = "Golden Pumpkin" mermaid_pendant = "Mermaid's Pendant" + pearl = "Pearl" + tea_set = "Tea Set" + void_ghost_pendant = "Void Ghost Pendant" + wilted_bouquet = "Wilted Bouquet" diff --git a/worlds/stardew_valley/strings/ingredient_names.py b/worlds/stardew_valley/strings/ingredient_names.py index 22271d661587..5537c7353c42 100644 --- a/worlds/stardew_valley/strings/ingredient_names.py +++ b/worlds/stardew_valley/strings/ingredient_names.py @@ -4,3 +4,4 @@ class Ingredient: oil = "Oil" rice = "Rice" vinegar = "Vinegar" + qi_seasoning = "Qi Seasoning" diff --git a/worlds/stardew_valley/strings/machine_names.py b/worlds/stardew_valley/strings/machine_names.py index 55d6cef79401..9a388dece348 100644 --- a/worlds/stardew_valley/strings/machine_names.py +++ b/worlds/stardew_valley/strings/machine_names.py @@ -1,22 +1,29 @@ class Machine: bee_house = "Bee House" + bone_mill = "Bone Mill" cask = "Cask" charcoal_kiln = "Charcoal Kiln" cheese_press = "Cheese Press" + coffee_maker = "Coffee Maker" + crab_pot = "Crab Pot" + crystalarium = "Crystalarium" furnace = "Furnace" geode_crusher = "Geode Crusher" + heavy_tapper = "Heavy Tapper" keg = "Keg" lightning_rod = "Lightning Rod" loom = "Loom" mayonnaise_machine = "Mayonnaise Machine" oil_maker = "Oil Maker" + ostrich_incubator = "Ostrich Incubator" preserves_jar = "Preserves Jar" recycling_machine = "Recycling Machine" seed_maker = "Seed Maker" + slime_egg_press = "Slime Egg-Press" + slime_incubator = "Slime Incubator" solar_panel = "Solar Panel" tapper = "Tapper" worm_bin = "Worm Bin" - coffee_maker = "Coffee Maker" - crab_pot = "Crab Pot" - ostrich_incubator = "Ostrich Incubator" + enricher = "Enricher" + pressure_nozzle = "Pressure Nozzle" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 67aefc692a56..75c08d48d3e1 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -16,6 +16,12 @@ class MetalBar: class Mineral: + earth_crystal = "Earth Crystal" + fire_quartz = "Fire Quartz" + marble = "Marble" + prismatic_shard = "Prismatic Shard" + diamond = "Diamond" + frozen_tear = "Frozen Tear" aquamarine = "Aquamarine" topaz = "Topaz" jade = "Jade" @@ -25,11 +31,19 @@ class Mineral: class Artifact: - pass # Eventually this will be the artifact names + dwarf_gadget = "Dwarf Gadget" + ancient_seed = "Ancient Seed" class Fossil: bone_fragment = "Bone Fragment" - - + fossilized_leg = "Fossilized Leg" + fossilized_ribs = "Fossilized Ribs" + fossilized_skull = "Fossilized Skull" + fossilized_spine = "Fossilized Spine" + fossilized_tail = "Fossilized Tail" + mummified_bat = "Mummified Bat" + mummified_frog = "Mummified Frog" + snake_skull = "Snake Skull" + snake_vertebrae = "Snake Vertebrae" diff --git a/worlds/stardew_valley/strings/seed_names.py b/worlds/stardew_valley/strings/seed_names.py index 6d8fe3f3defb..d29810ad26d6 100644 --- a/worlds/stardew_valley/strings/seed_names.py +++ b/worlds/stardew_valley/strings/seed_names.py @@ -1,10 +1,23 @@ class Seed: - sunflower = "Sunflower Seeds" - tomato = "Tomato Seeds" - melon = "Melon Seeds" - wheat = "Wheat Seeds" + coffee = "Coffee Bean" garlic = "Garlic Seeds" + jazz = "Jazz Seeds" + melon = "Melon Seeds" + mixed = "Mixed Seeds" pineapple = "Pineapple Seeds" - taro = "Taro Tuber" - coffee = "Coffee Bean" + poppy = "Poppy Seeds" qi_bean = "Qi Bean" + spangle = "Spangle Seeds" + sunflower = "Sunflower Seeds" + taro = "Taro Tuber" + tomato = "Tomato Seeds" + tulip = "Tulip Bulb" + wheat = "Wheat Seeds" + + +class TreeSeed: + acorn = "Acorn" + maple = "Maple Seed" + pine = "Pine Cone" + mahogany = "Mahogany Seed" + mushroom = "Mushroom Tree Seed" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 85934e6998e0..7d3090659f97 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -23,6 +23,7 @@ class TestBaseItemGeneration(SVTestBase): options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, + options.Shipsanity.internal_name: options.Shipsanity.option_everything, } def test_all_progression_items_are_added_to_the_pool(self): @@ -69,7 +70,8 @@ class TestNoGingerIslandItemGeneration(SVTestBase): options = { options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.Shipsanity.internal_name: options.Shipsanity.option_everything, } def test_all_progression_items_except_island_are_added_to_the_pool(self): diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index e175c354ca1e..c77ce7647a1a 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -1,11 +1,12 @@ import unittest from test.general import setup_solo_multiworld -from .. import StardewValleyWorld, StardewLocation -from ..data.bundle_data import BundleItem, all_bundle_items_except_money +from . import SVTestBase +from .. import StardewValleyWorld +from ..data.bundle_data import all_bundle_items_except_money from ..stardew_rule import MISSING_ITEM, False_ -multi_world = setup_solo_multiworld(StardewValleyWorld) +multi_world = setup_solo_multiworld(StardewValleyWorld, SVTestBase.allsanity_options_without_mods()) world = multi_world.worlds[1] logic = world.logic diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 01ed2481d386..2eb8d94fa224 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -604,6 +604,8 @@ def test_all_shipsanity_locations_require_shipping_bin(self): 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) - self.assertTrue(self.world.logic.region.can_reach_location(location.name)(self.multiworld.state)) + shipsanity_rule = self.world.logic.region.can_reach_location(location.name) + can_reach_shipsanity_location = shipsanity_rule(self.multiworld.state) + self.assertTrue(can_reach_shipsanity_location) self.remove(bin_item) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 0c52ffb5dc1f..ba9669453b8a 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -49,10 +49,11 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi class TestBaseItemGeneration(SVTestBase): options = { - Friendsanity.internal_name: Friendsanity.option_all_with_marriage, - SeasonRandomization.internal_name: SeasonRandomization.option_progressive, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - Mods.internal_name: all_mods + options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, + options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Mods.internal_name: mod_list } def test_all_progression_items_are_added_to_the_pool(self): @@ -72,10 +73,11 @@ def test_all_progression_items_are_added_to_the_pool(self): class TestNoGingerIslandModItemGeneration(SVTestBase): options = { - Friendsanity.internal_name: Friendsanity.option_all_with_marriage, - SeasonRandomization.internal_name: SeasonRandomization.option_progressive, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - Mods.internal_name: all_mods + options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Mods.internal_name: mod_list } def test_all_progression_items_except_island_are_added_to_the_pool(self): From f13731339fe2ad3d07750496dfde39a580a3cebd Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 21 Aug 2023 17:55:49 -0400 Subject: [PATCH 051/482] - Fix a bug with logic tests --- worlds/stardew_valley/test/TestLogic.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index c77ce7647a1a..04c5181c83be 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -1,12 +1,11 @@ import unittest -from test.general import setup_solo_multiworld -from . import SVTestBase +from . import SVTestBase, setup_solo_multiworld from .. import StardewValleyWorld from ..data.bundle_data import all_bundle_items_except_money from ..stardew_rule import MISSING_ITEM, False_ -multi_world = setup_solo_multiworld(StardewValleyWorld, SVTestBase.allsanity_options_without_mods()) +multi_world = setup_solo_multiworld(SVTestBase.allsanity_options_without_mods()) world = multi_world.worlds[1] logic = world.logic From 618158a7172a9ebc6ec1e3a72e400daf065fff8e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 21 Aug 2023 19:05:40 -0400 Subject: [PATCH 052/482] - Added Journal Scrap into logic --- worlds/stardew_valley/logic/logic.py | 16 ++++++++-------- .../stardew_valley/strings/forageable_names.py | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index ffe5d7a5fedd..9970139981d2 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -306,6 +306,7 @@ def __post_init__(self): Forageable.hay: self.buildings.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), Forageable.hazelnut: self.tool.can_forage(Season.fall), Forageable.holly: self.tool.can_forage(Season.winter), + Forageable.journal_scrap: self.region.can_reach_all([Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10]) & self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), Forageable.leek: self.tool.can_forage(Season.spring), Forageable.magma_cap: self.tool.can_forage(Generic.any, Region.volcano_floor_5), Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods), @@ -649,15 +650,14 @@ def has_fertilizer(self, tier: int) -> StardewRule: def can_complete_field_office(self) -> StardewRule: field_office = self.region.can_reach(Region.field_office) professor_snail = self.received("Open Professor Snail Cave") - dig_site = self.region.can_reach(Region.dig_site) tools = self.tool.has_tool(Tool.pickaxe) & self.tool.has_tool(Tool.hoe) & self.tool.has_tool(Tool.scythe) - leg_and_snake_skull = dig_site - ribs_and_spine = self.region.can_reach(Region.island_south) - skull = self.action.can_open_geode(Geode.golden_coconut) - tail = self.action.can_pan() & dig_site - frog = self.region.can_reach(Region.island_east) - bat = self.region.can_reach(Region.volcano_floor_5) - snake_vertebrae = self.region.can_reach(Region.island_west) + leg_and_snake_skull = self.has(Fossil.fossilized_leg) & self.has(Fossil.snake_skull) + ribs_and_spine = self.has(Fossil.fossilized_ribs) & self.has(Fossil.fossilized_spine) + skull = self.has(Fossil.fossilized_skull) + tail = self.has(Fossil.fossilized_tail) + frog = self.has(Fossil.mummified_frog) + bat = self.has(Fossil.mummified_bat) + snake_vertebrae = self.has(Fossil.snake_vertebrae) return field_office & professor_snail & tools & leg_and_snake_skull & ribs_and_spine & skull & tail & frog & bat & snake_vertebrae def can_complete_community_center(self) -> StardewRule: diff --git a/worlds/stardew_valley/strings/forageable_names.py b/worlds/stardew_valley/strings/forageable_names.py index b29ff317cf77..e482d3ef1558 100644 --- a/worlds/stardew_valley/strings/forageable_names.py +++ b/worlds/stardew_valley/strings/forageable_names.py @@ -14,6 +14,7 @@ class Forageable: hay = "Hay" hazelnut = "Hazelnut" holly = "Holly" + journal_scrap = "Journal Scrap" leek = "Leek" magma_cap = "Magma Cap" morel = "Morel" From 079368fb292ec6b67f18ba73dd7706e4e718e668 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 24 Aug 2023 11:58:53 -0400 Subject: [PATCH 053/482] - Missing Bundle and changes for recursive region access update --- BaseClasses.py | 1 + worlds/stardew_valley/__init__.py | 38 +- worlds/stardew_valley/bundles.py | 7 +- worlds/stardew_valley/data/bundle_data.py | 360 ++++++++++-------- worlds/stardew_valley/data/items.csv | 4 +- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/items.py | 7 +- worlds/stardew_valley/logic/building_logic.py | 3 +- worlds/stardew_valley/logic/logic.py | 13 + worlds/stardew_valley/logic/time_logic.py | 3 +- worlds/stardew_valley/regions.py | 10 +- worlds/stardew_valley/rules.py | 7 + .../ap_names/community_upgrade_names.py | 2 + .../strings/ap_names/event_names.py | 4 + .../stardew_valley/strings/entrance_names.py | 3 + worlds/stardew_valley/strings/gift_names.py | 1 + worlds/stardew_valley/strings/region_names.py | 3 + worlds/stardew_valley/test/TestGeneration.py | 6 +- worlds/stardew_valley/test/TestLogic.py | 1 - worlds/stardew_valley/test/TestRules.py | 3 + 20 files changed, 281 insertions(+), 197 deletions(-) create mode 100644 worlds/stardew_valley/strings/ap_names/community_upgrade_names.py create mode 100644 worlds/stardew_valley/strings/ap_names/event_names.py diff --git a/BaseClasses.py b/BaseClasses.py index 38598d42d999..080b28bef44b 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -650,6 +650,7 @@ def __init__(self, parent: MultiWorld): self.collect(item, True) def update_reachable_regions(self, player: int): + new_connection: bool = True self.stale[player] = False reachable_regions = self.reachable_regions[player] blocked_connections = self.blocked_connections[player] diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 6532eb2f2898..2e0f1c723b38 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -17,7 +17,8 @@ from .rules import set_rules from worlds.generic.Rules import set_rule from .stardew_rule import True_, StardewRule -from .strings.goal_names import Goal as GoalName +from .strings.ap_names.event_names import Event +from .strings.goal_names import Goal client_version = 0 @@ -137,6 +138,7 @@ def create_items(self): self.setup_early_items() self.setup_month_events() + self.setup_construction_events() self.setup_victory() def precollect_starting_season(self) -> Optional[StardewItem]: @@ -170,60 +172,64 @@ def setup_early_items(self): def setup_month_events(self): for i in range(0, MAX_MONTHS): - month_end = LocationData(None, "Stardew Valley", f"Month End {i + 1}") + month_end = LocationData(None, "Stardew Valley", f"{Event.month_end} {i + 1}") if i == 0: - self.create_event_location(month_end, True_(), "Month End") + self.create_event_location(month_end, True_(), Event.month_end) continue - self.create_event_location(month_end, self.logic.received("Month End", i).simplify(), "Month End") + self.create_event_location(month_end, self.logic.received(Event.month_end, i).simplify(), Event.month_end) + + def setup_construction_events(self): + can_construct_buildings = LocationData(None, "Carpenter Shop", Event.can_construct_buildings) + self.create_event_location(can_construct_buildings, True_(), Event.can_construct_buildings) def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], self.logic.can_complete_community_center().simplify(), - "Victory") + Event.victory) elif self.options.goal == Goal.option_grandpa_evaluation: self.create_event_location(location_table[GoalName.grandpa_evaluation], self.logic.can_finish_grandpa_evaluation().simplify(), - "Victory") + Event.victory) elif self.options.goal == Goal.option_bottom_of_the_mines: self.create_event_location(location_table[GoalName.bottom_of_the_mines], self.logic.mine.can_mine_to_floor(120).simplify(), - item="Victory") + Event.victory) elif self.options.goal == Goal.option_cryptic_note: self.create_event_location(location_table[GoalName.cryptic_note], self.logic.can_complete_quest("Cryptic Note").simplify(), - "Victory") + Event.victory) elif self.options.goal == Goal.option_master_angler: self.create_event_location(location_table[GoalName.master_angler], self.logic.can_catch_every_fish().simplify(), - "Victory") + Event.victory) elif self.options.goal == Goal.option_complete_collection: self.create_event_location(location_table[GoalName.complete_museum], self.logic.museum.can_complete_museum().simplify(), - "Victory") + Event.victory) elif self.options.goal == Goal.option_full_house: self.create_event_location(location_table[GoalName.full_house], (self.logic.relationship.has_children(2) & self.logic.relationship.can_reproduce()).simplify(), - "Victory") + Event.victory) elif self.options.goal == Goal.option_greatest_walnut_hunter: self.create_event_location(location_table[GoalName.greatest_walnut_hunter], self.logic.has_walnut(130).simplify(), - "Victory") + Event.victory) elif self.options[options.Goal] == options.Goal.option_protector_of_the_valley: self.create_event_location(location_table[Goal.protector_of_the_valley], self.logic.can_complete_all_monster_slaying_goals().simplify(), - "Victory") + Event.victory) elif self.options[options.Goal] == options.Goal.option_full_shipment: self.create_event_location(location_table[Goal.full_shipment], self.logic.can_ship_everything().simplify(), - "Victory") + Event.victory) elif self.options[options.Goal] == options.Goal.option_perfection: self.create_event_location(location_table[Goal.perfection], self.logic.has_everything(self.all_progression_items).simplify(), - "Victory") + Event.victory) - self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player) + self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player) def create_item(self, item: Union[str, ItemData], override_classification: ItemClassification = None) -> StardewItem: if isinstance(item, str): diff --git a/worlds/stardew_valley/bundles.py b/worlds/stardew_valley/bundles.py index 2deec4878ea9..d8eca75f5832 100644 --- a/worlds/stardew_valley/bundles.py +++ b/worlds/stardew_valley/bundles.py @@ -37,7 +37,7 @@ "Bulletin Board/33": "Enchanter's/O 336 5/725 1 0 348 1 0 446 1 0 637 1 0/1", "Bulletin Board/34": "Dye/BO 25 1/420 1 0 397 1 0 421 1 0 444 1 0 62 1 0 266 1 0/6", "Bulletin Board/35": "Fodder/BO 104 1/262 10 0 178 10 0 613 3 0/3", - # "Abandoned Joja Mart/36": "The Missing//348 1 1 807 1 0 74 1 0 454 5 2 795 1 2 445 1 0/1/5" + "Abandoned Joja Mart/36": "The Missing//348 1 1 807 1 0 74 1 0 454 5 2 795 1 2 445 1 0/1/5" } @@ -204,6 +204,7 @@ def shuffle_bundles_thematically(random: Random, bundles: Dict[str, Bundle]): shuffle_fish_tank_thematically(random, bundles) shuffle_boiler_room_thematically(random, bundles) shuffle_bulletin_board_thematically(random, bundles) + shuffle_abandoned_jojamart_thematically(random, bundles) def shuffle_crafts_room_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): @@ -247,6 +248,10 @@ def shuffle_bulletin_board_thematically(random: Random, bundles: Dict[str, Bundl bundles["Enchanter's Bundle"].randomize_requirements(random, enchanter_items) +def shuffle_abandoned_jojamart_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["The Missing Bundle"].randomize_requirements(random, missing_bundle_items) + + def shuffle_vault_amongst_themselves(random: Random, bundles: Dict[str, Bundle]): bundles["2,500g Bundle"].randomize_requirements(random, vault_bundle_items) bundles["5,000g Bundle"].randomize_requirements(random, vault_bundle_items) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 183383ccbf3a..817ebc64c81b 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -4,6 +4,12 @@ from .common_data import quality_dict from .game_item import GameItem from .museum_data import Mineral +from ..strings.artisan_good_names import ArtisanGood +from ..strings.crop_names import Fruit, Vegetable +from ..strings.fish_names import Fish +from ..strings.food_names import Beverage +from ..strings.seed_names import Seed + @dataclass(frozen=True) class BundleItem: @@ -12,7 +18,7 @@ class BundleItem: quality: int @staticmethod - def item_bundle(name: str, item_id: int, amount: int, quality: int): + def item_bundle(name: str, item_id: int, amount: int = 1, quality: int = 0): return BundleItem(GameItem(name, item_id), amount, quality) @staticmethod @@ -25,6 +31,9 @@ def as_amount(self, amount: int): def as_quality(self, quality: int): return BundleItem.item_bundle(self.item.name, self.item.item_id, self.amount, quality) + def as_silver_quality(self): + return self.as_quality(1) + def as_gold_quality(self): return self.as_quality(2) @@ -45,48 +54,48 @@ def __lt__(self, other): return self.item < other.item -wild_horseradish = BundleItem.item_bundle("Wild Horseradish", 16, 1, 0) -daffodil = BundleItem.item_bundle("Daffodil", 18, 1, 0) -leek = BundleItem.item_bundle("Leek", 20, 1, 0) -dandelion = BundleItem.item_bundle("Dandelion", 22, 1, 0) -morel = BundleItem.item_bundle("Morel", 257, 1, 0) -common_mushroom = BundleItem.item_bundle("Common Mushroom", 404, 1, 0) -salmonberry = BundleItem.item_bundle("Salmonberry", 296, 1, 0) -spring_onion = BundleItem.item_bundle("Spring Onion", 399, 1, 0) - -grape = BundleItem.item_bundle("Grape", 398, 1, 0) -spice_berry = BundleItem.item_bundle("Spice Berry", 396, 1, 0) -sweet_pea = BundleItem.item_bundle("Sweet Pea", 402, 1, 0) -red_mushroom = BundleItem.item_bundle("Red Mushroom", 420, 1, 0) -fiddlehead_fern = BundleItem.item_bundle("Fiddlehead Fern", 259, 1, 0) - -wild_plum = BundleItem.item_bundle("Wild Plum", 406, 1, 0) -hazelnut = BundleItem.item_bundle("Hazelnut", 408, 1, 0) -blackberry = BundleItem.item_bundle("Blackberry", 410, 1, 0) -chanterelle = BundleItem.item_bundle("Chanterelle", 281, 1, 0) - -winter_root = BundleItem.item_bundle("Winter Root", 412, 1, 0) -crystal_fruit = BundleItem.item_bundle("Crystal Fruit", 414, 1, 0) -snow_yam = BundleItem.item_bundle("Snow Yam", 416, 1, 0) -crocus = BundleItem.item_bundle("Crocus", 418, 1, 0) -holly = BundleItem.item_bundle("Holly", 283, 1, 0) - -coconut = BundleItem.item_bundle("Coconut", 88, 1, 0) -cactus_fruit = BundleItem.item_bundle("Cactus Fruit", 90, 1, 0) -cave_carrot = BundleItem.item_bundle("Cave Carrot", 78, 1, 0) -purple_mushroom = BundleItem.item_bundle("Purple Mushroom", 422, 1, 0) -maple_syrup = BundleItem.item_bundle("Maple Syrup", 724, 1, 0) -oak_resin = BundleItem.item_bundle("Oak Resin", 725, 1, 0) -pine_tar = BundleItem.item_bundle("Pine Tar", 726, 1, 0) -nautilus_shell = BundleItem.item_bundle("Nautilus Shell", 392, 1, 0) -coral = BundleItem.item_bundle("Coral", 393, 1, 0) -sea_urchin = BundleItem.item_bundle("Sea Urchin", 397, 1, 0) -rainbow_shell = BundleItem.item_bundle("Rainbow Shell", 394, 1, 0) +wild_horseradish = BundleItem.item_bundle("Wild Horseradish", 16) +daffodil = BundleItem.item_bundle("Daffodil", 18) +leek = BundleItem.item_bundle("Leek", 20) +dandelion = BundleItem.item_bundle("Dandelion", 22) +morel = BundleItem.item_bundle("Morel", 257) +common_mushroom = BundleItem.item_bundle("Common Mushroom", 404) +salmonberry = BundleItem.item_bundle("Salmonberry", 296) +spring_onion = BundleItem.item_bundle("Spring Onion", 399) + +grape = BundleItem.item_bundle("Grape", 398) +spice_berry = BundleItem.item_bundle("Spice Berry", 396) +sweet_pea = BundleItem.item_bundle("Sweet Pea", 402) +red_mushroom = BundleItem.item_bundle("Red Mushroom", 420) +fiddlehead_fern = BundleItem.item_bundle("Fiddlehead Fern", 259) + +wild_plum = BundleItem.item_bundle("Wild Plum", 406) +hazelnut = BundleItem.item_bundle("Hazelnut", 408) +blackberry = BundleItem.item_bundle("Blackberry", 410) +chanterelle = BundleItem.item_bundle("Chanterelle", 281) + +winter_root = BundleItem.item_bundle("Winter Root", 412) +crystal_fruit = BundleItem.item_bundle("Crystal Fruit", 414) +snow_yam = BundleItem.item_bundle("Snow Yam", 416) +crocus = BundleItem.item_bundle("Crocus", 418) +holly = BundleItem.item_bundle("Holly", 283) + +coconut = BundleItem.item_bundle("Coconut", 88) +cactus_fruit = BundleItem.item_bundle("Cactus Fruit", 90) +cave_carrot = BundleItem.item_bundle("Cave Carrot", 78) +purple_mushroom = BundleItem.item_bundle("Purple Mushroom", 422) +maple_syrup = BundleItem.item_bundle("Maple Syrup", 724) +oak_resin = BundleItem.item_bundle("Oak Resin", 725) +pine_tar = BundleItem.item_bundle("Pine Tar", 726) +nautilus_shell = BundleItem.item_bundle("Nautilus Shell", 392) +coral = BundleItem.item_bundle("Coral", 393) +sea_urchin = BundleItem.item_bundle("Sea Urchin", 397) +rainbow_shell = BundleItem.item_bundle("Rainbow Shell", 394) clam = BundleItem(fish_data.clam, 1, 0) cockle = BundleItem(fish_data.cockle, 1, 0) mussel = BundleItem(fish_data.mussel, 1, 0) oyster = BundleItem(fish_data.oyster, 1, 0) -seaweed = BundleItem.item_bundle("Seaweed", 152, 1, 0) +seaweed = BundleItem.item_bundle("Seaweed", 152) wood = BundleItem.item_bundle("Wood", 388, 99, 0) stone = BundleItem.item_bundle("Stone", 390, 99, 0) @@ -94,85 +103,90 @@ def __lt__(self, other): clay = BundleItem.item_bundle("Clay", 330, 10, 0) fiber = BundleItem.item_bundle("Fiber", 771, 99, 0) -blue_jazz = BundleItem.item_bundle("Blue Jazz", 597, 1, 0) -cauliflower = BundleItem.item_bundle("Cauliflower", 190, 1, 0) -green_bean = BundleItem.item_bundle("Green Bean", 188, 1, 0) -kale = BundleItem.item_bundle("Kale", 250, 1, 0) -parsnip = BundleItem.item_bundle("Parsnip", 24, 1, 0) -potato = BundleItem.item_bundle("Potato", 192, 1, 0) -strawberry = BundleItem.item_bundle("Strawberry", 400, 1, 0) -tulip = BundleItem.item_bundle("Tulip", 591, 1, 0) -unmilled_rice = BundleItem.item_bundle("Unmilled Rice", 271, 1, 0) -blueberry = BundleItem.item_bundle("Blueberry", 258, 1, 0) -corn = BundleItem.item_bundle("Corn", 270, 1, 0) -hops = BundleItem.item_bundle("Hops", 304, 1, 0) -hot_pepper = BundleItem.item_bundle("Hot Pepper", 260, 1, 0) -melon = BundleItem.item_bundle("Melon", 254, 1, 0) -poppy = BundleItem.item_bundle("Poppy", 376, 1, 0) -radish = BundleItem.item_bundle("Radish", 264, 1, 0) -summer_spangle = BundleItem.item_bundle("Summer Spangle", 593, 1, 0) -sunflower = BundleItem.item_bundle("Sunflower", 421, 1, 0) -tomato = BundleItem.item_bundle("Tomato", 256, 1, 0) -wheat = BundleItem.item_bundle("Wheat", 262, 1, 0) -hay = BundleItem.item_bundle("Hay", 178, 1, 0) -amaranth = BundleItem.item_bundle("Amaranth", 300, 1, 0) -bok_choy = BundleItem.item_bundle("Bok Choy", 278, 1, 0) -cranberries = BundleItem.item_bundle("Cranberries", 282, 1, 0) -eggplant = BundleItem.item_bundle("Eggplant", 272, 1, 0) -fairy_rose = BundleItem.item_bundle("Fairy Rose", 595, 1, 0) -pumpkin = BundleItem.item_bundle("Pumpkin", 276, 1, 0) -yam = BundleItem.item_bundle("Yam", 280, 1, 0) -sweet_gem_berry = BundleItem.item_bundle("Sweet Gem Berry", 417, 1, 0) -rhubarb = BundleItem.item_bundle("Rhubarb", 252, 1, 0) -beet = BundleItem.item_bundle("Beet", 284, 1, 0) -red_cabbage = BundleItem.item_bundle("Red Cabbage", 266, 1, 0) -artichoke = BundleItem.item_bundle("Artichoke", 274, 1, 0) - -egg = BundleItem.item_bundle("Egg", 176, 1, 0) -large_egg = BundleItem.item_bundle("Large Egg", 174, 1, 0) -brown_egg = BundleItem.item_bundle("Egg (Brown)", 180, 1, 0) -large_brown_egg = BundleItem.item_bundle("Large Egg (Brown)", 182, 1, 0) -wool = BundleItem.item_bundle("Wool", 440, 1, 0) -milk = BundleItem.item_bundle("Milk", 184, 1, 0) -large_milk = BundleItem.item_bundle("Large Milk", 186, 1, 0) -goat_milk = BundleItem.item_bundle("Goat Milk", 436, 1, 0) -large_goat_milk = BundleItem.item_bundle("Large Goat Milk", 438, 1, 0) -truffle = BundleItem.item_bundle("Truffle", 430, 1, 0) -duck_feather = BundleItem.item_bundle("Duck Feather", 444, 1, 0) -duck_egg = BundleItem.item_bundle("Duck Egg", 442, 1, 0) -rabbit_foot = BundleItem.item_bundle("Rabbit's Foot", 446, 1, 0) - -truffle_oil = BundleItem.item_bundle("Truffle Oil", 432, 1, 0) -cloth = BundleItem.item_bundle("Cloth", 428, 1, 0) -goat_cheese = BundleItem.item_bundle("Goat Cheese", 426, 1, 0) -cheese = BundleItem.item_bundle("Cheese", 424, 1, 0) -honey = BundleItem.item_bundle("Honey", 340, 1, 0) -beer = BundleItem.item_bundle("Beer", 346, 1, 0) -juice = BundleItem.item_bundle("Juice", 350, 1, 0) -mead = BundleItem.item_bundle("Mead", 459, 1, 0) -pale_ale = BundleItem.item_bundle("Pale Ale", 303, 1, 0) -wine = BundleItem.item_bundle("Wine", 348, 1, 0) -jelly = BundleItem.item_bundle("Jelly", 344, 1, 0) -pickles = BundleItem.item_bundle("Pickles", 342, 1, 0) -caviar = BundleItem.item_bundle("Caviar", 445, 1, 0) -aged_roe = BundleItem.item_bundle("Aged Roe", 447, 1, 0) -apple = BundleItem.item_bundle("Apple", 613, 1, 0) -apricot = BundleItem.item_bundle("Apricot", 634, 1, 0) -orange = BundleItem.item_bundle("Orange", 635, 1, 0) -peach = BundleItem.item_bundle("Peach", 636, 1, 0) -pomegranate = BundleItem.item_bundle("Pomegranate", 637, 1, 0) -cherry = BundleItem.item_bundle("Cherry", 638, 1, 0) +blue_jazz = BundleItem.item_bundle("Blue Jazz", 597) +cauliflower = BundleItem.item_bundle("Cauliflower", 190) +green_bean = BundleItem.item_bundle("Green Bean", 188) +kale = BundleItem.item_bundle("Kale", 250) +parsnip = BundleItem.item_bundle("Parsnip", 24) +potato = BundleItem.item_bundle("Potato", 192) +strawberry = BundleItem.item_bundle("Strawberry", 400) +tulip = BundleItem.item_bundle("Tulip", 591) +unmilled_rice = BundleItem.item_bundle("Unmilled Rice", 271) +coffee_bean = BundleItem.item_bundle(Seed.coffee, 433) +garlic = BundleItem.item_bundle(Vegetable.garlic, 248) +blueberry = BundleItem.item_bundle("Blueberry", 258) +corn = BundleItem.item_bundle("Corn", 270) +hops = BundleItem.item_bundle("Hops", 304) +hot_pepper = BundleItem.item_bundle("Hot Pepper", 260) +melon = BundleItem.item_bundle("Melon", 254) +poppy = BundleItem.item_bundle("Poppy", 376) +radish = BundleItem.item_bundle("Radish", 264) +summer_spangle = BundleItem.item_bundle("Summer Spangle", 593) +sunflower = BundleItem.item_bundle("Sunflower", 421) +tomato = BundleItem.item_bundle("Tomato", 256) +wheat = BundleItem.item_bundle("Wheat", 262) +hay = BundleItem.item_bundle("Hay", 178) +amaranth = BundleItem.item_bundle("Amaranth", 300) +bok_choy = BundleItem.item_bundle("Bok Choy", 278) +cranberries = BundleItem.item_bundle("Cranberries", 282) +eggplant = BundleItem.item_bundle("Eggplant", 272) +fairy_rose = BundleItem.item_bundle("Fairy Rose", 595) +pumpkin = BundleItem.item_bundle("Pumpkin", 276) +yam = BundleItem.item_bundle("Yam", 280) +sweet_gem_berry = BundleItem.item_bundle("Sweet Gem Berry", 417) +rhubarb = BundleItem.item_bundle("Rhubarb", 252) +beet = BundleItem.item_bundle("Beet", 284) +red_cabbage = BundleItem.item_bundle("Red Cabbage", 266) +starfruit = BundleItem.item_bundle(Fruit.starfruit, 268) +artichoke = BundleItem.item_bundle("Artichoke", 274) + +egg = BundleItem.item_bundle("Egg", 176) +large_egg = BundleItem.item_bundle("Large Egg", 174) +brown_egg = BundleItem.item_bundle("Egg (Brown)", 180) +large_brown_egg = BundleItem.item_bundle("Large Egg (Brown)", 182) +wool = BundleItem.item_bundle("Wool", 440) +milk = BundleItem.item_bundle("Milk", 184) +large_milk = BundleItem.item_bundle("Large Milk", 186) +goat_milk = BundleItem.item_bundle("Goat Milk", 436) +large_goat_milk = BundleItem.item_bundle("Large Goat Milk", 438) +truffle = BundleItem.item_bundle("Truffle", 430) +duck_feather = BundleItem.item_bundle("Duck Feather", 444) +duck_egg = BundleItem.item_bundle("Duck Egg", 442) +rabbit_foot = BundleItem.item_bundle("Rabbit's Foot", 446) + +truffle_oil = BundleItem.item_bundle("Truffle Oil", 432) +cloth = BundleItem.item_bundle("Cloth", 428) +goat_cheese = BundleItem.item_bundle("Goat Cheese", 426) +cheese = BundleItem.item_bundle("Cheese", 424) +honey = BundleItem.item_bundle("Honey", 340) +beer = BundleItem.item_bundle("Beer", 346) +juice = BundleItem.item_bundle("Juice", 350) +mead = BundleItem.item_bundle("Mead", 459) +pale_ale = BundleItem.item_bundle("Pale Ale", 303) +wine = BundleItem.item_bundle("Wine", 348) +jelly = BundleItem.item_bundle("Jelly", 344) +pickles = BundleItem.item_bundle("Pickles", 342) +caviar = BundleItem.item_bundle("Caviar", 445) +aged_roe = BundleItem.item_bundle("Aged Roe", 447) +coffee = BundleItem.item_bundle(Beverage.coffee, 395) +green_tea = BundleItem.item_bundle(ArtisanGood.green_tea, 614) +apple = BundleItem.item_bundle("Apple", 613) +apricot = BundleItem.item_bundle("Apricot", 634) +orange = BundleItem.item_bundle("Orange", 635) +peach = BundleItem.item_bundle("Peach", 636) +pomegranate = BundleItem.item_bundle("Pomegranate", 637) +cherry = BundleItem.item_bundle("Cherry", 638) lobster = BundleItem(fish_data.lobster, 1, 0) crab = BundleItem(fish_data.crab, 1, 0) shrimp = BundleItem(fish_data.shrimp, 1, 0) crayfish = BundleItem(fish_data.crayfish, 1, 0) snail = BundleItem(fish_data.snail, 1, 0) periwinkle = BundleItem(fish_data.periwinkle, 1, 0) -trash = BundleItem.item_bundle("Trash", 168, 1, 0) -driftwood = BundleItem.item_bundle("Driftwood", 169, 1, 0) -soggy_newspaper = BundleItem.item_bundle("Soggy Newspaper", 172, 1, 0) -broken_cd = BundleItem.item_bundle("Broken CD", 171, 1, 0) -broken_glasses = BundleItem.item_bundle("Broken Glasses", 170, 1, 0) +trash = BundleItem.item_bundle("Trash", 168) +driftwood = BundleItem.item_bundle("Driftwood", 169) +soggy_newspaper = BundleItem.item_bundle("Soggy Newspaper", 172) +broken_cd = BundleItem.item_bundle("Broken CD", 171) +broken_glasses = BundleItem.item_bundle("Broken Glasses", 170) chub = BundleItem(fish_data.chub, 1, 0) catfish = BundleItem(fish_data.catfish, 1, 0) @@ -217,11 +231,11 @@ def __lt__(self, other): stonefish = BundleItem(fish_data.stonefish, 1, 0) ghostfish = BundleItem(fish_data.ghostfish, 1, 0) -wilted_bouquet = BundleItem.item_bundle("Wilted Bouquet", 277, 1, 0) +wilted_bouquet = BundleItem.item_bundle("Wilted Bouquet", 277) copper_bar = BundleItem.item_bundle("Copper Bar", 334, 2, 0) iron_Bar = BundleItem.item_bundle("Iron Bar", 335, 2, 0) -gold_bar = BundleItem.item_bundle("Gold Bar", 336, 1, 0) -iridium_bar = BundleItem.item_bundle("Iridium Bar", 337, 1, 0) +gold_bar = BundleItem.item_bundle("Gold Bar", 336) +iridium_bar = BundleItem.item_bundle("Iridium Bar", 337) refined_quartz = BundleItem.item_bundle("Refined Quartz", 338, 2, 0) coal = BundleItem.item_bundle("Coal", 382, 5, 0) @@ -239,41 +253,41 @@ def __lt__(self, other): slime = BundleItem.item_bundle("Slime", 766, 99, 0) bug_meat = BundleItem.item_bundle("Bug Meat", 684, 10, 0) bat_wing = BundleItem.item_bundle("Bat Wing", 767, 10, 0) -solar_essence = BundleItem.item_bundle("Solar Essence", 768, 1, 0) -void_essence = BundleItem.item_bundle("Void Essence", 769, 1, 0) - -maki_roll = BundleItem.item_bundle("Maki Roll", 228, 1, 0) -fried_egg = BundleItem.item_bundle("Fried Egg", 194, 1, 0) -omelet = BundleItem.item_bundle("Omelet", 195, 1, 0) -pizza = BundleItem.item_bundle("Pizza", 206, 1, 0) -hashbrowns = BundleItem.item_bundle("Hashbrowns", 210, 1, 0) -pancakes = BundleItem.item_bundle("Pancakes", 211, 1, 0) -bread = BundleItem.item_bundle("Bread", 216, 1, 0) -tortilla = BundleItem.item_bundle("Tortilla", 229, 1, 0) -triple_shot_espresso = BundleItem.item_bundle("Triple Shot Espresso", 253, 1, 0) -farmer_s_lunch = BundleItem.item_bundle("Farmer's Lunch", 240, 1, 0) -survival_burger = BundleItem.item_bundle("Survival Burger", 241, 1, 0) -dish_o_the_sea = BundleItem.item_bundle("Dish O' The Sea", 242, 1, 0) -miner_s_treat = BundleItem.item_bundle("Miner's Treat", 243, 1, 0) -roots_platter = BundleItem.item_bundle("Roots Platter", 244, 1, 0) -salad = BundleItem.item_bundle("Salad", 196, 1, 0) -cheese_cauliflower = BundleItem.item_bundle("Cheese Cauliflower", 197, 1, 0) -parsnip_soup = BundleItem.item_bundle("Parsnip Soup", 199, 1, 0) -fried_mushroom = BundleItem.item_bundle("Fried Mushroom", 205, 1, 0) -salmon_dinner = BundleItem.item_bundle("Salmon Dinner", 212, 1, 0) -pepper_poppers = BundleItem.item_bundle("Pepper Poppers", 215, 1, 0) -spaghetti = BundleItem.item_bundle("Spaghetti", 224, 1, 0) -sashimi = BundleItem.item_bundle("Sashimi", 227, 1, 0) -blueberry_tart = BundleItem.item_bundle("Blueberry Tart", 234, 1, 0) -algae_soup = BundleItem.item_bundle("Algae Soup", 456, 1, 0) -pale_broth = BundleItem.item_bundle("Pale Broth", 457, 1, 0) -chowder = BundleItem.item_bundle("Chowder", 727, 1, 0) -green_algae = BundleItem.item_bundle("Green Algae", 153, 1, 0) -white_algae = BundleItem.item_bundle("White Algae", 157, 1, 0) -geode = BundleItem.item_bundle("Geode", 535, 1, 0) -frozen_geode = BundleItem.item_bundle("Frozen Geode", 536, 1, 0) -magma_geode = BundleItem.item_bundle("Magma Geode", 537, 1, 0) -omni_geode = BundleItem.item_bundle("Omni Geode", 749, 1, 0) +solar_essence = BundleItem.item_bundle("Solar Essence", 768) +void_essence = BundleItem.item_bundle("Void Essence", 769) + +maki_roll = BundleItem.item_bundle("Maki Roll", 228) +fried_egg = BundleItem.item_bundle("Fried Egg", 194) +omelet = BundleItem.item_bundle("Omelet", 195) +pizza = BundleItem.item_bundle("Pizza", 206) +hashbrowns = BundleItem.item_bundle("Hashbrowns", 210) +pancakes = BundleItem.item_bundle("Pancakes", 211) +bread = BundleItem.item_bundle("Bread", 216) +tortilla = BundleItem.item_bundle("Tortilla", 229) +triple_shot_espresso = BundleItem.item_bundle("Triple Shot Espresso", 253) +farmer_s_lunch = BundleItem.item_bundle("Farmer's Lunch", 240) +survival_burger = BundleItem.item_bundle("Survival Burger", 241) +dish_o_the_sea = BundleItem.item_bundle("Dish O' The Sea", 242) +miner_s_treat = BundleItem.item_bundle("Miner's Treat", 243) +roots_platter = BundleItem.item_bundle("Roots Platter", 244) +salad = BundleItem.item_bundle("Salad", 196) +cheese_cauliflower = BundleItem.item_bundle("Cheese Cauliflower", 197) +parsnip_soup = BundleItem.item_bundle("Parsnip Soup", 199) +fried_mushroom = BundleItem.item_bundle("Fried Mushroom", 205) +salmon_dinner = BundleItem.item_bundle("Salmon Dinner", 212) +pepper_poppers = BundleItem.item_bundle("Pepper Poppers", 215) +spaghetti = BundleItem.item_bundle("Spaghetti", 224) +sashimi = BundleItem.item_bundle("Sashimi", 227) +blueberry_tart = BundleItem.item_bundle("Blueberry Tart", 234) +algae_soup = BundleItem.item_bundle("Algae Soup", 456) +pale_broth = BundleItem.item_bundle("Pale Broth", 457) +chowder = BundleItem.item_bundle("Chowder", 727) +green_algae = BundleItem.item_bundle("Green Algae", 153) +white_algae = BundleItem.item_bundle("White Algae", 157) +geode = BundleItem.item_bundle("Geode", 535) +frozen_geode = BundleItem.item_bundle("Frozen Geode", 536) +magma_geode = BundleItem.item_bundle("Magma Geode", 537) +omni_geode = BundleItem.item_bundle("Omni Geode", 749) spring_foraging_items = [wild_horseradish, daffodil, leek, dandelion, salmonberry, spring_onion] summer_foraging_items = [grape, spice_berry, sweet_pea, fiddlehead_fern, rainbow_shell] @@ -284,22 +298,17 @@ def __lt__(self, other): sea_urchin, clam, cockle, mussel, oyster, seaweed] construction_items = [wood, stone, hardwood, clay, fiber] -# TODO coffee_bean, garlic, rhubarb, tea_leaves -spring_crop_items = [blue_jazz, cauliflower, green_bean, kale, parsnip, potato, strawberry, tulip, unmilled_rice] -# TODO red_cabbage, starfruit, ancient_fruit, pineapple, taro_root +spring_crop_items = [blue_jazz, cauliflower, green_bean, kale, parsnip, potato, strawberry, tulip, unmilled_rice, coffee_bean, garlic, rhubarb] summer_crops_items = [blueberry, corn, hops, hot_pepper, melon, poppy, - radish, summer_spangle, sunflower, tomato, wheat] -# TODO artichoke, beet + radish, summer_spangle, sunflower, tomato, wheat, red_cabbage, starfruit] fall_crops_items = [corn, sunflower, wheat, amaranth, bok_choy, cranberries, - eggplant, fairy_rose, grape, pumpkin, yam, sweet_gem_berry] + eggplant, fairy_rose, grape, pumpkin, yam, sweet_gem_berry, artichoke, beet] all_crops_items = sorted({*spring_crop_items, *summer_crops_items, *fall_crops_items}) quality_crops_items = [item.as_quality_crop() for item in all_crops_items] -# TODO void_egg, dinosaur_egg, ostrich_egg, golden_egg animal_product_items = [egg, large_egg, brown_egg, large_brown_egg, wool, milk, large_milk, goat_milk, large_goat_milk, truffle, duck_feather, duck_egg, rabbit_foot] -# TODO coffee, green_tea artisan_goods_items = [truffle_oil, cloth, goat_cheese, cheese, honey, beer, juice, mead, pale_ale, wine, jelly, - pickles, caviar, aged_roe, apple, apricot, orange, peach, pomegranate, cherry] + pickles, caviar, aged_roe, apple, apricot, orange, peach, pomegranate, cherry, coffee, green_tea] river_fish_items = [chub, catfish, rainbow_trout, lingcod, walleye, perch, pike, bream, salmon, sunfish, tiger_trout, shad, smallmouth_bass, dorado] @@ -307,13 +316,12 @@ def __lt__(self, other): ocean_fish_items = [tilapia, pufferfish, tuna, super_cucumber, flounder, anchovy, sardine, red_mullet, herring, eel, octopus, red_snapper, squid, sea_cucumber, albacore, halibut] night_fish_items = [walleye, bream, super_cucumber, eel, squid, midnight_carp] -# TODO void_salmon + specialty_fish_items = [scorpion_carp, sandfish, woodskip, pufferfish, eel, octopus, squid, lava_eel, ice_pip, stonefish, ghostfish, dorado] crab_pot_items = [lobster, clam, crab, cockle, mussel, shrimp, oyster, crayfish, snail, periwinkle, trash, driftwood, soggy_newspaper, broken_cd, broken_glasses] -# TODO radioactive_bar blacksmith_items = [wilted_bouquet, copper_bar, iron_Bar, gold_bar, iridium_bar, refined_quartz, coal] geologist_items = [quartz, earth_crystal, frozen_tear, fire_quartz, emerald, aquamarine, ruby, amethyst, topaz, jade] adventurer_items = [slime, bug_meat, bat_wing, solar_essence, void_essence, coal] @@ -323,13 +331,22 @@ def __lt__(self, other): cheese_cauliflower, parsnip_soup, fried_mushroom, salmon_dinner, pepper_poppers, spaghetti, sashimi, blueberry_tart, algae_soup, pale_broth, chowder] -dwarf_scroll_1 = BundleItem.item_bundle("Dwarf Scroll I", 96, 1, 0) -dwarf_scroll_2 = BundleItem.item_bundle("Dwarf Scroll II", 97, 1, 0) -dwarf_scroll_3 = BundleItem.item_bundle("Dwarf Scroll III", 98, 1, 0) -dwarf_scroll_4 = BundleItem.item_bundle("Dwarf Scroll IV", 99, 1, 0) -elvish_jewelry = BundleItem.item_bundle("Elvish Jewelry", 104, 1, 0) -ancient_drum = BundleItem.item_bundle("Ancient Drum", 123, 1, 0) -dried_starfish = BundleItem.item_bundle("Dried Starfish", 116, 1, 0) +dwarf_scroll_1 = BundleItem.item_bundle("Dwarf Scroll I", 96) +dwarf_scroll_2 = BundleItem.item_bundle("Dwarf Scroll II", 97) +dwarf_scroll_3 = BundleItem.item_bundle("Dwarf Scroll III", 98) +dwarf_scroll_4 = BundleItem.item_bundle("Dwarf Scroll IV", 99) +elvish_jewelry = BundleItem.item_bundle("Elvish Jewelry", 104) +ancient_drum = BundleItem.item_bundle("Ancient Drum", 123) +dried_starfish = BundleItem.item_bundle("Dried Starfish", 116) + +dinosaur_mayo = BundleItem.item_bundle(ArtisanGood.dinosaur_mayonnaise, 807) +void_mayo = BundleItem.item_bundle(ArtisanGood.void_mayonnaise, 308) +prismatic_shard = BundleItem(Mineral.prismatic_shard, 1, 0) +diamond = BundleItem(Mineral.diamond, 1, 0) +ancient_fruit = BundleItem.item_bundle(Fruit.ancient_fruit, 454) +void_salmon = BundleItem.item_bundle(Fish.void_salmon, 795) +tea_leaves = BundleItem.item_bundle(Vegetable.tea_leaves, 815) +blobfish = BundleItem.item_bundle(Fish.blobfish, 800) dye_red_items = [cranberries, hot_pepper, radish, rhubarb, spaghetti, strawberry, tomato, tulip] dye_orange_items = [poppy, pumpkin, apricot, orange, spice_berry, winter_root] @@ -344,6 +361,11 @@ def __lt__(self, other): green_bean.as_amount(3), potato.as_amount(3), green_algae.as_amount(5), white_algae.as_amount(3)] enchanter_items = [oak_resin, wine, rabbit_foot, pomegranate, purple_mushroom, solar_essence, super_cucumber, void_essence, fire_quartz, frozen_tear, jade] +missing_bundle_items = [wine.as_silver_quality(), pale_ale.as_silver_quality(), beer.as_silver_quality(), mead.as_silver_quality(), cheese.as_silver_quality(), + goat_cheese.as_silver_quality(), dinosaur_mayo, void_mayo, cloth, green_tea, truffle_oil, caviar, prismatic_shard, diamond, + ancient_fruit.as_gold_quality().as_amount(5), sweet_gem_berry.as_gold_quality().as_amount(5), starfruit.as_gold_quality().as_amount(5), + tea_leaves.as_amount(5), + void_salmon.as_gold_quality(), lava_eel.as_gold_quality(), scorpion_carp.as_gold_quality(), blobfish.as_gold_quality()] vault_2500_items = [BundleItem.money_bundle(2500)] vault_5000_items = [BundleItem.money_bundle(5000)] @@ -404,6 +426,7 @@ def __lt__(self, other): *fish_tank_bundle_items, *boiler_room_bundle_items, *bulletin_board_bundle_items, + *missing_bundle_items, }, key=lambda x: x.item.name) all_bundle_items = sorted({ @@ -413,6 +436,7 @@ def __lt__(self, other): *boiler_room_bundle_items, *bulletin_board_bundle_items, *vault_bundle_items, + *missing_bundle_items, }, key=lambda x: x.item.name) all_bundle_items_by_name = {item.item.name: item for item in all_bundle_items} diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index ae41051e5b65..e254546bb11e 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -7,7 +7,7 @@ id,name,classification,groups,mod_name 19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, 20,Minecarts Repair,useful,COMMUNITY_REWARD, 21,Bus Repair,progression,COMMUNITY_REWARD, -22,Movie Theater,useful,, +22,Progressive Movie Theater,progression,COMMUNITY_REWARD, 23,Stardrop,progression,, 24,Progressive Backpack,progression,, 25,Rusty Sword,filler,"WEAPON,DEPRECATED", @@ -318,7 +318,7 @@ id,name,classification,groups,mod_name 333,Tub o' Flowers Recipe,progression,"CRAFTING_RECIPE", 334,Fiber Seeds Recipe,progression,"CRAFTING_RECIPE", 335,Quality Bobber Recipe,progression,"CRAFTING_RECIPE", -336,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 48c26ab918d1..4224b68fbaeb 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -29,7 +29,7 @@ id,region,name,tags,mod_name 28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", 29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", 30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -31,Abandoned JojaMart,The Missing Bundle,BUNDLE, +31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", 32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", 33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", 34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index c8f27b0e3fe0..1ecd9502a652 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -14,6 +14,7 @@ Fishsanity, BuildingProgression, SkillProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff +from .strings.ap_names.event_names import Event ITEM_CODE_OFFSET = 717000 @@ -114,8 +115,9 @@ def load_item_csv(): events = [ - ItemData(None, "Victory", ItemClassification.progression), - ItemData(None, "Month End", ItemClassification.progression), + ItemData(None, Event.victory, ItemClassification.progression), + ItemData(None, Event.month_end, ItemClassification.progression), + ItemData(None, Event.can_construct_buildings, ItemClassification.progression), ] all_items: List[ItemData] = load_item_csv() + events @@ -168,6 +170,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items = [] items.extend(item_factory(item) for item in items_by_group[Group.COMMUNITY_REWARD]) + items.append(item_factory("Progressive Movie Theater")) # It is a community reward, but we need two of them create_backpack_items(item_factory, options, items) create_weapons(item_factory, world_options, items) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index a710d75c537d..dd90b5a88880 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -7,6 +7,7 @@ from .. import options from ..stardew_rule import StardewRule, True_, False_, Has from ..strings.artisan_good_names import ArtisanGood +from ..strings.ap_names.event_names import Event from ..strings.building_names import Building from ..strings.fish_names import WaterItem from ..strings.material_names import Material @@ -60,7 +61,7 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): self.building_rules.update(new_rules) def has_building(self, building: str) -> StardewRule: - carpenter_rule = self.region.can_reach(Region.carpenter) + carpenter_rule = self.received(Event.can_construct_buildings) if self.building_option == options.BuildingProgression.option_vanilla: return Has(building, self.building_rules) & carpenter_rule diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9970139981d2..1a6b3c22c5ed 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -46,6 +46,7 @@ from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.ap_names.buff_names import Buff +from ..strings.ap_names.community_upgrade_names import CommunityUpgrade from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building from ..strings.calendar_names import Weekday @@ -341,6 +342,7 @@ def __post_init__(self): Gift.bouquet: self.relationship.has_hearts(Generic.bachelor, 8) & self.money.can_spend_at(Region.pierre_store, 100), Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Consumable.rain_totem), + Gift.movie_ticket: self.money.can_spend_at(Region.movie_ticket_stand, 1000), Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months(), Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200), @@ -548,6 +550,8 @@ def can_buy_seed(self, seed: SeedItem) -> StardewRule: item_rule = True_() else: item_rule = self.received(seed.name) + if seed.name == Seed.coffee: + item_rule = item_rule & self.has_traveling_merchant(3) season_rule = self.season.has_any(seed.seasons) region_rule = self.region.can_reach_all(seed.regions) currency_rule = self.money.can_spend(1000) @@ -609,6 +613,9 @@ def can_smelt(self, item: str) -> StardewRule: return self.has(Machine.furnace) & self.has(item) def has_traveling_merchant(self, tier: int = 1): + if tier <= 0: + return True_() + tier = min(7, max(1, tier)) traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] return self.received(traveling_merchant_days, tier) @@ -876,3 +883,9 @@ def can_ship_everything(self) -> StardewRule: all_items_to_ship.append(location.name[len(shipsanity_prefix):]) return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) + def has_abandoned_jojamart(self) -> StardewRule: + return self.received(CommunityUpgrade.movie_theater, 1) + + def has_movie_theater(self) -> StardewRule: + return self.received(CommunityUpgrade.movie_theater, 2) + diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index e72871fb7b80..e7b1d378f97d 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,5 +1,6 @@ from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule +from ..strings.ap_names.event_names import Event MAX_MONTHS = 12 @@ -14,7 +15,7 @@ def __init__(self, player: int, received_logic: ReceivedLogic): def has_lived_months(self, number: int) -> StardewRule: number = max(0, min(number, MAX_MONTHS)) - return self.received("Month End", number) + return self.received(Event.month_end, number) def has_lived_max_months(self) -> StardewRule: return self.has_lived_months(MAX_MONTHS) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 1ea6f535295d..691dca14c862 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -68,7 +68,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: Entrance.town_to_sam_house, Entrance.town_to_haley_house, Entrance.town_to_sewer, Entrance.town_to_clint_blacksmith, Entrance.town_to_museum, - Entrance.town_to_jojamart, + Entrance.town_to_jojamart, Entrance.purchase_movie_ticket, Entrance.attend_egg_festival, Entrance.attend_fair, Entrance.attend_spirit_eve, Entrance.attend_winter_star]), RegionData(Region.beach, [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, @@ -117,7 +117,10 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.blacksmith_gold, [Entrance.blacksmith_iridium]), RegionData(Region.blacksmith_iridium), RegionData(Region.museum), - RegionData(Region.jojamart), + RegionData(Region.jojamart, [Entrance.enter_abandoned_jojamart]), + RegionData(Region.abandoned_jojamart, [Entrance.enter_movie_theater]), + RegionData(Region.movie_ticket_stand), + RegionData(Region.movie_theater), RegionData(Region.fish_shop, [Entrance.fish_shop_to_boat_tunnel]), RegionData(Region.boat_tunnel, [Entrance.boat_to_ginger_island]), RegionData(Region.elliott_house), @@ -334,6 +337,9 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.town_to_jojamart, Region.jojamart, flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(Entrance.purchase_movie_ticket, Region.movie_ticket_stand), + ConnectionData(Entrance.enter_abandoned_jojamart, Region.abandoned_jojamart), + ConnectionData(Entrance.enter_movie_theater, Region.movie_theater), ConnectionData(Entrance.town_to_beach, Region.beach), ConnectionData(Entrance.enter_elliott_house, Region.elliott_house, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 376e4c022c86..f3feb16a46a1 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -214,6 +214,13 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: logic.wallet.has_rusty_key().simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.town_to_sewer, player), logic.wallet.has_rusty_key().simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_abandoned_jojamart, player), + logic.has_abandoned_jojamart().simplify()) + movie_theater_rule = logic.has_movie_theater().simplify() + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_movie_theater, player), + movie_theater_rule) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.purchase_movie_ticket, player), + movie_theater_rule) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.take_bus_to_desert, player), logic.received("Bus Repair").simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_skull_cavern, player), diff --git a/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py b/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py new file mode 100644 index 000000000000..0be4d31b5384 --- /dev/null +++ b/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py @@ -0,0 +1,2 @@ +class CommunityUpgrade: + movie_theater = "Progressive Movie Theater" diff --git a/worlds/stardew_valley/strings/ap_names/event_names.py b/worlds/stardew_valley/strings/ap_names/event_names.py new file mode 100644 index 000000000000..b84b6c2f939c --- /dev/null +++ b/worlds/stardew_valley/strings/ap_names/event_names.py @@ -0,0 +1,4 @@ +class Event: + victory = "Victory" + month_end = "Month End" + can_construct_buildings = "Can Construct Buildings" diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 3913da73550c..5b47d369e489 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -78,6 +78,9 @@ class Entrance: town_to_clint_blacksmith = "Town to Clint's Blacksmith" town_to_museum = "Town to Museum" town_to_jojamart = "Town to JojaMart" + purchase_movie_ticket = "Purchase Movie Ticket" + enter_abandoned_jojamart = "Enter Abandoned Joja Mart" + enter_movie_theater = "Enter Movie Theater" beach_to_willy_fish_shop = "Beach to Willy's Fish Shop" fish_shop_to_boat_tunnel = "Fish Shop to Boat Tunnel" boat_to_ginger_island = "Take the Boat to Ginger Island" diff --git a/worlds/stardew_valley/strings/gift_names.py b/worlds/stardew_valley/strings/gift_names.py index 8b000570470c..9988dbe96559 100644 --- a/worlds/stardew_valley/strings/gift_names.py +++ b/worlds/stardew_valley/strings/gift_names.py @@ -2,6 +2,7 @@ class Gift: bouquet = "Bouquet" golden_pumpkin = "Golden Pumpkin" mermaid_pendant = "Mermaid's Pendant" + movie_ticket = "Movie Ticket" pearl = "Pearl" tea_set = "Tea Set" void_ghost_pendant = "Void Ghost Pendant" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 13fe8cc74cd0..ef9ae9b4c2ce 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -106,6 +106,9 @@ class Region: haley_house = "Haley's House" sam_house = "Sam's House" jojamart = "JojaMart" + abandoned_jojamart = "Abandoned JojaMart" + movie_theater = "Movie Theater" + movie_ticket_stand = "Ticket Stand" fish_shop = "Willy's Fish Shop" boat_tunnel = "Boat Tunnel" tide_pools = "Tide Pools" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 7d3090659f97..93bbb492483f 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -221,7 +221,8 @@ def test_given_elevator_to_floor_105_when_find_another_elevator_then_has_access_ items_for_115 = self.generate_items_for_mine_115() last_elevator = self.get_item_by_name("Progressive Mine Elevator") self.collect(items_for_115) - floor_115 = self.multiworld.get_region("The Mines - Floor 115", self.player) floor_120 = self.multiworld.get_region("The Mines - Floor 120", self.player) + floor_115 = self.multiworld.get_region("The Mines - Floor 115", self.player) + floor_120 = self.multiworld.get_region("The Mines - Floor 120", self.player) self.assertTrue(floor_115.can_reach(self.multiworld.state)) self.assertFalse(floor_120.can_reach(self.multiworld.state)) @@ -236,7 +237,8 @@ def test_given_access_to_floor_115_when_find_another_pickaxe_and_dagger_then_doe items_for_120 = self.generate_items_for_extra_mine_levels("Progressive Dagger") self.collect(items_for_115) - self.assertTrue(self.multiworld.get_region("The Mines - Floor 115", self.player).can_reach(self.multiworld.state)) + can_reach = self.multiworld.get_region("The Mines - Floor 115", self.player).can_reach(self.multiworld.state) + self.assertTrue(can_reach) self.assertFalse(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) self.collect(items_for_120) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 04c5181c83be..494daa9e873f 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -1,7 +1,6 @@ import unittest from . import SVTestBase, setup_solo_multiworld -from .. import StardewValleyWorld from ..data.bundle_data import all_bundle_items_except_money from ..stardew_rule import MISSING_ITEM, False_ diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 2eb8d94fa224..d60a6bda73be 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -121,6 +121,7 @@ def test_big_coop_blueprint(self): self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + self.multiworld.state.collect(self.world.create_item("Can Construct Buildings"), event=True) self.assertFalse(self.world.logic.region.can_reach_location("Big Coop Blueprint")(self.multiworld.state), f"Rule is {repr(self.multiworld.get_location('Big Coop Blueprint', self.player).access_rule)}") @@ -138,6 +139,7 @@ def test_deluxe_coop_blueprint(self): self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + 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) @@ -156,6 +158,7 @@ def test_big_shed_blueprint(self): self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + self.multiworld.state.collect(self.world.create_item("Can Construct Buildings"), event=True) self.assertFalse(self.world.logic.region.can_reach_location("Big Shed Blueprint")(self.multiworld.state), f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}") From af458ab4dc8c863fcf395e104e3c520765d8e70b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 26 Aug 2023 12:19:02 -0400 Subject: [PATCH 054/482] - Added minsanity options --- worlds/stardew_valley/logic/logic.py | 3 ++ worlds/stardew_valley/rules.py | 6 +-- worlds/stardew_valley/test/TestGeneration.py | 26 ++++++++++-- worlds/stardew_valley/test/__init__.py | 42 ++++++++++++++++++++ 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 1a6b3c22c5ed..e775b197183f 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -889,3 +889,6 @@ def has_abandoned_jojamart(self) -> StardewRule: def has_movie_theater(self) -> StardewRule: return self.received(CommunityUpgrade.movie_theater, 2) + def can_use_obelisk(self, obelisk: str) -> StardewRule: + return self.region.can_reach(Region.wizard_tower) & self.region.can_reach(Region.farm) & self.received(obelisk) + diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index f3feb16a46a1..bec3342e7652 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -231,11 +231,11 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_desert_obelisk, player), - logic.received(Transportation.desert_obelisk).simplify()) + logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_obelisk, player), - logic.received(Transportation.island_obelisk).simplify()) + logic.can_use_obelisk(Transportation.island_obelisk).simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_farm_obelisk, player), - logic.received(Transportation.farm_obelisk).simplify()) + logic.can_use_obelisk(Transportation.farm_obelisk).simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.buy_from_traveling_merchant, player), logic.has_traveling_merchant()) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 93bbb492483f..bffef684a71e 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -5,7 +5,7 @@ allsanity_options_without_mods, minimal_locations_maximal_items from .. import locations, items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name -from ..items import items_by_group, Group +from ..items import items_by_group, Group, item_table from ..locations import LocationTags from ..mods.mod_data import ModNames @@ -279,10 +279,28 @@ def test_minimal_location_maximal_items_still_valid(self): min_max_options = minimal_locations_maximal_items() multiworld = setup_solo_multiworld(min_max_options) valid_locations = get_real_locations(self, multiworld) - self.assertGreaterEqual(len(valid_locations), len(multiworld.itempool)) + number_locations = len(valid_locations) + number_items = len([item for item in multiworld.itempool + if Group.RESOURCE_PACK not in item_table[item.name].groups and Group.TRAP not in item_table[item.name].groups]) + self.assertGreaterEqual(number_locations, number_items) + print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items}") + + def test_minsanity_has_fewer_than_locations(self): + expected_locations = 122 + minsanity_options = self.minsanity_options() + multiworld = setup_solo_multiworld(minsanity_options) + real_locations = get_real_locations(self, multiworld) + number_locations = len(real_locations) + self.assertLessEqual(number_locations, expected_locations) + print(f"Stardew Valley - Minsanity Locations: {number_locations}") + if number_locations != expected_locations: + print(f"\tNew locations detected!" + f"\n\tPlease update test_minsanity_has_fewer_than_locations" + f"\n\t\tExpected: {expected_locations}" + f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1054 + expected_locations = 1633 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -296,7 +314,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 1306 + expected_locations = 1885 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index bb45b8736c9c..9bae6c7d9deb 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -54,25 +54,67 @@ def run_default_tests(self) -> bool: @cache_argsless def minimal_locations_maximal_items(): min_max_options = { +Goal.internal_name: Goal.option_bottom_of_the_mines, + BundleRandomization.internal_name: BundleRandomization.option_vanilla, + BundlePrice.internal_name: BundlePrice.option_very_cheap, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, Cropsanity.internal_name: Cropsanity.option_enabled, BackpackProgression.internal_name: BackpackProgression.option_vanilla, ToolProgression.internal_name: ToolProgression.option_vanilla, SkillProgression.internal_name: SkillProgression.option_vanilla, BuildingProgression.internal_name: BuildingProgression.option_vanilla, + FestivalLocations.internal_name: FestivalLocations.option_disabled, ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, HelpWantedLocations.internal_name: 0, Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, + FriendsanityHeartSize.internal_name: 8, NumberOfMovementBuffs.internal_name: 12, NumberOfLuckBuffs.internal_name: 12, + options.ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + options.TrapItems.internal_name: TrapItems.option_nightmare, + options.Mods.internal_name: (), } return min_max_options +@cache_argsless +def minsanity_options(): + minsanity = { + Goal.internal_name: Goal.option_bottom_of_the_mines, + BundleRandomization.internal_name: BundleRandomization.option_vanilla, + BundlePrice.internal_name: BundlePrice.option_very_cheap, + SeasonRandomization.internal_name: SeasonRandomization.option_disabled, + Cropsanity.internal_name: Cropsanity.option_disabled, + BackpackProgression.internal_name: BackpackProgression.option_vanilla, + ToolProgression.internal_name: ToolProgression.option_vanilla, + SkillProgression.internal_name: SkillProgression.option_vanilla, + BuildingProgression.internal_name: BuildingProgression.option_vanilla, + FestivalLocations.internal_name: FestivalLocations.option_disabled, + ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, + ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, + HelpWantedLocations.internal_name: 0, + Fishsanity.internal_name: Fishsanity.option_none, + Museumsanity.internal_name: Museumsanity.option_none, + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, + Friendsanity.internal_name: Friendsanity.option_none, + FriendsanityHeartSize.internal_name: 8, + NumberOfMovementBuffs.internal_name: 0, + NumberOfLuckBuffs.internal_name: 0, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + TrapItems.internal_name: TrapItems.option_no_traps, + Mods.internal_name: (), + } + return minsanity + + @cache_argsless def default_options(): default = {} From 0344b59401e60d93278e5f6f97ff4c18ae5545af Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 26 Aug 2023 19:44:59 -0400 Subject: [PATCH 055/482] - Add new options for buildings and tools to be cheaper # Conflicts: # worlds/stardew_valley/options.py --- worlds/stardew_valley/options.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 6d3dc2fc5219..e5bfe8e5daee 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -192,12 +192,18 @@ class BackpackProgression(Choice): class ToolProgression(Choice): """Shuffle the tool upgrades? Vanilla: Clint will upgrade your tools with metal bars. - Progressive: You will randomly find Progressive Tool upgrades.""" + Progressive: You will randomly find Progressive Tool upgrades. + Cheap: Tool Upgrades will cost half as much + Very Cheap: Tool Upgrades will cost 1/5th as much""" internal_name = "tool_progression" display_name = "Tool Progression" default = 1 option_vanilla = 0 option_progressive = 1 + option_vanilla_cheap = 2 + option_vanilla_very_cheap = 3 + option_progressive_cheap = 4 + option_progressive_very_cheap = 5 class ElevatorProgression(Choice): @@ -231,6 +237,8 @@ class BuildingProgression(Choice): Progressive: You will receive the buildings and will be able to build the first one of each type for free, once it is received. If you want more of the same building, it will cost the vanilla price. Progressive early shipping bin: Same as Progressive, but the shipping bin will be placed early in the multiworld. + Cheap: Buildings will cost as much + Very Cheap: Buildings will cost 1/5th as much """ internal_name = "building_progression" display_name = "Building Progression" @@ -238,6 +246,12 @@ class BuildingProgression(Choice): option_vanilla = 0 option_progressive = 1 option_progressive_early_shipping_bin = 2 + option_vanilla_cheap = 3 + option_vanilla_very_cheap = 4 + option_progressive_cheap = 5 + option_progressive_very_cheap = 6 + option_progressive_early_shipping_bin_cheap = 7 + option_progressive_early_shipping_bin_very_cheap = 8 class FestivalLocations(Choice): From 501fe5004ec2b642be46e712c87a3cfff94419db Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 31 Aug 2023 00:35:36 -0400 Subject: [PATCH 056/482] - Turned ToolProgression and BUildingProgression into flags so the mod has an easier time with them --- worlds/stardew_valley/items.py | 8 +-- worlds/stardew_valley/locations.py | 4 +- worlds/stardew_valley/logic/building_logic.py | 4 +- worlds/stardew_valley/logic/mine_logic.py | 6 +- worlds/stardew_valley/logic/tool_logic.py | 4 +- worlds/stardew_valley/options.py | 32 +++++----- worlds/stardew_valley/rules.py | 19 +++--- worlds/stardew_valley/test/TestOptionFlags.py | 59 +++++++++++++++++++ 8 files changed, 98 insertions(+), 38 deletions(-) create mode 100644 worlds/stardew_valley/test/TestOptionFlags.py diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 1ecd9502a652..42790c5486ff 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -247,8 +247,8 @@ def create_elevators(item_factory: StardewItemFactory, world_options: StardewOpt items.extend([item_factory(item) for item in ["Progressive Skull Cavern Elevator"] * 8]) -def create_tools(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if options.tool_progression == ToolProgression.option_progressive: +def create_tools(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + if world_options[options.ToolProgression] & options.ToolProgression.option_progressive: for item_data in items_by_group[Group.PROGRESSIVE_TOOLS]: name = item_data.name if "Trash Can" in name: @@ -286,7 +286,7 @@ def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewVa def create_carpenter_buildings(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): building_option = world_options[options.BuildingProgression] - if building_option == options.BuildingProgression.option_vanilla: + if building_option & options.BuildingProgression.option_vanilla: return items.append(item_factory("Progressive Coop")) items.append(item_factory("Progressive Coop")) @@ -302,7 +302,7 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, world_options: items.append(item_factory("Fish Pond")) items.append(item_factory("Stable")) items.append(item_factory("Slime Hutch")) - needs_early_bin = building_option == options.BuildingProgression.option_progressive_early_shipping_bin + needs_early_bin = building_option & options.BuildingProgression.option_progressive_early_shipping_bin has_shipsanity = world_options[options.Shipsanity] != options.Shipsanity.option_none need_shipping = needs_early_bin or has_shipsanity or world_is_perfection(world_options) items.append(item_factory("Shipping Bin", ItemClassification.progression if need_shipping else ItemClassification.useful)) diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 35e930be254d..1a590071384f 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -353,7 +353,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_mandatory_locations(randomized_locations, options) extend_backpack_locations(randomized_locations, options) - if not options.tool_progression == ToolProgression.option_vanilla: + if not world_options[options.ToolProgression] & options.ToolProgression.option_vanilla: randomized_locations.extend(locations_by_tag[LocationTags.TOOL_UPGRADE]) extend_elevator_locations(randomized_locations, options) @@ -363,7 +363,7 @@ def create_locations(location_collector: StardewLocationCollector, if location.mod_name is None or location.mod_name in options.mods: randomized_locations.append(location_table[location.name]) - if not options.building_progression == BuildingProgression.option_vanilla: + if not world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla: for location in locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: if location.mod_name is None or location.mod_name in options.mods: randomized_locations.append(location_table[location.name]) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index dd90b5a88880..2dbe3d094270 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -62,7 +62,7 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): def has_building(self, building: str) -> StardewRule: carpenter_rule = self.received(Event.can_construct_buildings) - if self.building_option == options.BuildingProgression.option_vanilla: + if self.building_option & options.BuildingProgression.option_vanilla: return Has(building, self.building_rules) & carpenter_rule count = 1 @@ -83,7 +83,7 @@ def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level > 3: return False_() - if not self.building_option == options.BuildingProgression.option_vanilla: + if not self.building_option & options.BuildingProgression.option_vanilla: return self.received(f"Progressive House", upgrade_level) & self.region.can_reach(Region.carpenter) if upgrade_level == 1: diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 85685d4278e5..90589b051e7a 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -69,7 +69,7 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) - if self.tool_option == options.ToolProgression.option_progressive: + if self.tool_option & options.ToolProgression.option_progressive: rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) if self.skill_option == options.SkillProgression.option_progressive: combat_tier = min(10, max(0, tier * 2)) @@ -81,7 +81,7 @@ def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) - if self.tool_option == options.ToolProgression.option_progressive: + if self.tool_option & options.ToolProgression.option_progressive: rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) if self.skill_option == options.SkillProgression.option_progressive: combat_tier = min(10, max(0, tier * 2)) @@ -106,7 +106,7 @@ def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule rules = [] weapon_rule = self.combat.has_great_weapon() rules.append(weapon_rule) - if self.tool_option == options.ToolProgression.option_progressive: + if self.tool_option & options.ToolProgression.option_progressive: rules.append(self.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) if self.skill_option == options.SkillProgression.option_progressive: skill_tier = min(10, max(0, tier * 2 + 6)) diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 634bfcbb20de..e03362caf091 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -54,13 +54,13 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule if material == ToolMaterial.basic or tool == Tool.scythe: return True_() - if self.tool_option == options.ToolProgression.option_progressive: + if self.tool_option & options.ToolProgression.option_progressive: return self.received(f"Progressive {tool}", tool_materials[material]) return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) def has_fishing_rod(self, level: int) -> StardewRule: - if self.tool_option == options.ToolProgression.option_progressive: + if self.tool_option & options.ToolProgression.option_progressive: return self.received(f"Progressive {Tool.fishing_rod}", level) if level <= 1: diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index e5bfe8e5daee..f3be783b531a 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -197,13 +197,13 @@ class ToolProgression(Choice): Very Cheap: Tool Upgrades will cost 1/5th as much""" internal_name = "tool_progression" display_name = "Tool Progression" - default = 1 - option_vanilla = 0 - option_progressive = 1 - option_vanilla_cheap = 2 - option_vanilla_very_cheap = 3 - option_progressive_cheap = 4 - option_progressive_very_cheap = 5 + default = 2 + option_vanilla = 0b0001 # 1 + option_progressive = 0b0010 # 2 + option_vanilla_cheap = 0b0101 # 5 + option_vanilla_very_cheap = 0b1001 # 9 + option_progressive_cheap = 0b0110 # 6 + option_progressive_very_cheap = 0b1010 # 10 class ElevatorProgression(Choice): @@ -243,15 +243,15 @@ class BuildingProgression(Choice): internal_name = "building_progression" display_name = "Building Progression" default = 2 - option_vanilla = 0 - option_progressive = 1 - option_progressive_early_shipping_bin = 2 - option_vanilla_cheap = 3 - option_vanilla_very_cheap = 4 - option_progressive_cheap = 5 - option_progressive_very_cheap = 6 - option_progressive_early_shipping_bin_cheap = 7 - option_progressive_early_shipping_bin_very_cheap = 8 + option_vanilla = 0b00001 # 1 + option_progressive = 0b00010 # 2 + option_progressive_early_shipping_bin = 0b00110 # 6 + option_vanilla_cheap = 0b01001 # 9 + option_vanilla_very_cheap = 0b10001 # 17 + option_progressive_cheap = 0b01010 # 10 + option_progressive_very_cheap = 0b10010 # 18 + option_progressive_early_shipping_bin_cheap = 0b01110 # 14 + option_progressive_early_shipping_bin_very_cheap = 0b10110 # 22 class FestivalLocations(Choice): diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index bec3342e7652..538fa462ed86 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -87,9 +87,8 @@ def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): logic.relationship.can_reproduce(2).simplify()) -def set_tool_rules(logic: StardewLogic, multiworld, player, world_options): - # Those checks do not exist if ToolProgression is vanilla - if world_options.tool_progression == ToolProgression.option_vanilla: +def set_tool_rules(logic: StardewLogic, multi_world, player, world_options): + if world_options[options.ToolProgression] & options.ToolProgression.option_vanilla: return MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), @@ -107,12 +106,14 @@ def set_tool_rules(logic: StardewLogic, multiworld, player, world_options): def set_building_rules(logic: StardewLogic, multi_world, player, world_options): - if world_options[options.BuildingProgression] != options.BuildingProgression.option_vanilla: - for building in locations.locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: - if building.mod_name is not None and building.mod_name not in world_options[options.Mods]: - continue - MultiWorldRules.set_rule(multi_world.get_location(building.name, player), - logic.buildings.building_rules[building.name.replace(" Blueprint", "")].simplify()) + if world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla: + return + + for building in locations.locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: + if building.mod_name is not None and building.mod_name not in world_options[options.Mods]: + continue + MultiWorldRules.set_rule(multi_world.get_location(building.name, player), + logic.buildings.building_rules[building.name.replace(" Blueprint", "")].simplify()) def set_bundle_rules(current_bundles, logic: StardewLogic, multi_world, player): diff --git a/worlds/stardew_valley/test/TestOptionFlags.py b/worlds/stardew_valley/test/TestOptionFlags.py new file mode 100644 index 000000000000..1395932fb5db --- /dev/null +++ b/worlds/stardew_valley/test/TestOptionFlags.py @@ -0,0 +1,59 @@ +from . import SVTestBase +from .. import options + + +class TestBitFlagsProgressive(SVTestBase): + options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive} + + def test_options_are_detected_as_progressive(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + self.assertTrue(tool_progressive) + self.assertTrue(building_progressive) + + def test_options_are_not_detected_as_vanilla(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla + self.assertFalse(tool_progressive) + self.assertFalse(building_progressive) + + +class TestBitFlagsProgressiveCheap(SVTestBase): + options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive_cheap, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_cheap} + + def test_options_are_detected_as_progressive(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + self.assertTrue(tool_progressive) + self.assertTrue(building_progressive) + + def test_options_are_not_detected_as_vanilla(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla + self.assertFalse(tool_progressive) + self.assertFalse(building_progressive) + + +class TestBitFlagsProgressiveVeryCheap(SVTestBase): + options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive_very_cheap, + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_very_cheap} + + def test_options_are_detected_as_progressive(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + self.assertTrue(tool_progressive) + self.assertTrue(building_progressive) + + def test_options_are_not_detected_as_vanilla(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla + self.assertFalse(tool_progressive) + self.assertFalse(building_progressive) From 8d9f1cbd4f7e091fccb028a8f5e2da01ad70b179 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 31 Aug 2023 00:41:46 -0400 Subject: [PATCH 057/482] - Added a few more bitflag tests --- worlds/stardew_valley/test/TestOptionFlags.py | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/worlds/stardew_valley/test/TestOptionFlags.py b/worlds/stardew_valley/test/TestOptionFlags.py index 1395932fb5db..bb29fe24fccb 100644 --- a/worlds/stardew_valley/test/TestOptionFlags.py +++ b/worlds/stardew_valley/test/TestOptionFlags.py @@ -2,6 +2,78 @@ from .. import options +class TestBitFlagsVanilla(SVTestBase): + options = {options.ToolProgression.internal_name: options.ToolProgression.option_vanilla, + options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla} + + def test_options_are_not_detected_as_progressive(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + self.assertFalse(tool_progressive) + self.assertFalse(building_progressive) + + def test_options_are_detected_as_vanilla(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla + self.assertTrue(tool_progressive) + self.assertTrue(building_progressive) + + def test_tools_and_buildings_not_in_pool(self): + item_names = [item.name for item in self.multiworld.itempool] + self.assertNotIn("Progressive Coop", item_names) + self.assertNotIn("Progressive Pickaxe", item_names) + + +class TestBitFlagsVanillaCheap(SVTestBase): + options = {options.ToolProgression.internal_name: options.ToolProgression.option_vanilla_cheap, + options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla_cheap} + + def test_options_are_not_detected_as_progressive(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + self.assertFalse(tool_progressive) + self.assertFalse(building_progressive) + + def test_options_are_detected_as_vanilla(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla + self.assertTrue(tool_progressive) + self.assertTrue(building_progressive) + + def test_tools_and_buildings_not_in_pool(self): + item_names = [item.name for item in self.multiworld.itempool] + self.assertNotIn("Progressive Coop", item_names) + self.assertNotIn("Progressive Pickaxe", item_names) + + +class TestBitFlagsVanillaVeryCheap(SVTestBase): + options = {options.ToolProgression.internal_name: options.ToolProgression.option_vanilla_very_cheap, + options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla_very_cheap} + + def test_options_are_not_detected_as_progressive(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + self.assertFalse(tool_progressive) + self.assertFalse(building_progressive) + + def test_options_are_detected_as_vanilla(self): + world_options = self.multiworld.worlds[self.player].options + tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla + building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla + self.assertTrue(tool_progressive) + self.assertTrue(building_progressive) + + def test_tools_and_buildings_not_in_pool(self): + item_names = [item.name for item in self.multiworld.itempool] + self.assertNotIn("Progressive Coop", item_names) + self.assertNotIn("Progressive Pickaxe", item_names) + + class TestBitFlagsProgressive(SVTestBase): options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive, options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive} @@ -20,6 +92,11 @@ def test_options_are_not_detected_as_vanilla(self): self.assertFalse(tool_progressive) self.assertFalse(building_progressive) + def test_tools_and_buildings_in_pool(self): + item_names = [item.name for item in self.multiworld.itempool] + self.assertIn("Progressive Coop", item_names) + self.assertIn("Progressive Pickaxe", item_names) + class TestBitFlagsProgressiveCheap(SVTestBase): options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive_cheap, @@ -39,6 +116,11 @@ def test_options_are_not_detected_as_vanilla(self): self.assertFalse(tool_progressive) self.assertFalse(building_progressive) + def test_tools_and_buildings_in_pool(self): + item_names = [item.name for item in self.multiworld.itempool] + self.assertIn("Progressive Coop", item_names) + self.assertIn("Progressive Pickaxe", item_names) + class TestBitFlagsProgressiveVeryCheap(SVTestBase): options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive_very_cheap, @@ -57,3 +139,8 @@ def test_options_are_not_detected_as_vanilla(self): building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla self.assertFalse(tool_progressive) self.assertFalse(building_progressive) + + def test_tools_and_buildings_in_pool(self): + item_names = [item.name for item in self.multiworld.itempool] + self.assertIn("Progressive Coop", item_names) + self.assertIn("Progressive Pickaxe", item_names) From b50906e45bff3160309482f5c8e76f9a34be7b53 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 4 Sep 2023 22:06:36 -0400 Subject: [PATCH 058/482] - Rebase from main --- worlds/stardew_valley/logic/logic.py | 16 +----- .../logic/relationship_logic.py | 2 + worlds/stardew_valley/logic/shipping_logic.py | 39 +++++++++++++ .../logic/special_order_logic.py | 55 ++++++++++--------- 4 files changed, 72 insertions(+), 40 deletions(-) create mode 100644 worlds/stardew_valley/logic/shipping_logic.py diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index e775b197183f..a7708b1bfeb9 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -629,7 +629,7 @@ def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_requ item_rules.append(bundle_item.item.name) if bundle_item.quality > highest_quality_yet: highest_quality_yet = bundle_item.quality - return self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) + return self.region.can_reach(Region.wizard_tower) & self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) def can_grow_gold_quality(self, quality: int) -> StardewRule: if quality <= 0: @@ -869,20 +869,6 @@ def has_all_rarecrows(self) -> StardewRule: rules.append(self.received(f"Rarecrow #{rarecrow_number}")) return And(rules) - def can_ship(self, item: str) -> StardewRule: - return self.buildings.has_building(Building.shipping_bin) & self.has(item) - - def can_ship_everything(self) -> StardewRule: - shipsanity_prefix = "Shipsanity: " - all_items_to_ship = [] - include_island = self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_false - include_qi = self.options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_qi - for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: - if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ - (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): - all_items_to_ship.append(location.name[len(shipsanity_prefix):]) - return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) - def has_abandoned_jojamart(self) -> StardewRule: return self.received(CommunityUpgrade.movie_theater, 1) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index e9542f00f3eb..ea8cbc8ca03f 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -112,6 +112,8 @@ def can_meet(self, npc: str) -> StardewRule: rules = [self.region.can_reach_any(villager.locations)] if npc == NPC.kent: rules.append(self.time.has_year_two()) + elif npc == NPC.leo: + rules.append(self.received("Island West Turtle")) return And(rules) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py new file mode 100644 index 000000000000..f7ae8c4d2aee --- /dev/null +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -0,0 +1,39 @@ + +from .building_logic import BuildingLogic +from .has_logic import HasLogic +from .. import options +from ..locations import LocationTags, locations_by_tag +from ..stardew_rule import StardewRule, And +from ..strings.building_names import Building + + +class ShippingLogic: + player: int + exclude_ginger_island: int + special_orders_option: int + has: HasLogic + buildings: BuildingLogic + + def __init__(self, player: int, exclude_ginger_island: int, special_orders_option: int, has: HasLogic, buildings: BuildingLogic): + self.player = player + self.exclude_ginger_island = exclude_ginger_island + self.special_orders_option = special_orders_option + self.has = has + self.buildings = buildings + + def can_ship(self, item: str = "") -> StardewRule: + shipping_bin_rule = self.buildings.has_building(Building.shipping_bin) + if item == "": + return shipping_bin_rule + return shipping_bin_rule & self.has(item) + + def can_ship_everything(self) -> StardewRule: + shipsanity_prefix = "Shipsanity: " + all_items_to_ship = [] + include_island = self.exclude_ginger_island == options.ExcludeGingerIsland.option_false + include_qi = self.special_orders_option == options.SpecialOrderLocations.option_board_qi + for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: + if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ + (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): + all_items_to_ship.append(location.name[len(shipsanity_prefix):]) + return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index e405377252bc..ad807921a9b9 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -11,6 +11,7 @@ from .region_logic import RegionLogic from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic +from .shipping_logic import ShippingLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic from ..stardew_rule import StardewRule, Has @@ -39,6 +40,7 @@ class SpecialOrderLogic: season: SeasonLogic time: TimeLogic money: MoneyLogic + shipping: ShippingLogic arcade: ArcadeLogic artisan: ArtisanLogic relationship: RelationshipLogic @@ -49,8 +51,8 @@ class SpecialOrderLogic: special_order_rules: Dict[str, StardewRule] def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, - arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, skill: SkillLogic, mine: MineLogic, cooking: CookingLogic, - ability: AbilityLogic): + shipping: ShippingLogic, arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, skill: SkillLogic, mine: MineLogic, + cooking: CookingLogic, ability: AbilityLogic): self.player = player self.received = received self.has = has @@ -58,6 +60,7 @@ def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: self.season = season self.time = time self.money = money + self.shipping = shipping self.arcade = arcade self.artisan = artisan self.relationship = relationship @@ -69,36 +72,38 @@ def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: def initialize_rules(self): self.special_order_rules.update({ - SpecialOrder.island_ingredients: self.has_island_transport() & self.ability.can_farm_perfectly() & - self.has(Vegetable.taro_root) & self.has(Fruit.pineapple) & self.has(Forageable.ginger), - SpecialOrder.cave_patrol: self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(120), - SpecialOrder.aquatic_overpopulation: self.ability.can_fish_perfectly(), - SpecialOrder.biome_balance: self.ability.can_fish_perfectly(), - SpecialOrder.rock_rejuivenation: self.has(Mineral.ruby) & self.has(Mineral.topaz) & self.has(Mineral.emerald) & - self.has(Mineral.jade) & self.has(Mineral.amethyst) & self.relationship.has_hearts(NPC.emily, 4) & + SpecialOrder.island_ingredients: self.relationship.can_meet(NPC.caroline) & self.has_island_transport() & self.ability.can_farm_perfectly() & + self.shipping.can_ship(Vegetable.taro_root) & self.shipping.can_ship(Fruit.pineapple) & self.shipping.can_ship(Forageable.ginger), + SpecialOrder.cave_patrol: self.relationship.can_meet(NPC.clint) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(120), + SpecialOrder.aquatic_overpopulation: self.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), + SpecialOrder.biome_balance: self.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), + SpecialOrder.rock_rejuivenation: self.relationship.has_hearts(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & + self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & self.has(ArtisanGood.cloth) & self.region.can_reach(Region.haley_house), - SpecialOrder.gifts_for_george: self.season.has(Season.spring) & self.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.dig_site), - SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), - SpecialOrder.crop_order: self.ability.can_farm_perfectly(), - SpecialOrder.community_cleanup: self.skill.can_crab_pot(), - SpecialOrder.the_strong_stuff: self.artisan.can_keg(Vegetable.potato), - SpecialOrder.pierres_prime_produce: self.ability.can_farm_perfectly(), - SpecialOrder.robins_project: self.ability.can_chop_perfectly() & self.has(Material.hardwood), - SpecialOrder.robins_resource_rush: self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted_yum: self.has(Loot.bug_meat), - SpecialOrder.tropical_fish: self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), - SpecialOrder.a_curious_substance: self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), - SpecialOrder.prismatic_jelly: self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(40), + SpecialOrder.gifts_for_george: self.can_reach_region(Region.alex_house) & self.season.has(Season.spring) & self.has(Forageable.leek), + SpecialOrder.fragments_of_the_past: self.can_reach_region(Region.museum) & self.region.can_reach(Region.dig_site) & self.has_tool(Tool.pickaxe), + SpecialOrder.gus_famous_omelet: self.can_reach_region(Region.saloon) & self.has(AnimalProduct.any_egg), + SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.can_ship(), + SpecialOrder.community_cleanup: self.can_reach_region(Region.railroad) & self.skill.can_crab_pot(), + SpecialOrder.the_strong_stuff: self.can_reach_region(Region.trailer) & self.artisan.can_keg(Vegetable.potato), + SpecialOrder.pierres_prime_produce: self.can_reach_region(Region.pierre_store) & self.ability.can_farm_perfectly(), + SpecialOrder.robins_project: self.can_meet(NPC.robin) & self.can_reach_region(Region.carpenter) & + self.ability.can_chop_perfectly() & self.has(Material.hardwood), + SpecialOrder.robins_resource_rush: self.can_meet(NPC.robin) & self.can_reach_region(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), + SpecialOrder.juicy_bugs_wanted_yum: self.can_reach_region(Region.beach) & self.has(Loot.bug_meat), + SpecialOrder.tropical_fish: self.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & + self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), + SpecialOrder.a_curious_substance: self.can_reach_region(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), + SpecialOrder.prismatic_jelly: self.can_reach_region(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(40), SpecialOrder.qis_crop: self.ability.can_farm_perfectly() & self.region.can_reach(Region.greenhouse) & self.region.can_reach(Region.island_west) & self.skill.has_total_level(50) & - self.has(Machine.seed_maker), + self.has(Machine.seed_maker) & self.shipping.can_ship(), SpecialOrder.lets_play_a_game: self.arcade.has_junimo_kart_max_level(), SpecialOrder.four_precious_stones: self.time.has_lived_max_months() & self.has("Prismatic Shard") & self.ability.can_mine_perfectly_in_the_skull_cavern(), SpecialOrder.qis_hungry_challenge: self.ability.can_mine_perfectly_in_the_skull_cavern() & self.ability.has_max_buffs(), - SpecialOrder.qis_cuisine: self.cooking.can_cook() & ( - self.money.can_spend_at(Region.saloon, 205000) | self.money.can_spend_at(Region.pierre_store, 170000)), + SpecialOrder.qis_cuisine: self.cooking.can_cook() & self.shipping.can_ship() & + (self.money.can_spend_at(Region.saloon, 205000) | self.money.can_spend_at(Region.pierre_store, 170000)), SpecialOrder.qis_kindness: self.relationship.can_give_loved_gifts_to_everyone(), SpecialOrder.extended_family: self.ability.can_fish_perfectly() & self.has(Fish.angler) & self.has(Fish.glacierfish) & self.has(Fish.crimsonfish) & self.has(Fish.mutant_carp) & self.has(Fish.legend), From 15c37b68485f85b70ba9038e93fd5ce6a2cb9533 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 4 Sep 2023 22:19:47 -0400 Subject: [PATCH 059/482] - Finished the fixes for extracting shipping logic --- worlds/stardew_valley/logic/logic.py | 7 ++-- .../logic/special_order_logic.py | 38 ++++++++++--------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index a7708b1bfeb9..71ef79576c4d 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -23,6 +23,7 @@ from .region_logic import RegionLogic from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic +from .shipping_logic import ShippingLogic from .skill_logic import SkillLogic from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogic @@ -31,7 +32,6 @@ from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name from ..data.monster_data import all_monsters_by_category, all_monsters_by_name -from ..locations import LocationTags, locations_by_tag from ..mods.logic.mod_logic import ModLogic from .. import options from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops @@ -119,6 +119,7 @@ def __post_init__(self): heart_size_option = self.options[options.FriendsanityHeartSize] mods_option = self.options[options.Mods] self.buildings = BuildingLogic(self.player, self.options[options.BuildingProgression], self.received, self.has, self.region, self.money, mods_option) + self.shipping = ShippingLogic(self.player, self.options[options.ExcludeGingerIsland], self.options[options.SpecialOrderLocations], self.has, self.buildings) self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.options[options.Museumsanity], self.received, self.has, self.region, self.action) @@ -135,8 +136,8 @@ def __post_init__(self): self.crafting = CraftingLogic(self.player, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, self.region, self.tool, self.skill, self.mine) - self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.arcade, self.artisan, - self.relationship, self.skill, self.mine, self.cooking, self.ability) + self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, + self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability) diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index ad807921a9b9..c18ad900588f 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -14,6 +14,7 @@ from .shipping_logic import ShippingLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic +from .tool_logic import ToolLogic from ..stardew_rule import StardewRule, Has from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.transport_names import Transportation @@ -29,6 +30,7 @@ from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.special_order_names import SpecialOrder +from ..strings.tool_names import Tool from ..strings.villager_names import NPC @@ -44,6 +46,7 @@ class SpecialOrderLogic: arcade: ArcadeLogic artisan: ArtisanLogic relationship: RelationshipLogic + tool: ToolLogic skill: SkillLogic mine: MineLogic cooking: CookingLogic @@ -51,8 +54,8 @@ class SpecialOrderLogic: special_order_rules: Dict[str, StardewRule] def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, - shipping: ShippingLogic, arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, skill: SkillLogic, mine: MineLogic, - cooking: CookingLogic, ability: AbilityLogic): + shipping: ShippingLogic, arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, tool: ToolLogic, skill: SkillLogic, + mine: MineLogic, cooking: CookingLogic, ability: AbilityLogic): self.player = player self.received = received self.has = has @@ -64,6 +67,7 @@ def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: self.arcade = arcade self.artisan = artisan self.relationship = relationship + self.tool = tool self.skill = skill self.mine = mine self.cooking = cooking @@ -75,26 +79,26 @@ def initialize_rules(self): SpecialOrder.island_ingredients: self.relationship.can_meet(NPC.caroline) & self.has_island_transport() & self.ability.can_farm_perfectly() & self.shipping.can_ship(Vegetable.taro_root) & self.shipping.can_ship(Fruit.pineapple) & self.shipping.can_ship(Forageable.ginger), SpecialOrder.cave_patrol: self.relationship.can_meet(NPC.clint) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(120), - SpecialOrder.aquatic_overpopulation: self.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), - SpecialOrder.biome_balance: self.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), + SpecialOrder.aquatic_overpopulation: self.relationship.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), + SpecialOrder.biome_balance: self.relationship.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), SpecialOrder.rock_rejuivenation: self.relationship.has_hearts(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & self.has(ArtisanGood.cloth) & self.region.can_reach(Region.haley_house), - SpecialOrder.gifts_for_george: self.can_reach_region(Region.alex_house) & self.season.has(Season.spring) & self.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.can_reach_region(Region.museum) & self.region.can_reach(Region.dig_site) & self.has_tool(Tool.pickaxe), - SpecialOrder.gus_famous_omelet: self.can_reach_region(Region.saloon) & self.has(AnimalProduct.any_egg), - SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.can_ship(), - SpecialOrder.community_cleanup: self.can_reach_region(Region.railroad) & self.skill.can_crab_pot(), - SpecialOrder.the_strong_stuff: self.can_reach_region(Region.trailer) & self.artisan.can_keg(Vegetable.potato), - SpecialOrder.pierres_prime_produce: self.can_reach_region(Region.pierre_store) & self.ability.can_farm_perfectly(), - SpecialOrder.robins_project: self.can_meet(NPC.robin) & self.can_reach_region(Region.carpenter) & + SpecialOrder.gifts_for_george: self.region.can_reach(Region.alex_house) & self.season.has(Season.spring) & self.has(Forageable.leek), + SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.museum) & self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), + SpecialOrder.gus_famous_omelet: self.region.can_reach(Region.saloon) & self.has(AnimalProduct.any_egg), + SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.shipping.can_ship(), + SpecialOrder.community_cleanup: self.region.can_reach(Region.railroad) & self.skill.can_crab_pot(), + SpecialOrder.the_strong_stuff: self.region.can_reach(Region.trailer) & self.artisan.can_keg(Vegetable.potato), + SpecialOrder.pierres_prime_produce: self.region.can_reach(Region.pierre_store) & self.ability.can_farm_perfectly(), + SpecialOrder.robins_project: self.relationship.can_meet(NPC.robin) & self.region.can_reach(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Material.hardwood), - SpecialOrder.robins_resource_rush: self.can_meet(NPC.robin) & self.can_reach_region(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted_yum: self.can_reach_region(Region.beach) & self.has(Loot.bug_meat), - SpecialOrder.tropical_fish: self.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & + SpecialOrder.robins_resource_rush: self.relationship.can_meet(NPC.robin) & self.region.can_reach(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), + SpecialOrder.juicy_bugs_wanted_yum: self.region.can_reach(Region.beach) & self.has(Loot.bug_meat), + SpecialOrder.tropical_fish: self.relationship.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), - SpecialOrder.a_curious_substance: self.can_reach_region(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), - SpecialOrder.prismatic_jelly: self.can_reach_region(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(40), + SpecialOrder.a_curious_substance: self.region.can_reach(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), + SpecialOrder.prismatic_jelly: self.region.can_reach(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(40), SpecialOrder.qis_crop: self.ability.can_farm_perfectly() & self.region.can_reach(Region.greenhouse) & self.region.can_reach(Region.island_west) & self.skill.has_total_level(50) & self.has(Machine.seed_maker) & self.shipping.can_ship(), From 34c156de9470abfc4164ac390848bf0f4b41949b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 4 Sep 2023 22:20:09 -0400 Subject: [PATCH 060/482] - Missed a rule --- worlds/stardew_valley/rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 538fa462ed86..f1af49b2975e 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -714,7 +714,7 @@ def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, mul continue item_to_ship = location.name[len(shipsanity_prefix):] MultiWorldRules.set_rule(multi_world.get_location(location.name, player), - logic.can_ship(item_to_ship)) + logic.shipping.can_ship(item_to_ship)) def set_traveling_merchant_day_rules(logic: StardewLogic, multi_world: MultiWorld, player: int): From 8e1cbea7d297cb35a186659f6481b3dbbe107560 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 4 Sep 2023 22:24:49 -0400 Subject: [PATCH 061/482] - Fixed the rule in the goal --- worlds/stardew_valley/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 2e0f1c723b38..e1443cf9fd5d 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -222,7 +222,7 @@ def setup_victory(self): Event.victory) elif self.options[options.Goal] == options.Goal.option_full_shipment: self.create_event_location(location_table[Goal.full_shipment], - self.logic.can_ship_everything().simplify(), + self.logic.shipping.can_ship_everything().simplify(), Event.victory) elif self.options[options.Goal] == options.Goal.option_perfection: self.create_event_location(location_table[Goal.perfection], From 40d9c3bd6c58f7b6255d8f8fd29706ec0493c3d7 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 6 Sep 2023 12:44:28 -0400 Subject: [PATCH 062/482] - Rename, modify monstersanity monster names and subset, to match more closely the vanilla monster slaying goals --- worlds/stardew_valley/data/locations.csv | 74 +++++++++--------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 4224b68fbaeb..c9df23743050 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1676,54 +1676,32 @@ id,region,name,tags,mod_name 3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", 3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", 3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3102,Adventurer's Guild,Monster Eradication: Blue Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3103,Adventurer's Guild,Monster Eradication: Red Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3104,Adventurer's Guild,Monster Eradication: Purple Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3105,Adventurer's Guild,Monster Eradication: Yellow Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3106,Adventurer's Guild,Monster Eradication: Black Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3107,Adventurer's Guild,Monster Eradication: Copper Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3108,Adventurer's Guild,Monster Eradication: Iron Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3109,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3110,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3111,Adventurer's Guild,Monster Eradication: Dangerous Shadow Shaman,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3112,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3113,Adventurer's Guild,Monster Eradication: Dangerous Shadow Brute,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3114,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3115,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3116,Adventurer's Guild,Monster Eradication: Dangerous Bat,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3117,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3118,Adventurer's Guild,Monster Eradication: Dangerous Frost Bat,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3119,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3120,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3121,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3122,Adventurer's Guild,Monster Eradication: Dangerous Skeleton,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3123,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3124,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3125,Adventurer's Guild,Monster Eradication: Dangerous Bug,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3126,Adventurer's Guild,Monster Eradication: Cave Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3127,Adventurer's Guild,Monster Eradication: Dangerous Cave Fly,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3128,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3129,Adventurer's Guild,Monster Eradication: Dangerous Grub,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3130,Adventurer's Guild,Monster Eradication: Mutant Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", -3131,Adventurer's Guild,Monster Eradication: Mutant Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER,REQUIRES_MUSEUM", -3132,Adventurer's Guild,Monster Eradication: Armored Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3133,Adventurer's Guild,Monster Eradication: Dangerous Armored Bug,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3134,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3135,Adventurer's Guild,Monster Eradication: Dangerous Duggy,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3136,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3137,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3138,Adventurer's Guild,Monster Eradication: Dangerous Dust Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3139,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3140,Adventurer's Guild,Monster Eradication: Dangerous Rock Crab,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3141,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3142,Adventurer's Guild,Monster Eradication: Dangerous Lava Crab,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3143,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3144,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3145,Adventurer's Guild,Monster Eradication: Dangerous Mummy,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3146,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3147,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3148,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3149,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill From 6a4ec64ed017c113cd506a007d2a7bc4eeb79181 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Sep 2023 12:03:27 -0400 Subject: [PATCH 063/482] - Update options to have better flags # Conflicts: # worlds/stardew_valley/options.py --- worlds/stardew_valley/options.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index f3be783b531a..d4f2cb498013 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -193,17 +193,17 @@ class ToolProgression(Choice): """Shuffle the tool upgrades? Vanilla: Clint will upgrade your tools with metal bars. Progressive: You will randomly find Progressive Tool upgrades. - Cheap: Tool Upgrades will cost half as much + Cheap: Tool Upgrades will cost 2/5th as much Very Cheap: Tool Upgrades will cost 1/5th as much""" internal_name = "tool_progression" display_name = "Tool Progression" - default = 2 - option_vanilla = 0b0001 # 1 - option_progressive = 0b0010 # 2 - option_vanilla_cheap = 0b0101 # 5 - option_vanilla_very_cheap = 0b1001 # 9 - option_progressive_cheap = 0b0110 # 6 - option_progressive_very_cheap = 0b1010 # 10 + default = 1 + option_vanilla = 0b000 # 0 + option_progressive = 0b001 # 1 + option_vanilla_cheap = 0b010 # 2 + option_vanilla_very_cheap = 0b100 # 4 + option_progressive_cheap = 0b011 # 3 + option_progressive_very_cheap = 0b101 # 5 class ElevatorProgression(Choice): @@ -237,7 +237,7 @@ class BuildingProgression(Choice): Progressive: You will receive the buildings and will be able to build the first one of each type for free, once it is received. If you want more of the same building, it will cost the vanilla price. Progressive early shipping bin: Same as Progressive, but the shipping bin will be placed early in the multiworld. - Cheap: Buildings will cost as much + Cheap: Buildings will cost half as much Very Cheap: Buildings will cost 1/5th as much """ internal_name = "building_progression" From e628fc614cb5c555a5e33cf1ed63c57beebf9fd0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Sep 2023 12:25:16 -0400 Subject: [PATCH 064/482] - Fixed Building Progression flags --- worlds/stardew_valley/options.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index d4f2cb498013..49e5d8670e3e 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -243,15 +243,15 @@ class BuildingProgression(Choice): internal_name = "building_progression" display_name = "Building Progression" default = 2 - option_vanilla = 0b00001 # 1 - option_progressive = 0b00010 # 2 - option_progressive_early_shipping_bin = 0b00110 # 6 - option_vanilla_cheap = 0b01001 # 9 - option_vanilla_very_cheap = 0b10001 # 17 - option_progressive_cheap = 0b01010 # 10 - option_progressive_very_cheap = 0b10010 # 18 - option_progressive_early_shipping_bin_cheap = 0b01110 # 14 - option_progressive_early_shipping_bin_very_cheap = 0b10110 # 22 + option_vanilla = 0b0000 # 0 + option_vanilla_cheap = 0b0100 # 4 + option_vanilla_very_cheap = 0b1000 # 8 + option_progressive = 0b0001 # 1 + option_progressive_cheap = 0b0101 # 5 + option_progressive_very_cheap = 0b1001 # 9 + option_progressive_early_shipping_bin = 0b0011 # 3 + option_progressive_early_shipping_bin_cheap = 0b0111 # 7 + option_progressive_early_shipping_bin_very_cheap = 0b1011 # 11 class FestivalLocations(Choice): From 02172aed46ed6c3504dd88b628397509262097cb Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Sep 2023 21:59:21 -0400 Subject: [PATCH 065/482] - Improved the flags a little bit --- worlds/stardew_valley/items.py | 2 +- worlds/stardew_valley/locations.py | 4 +- worlds/stardew_valley/logic/building_logic.py | 4 +- worlds/stardew_valley/options.py | 2 +- worlds/stardew_valley/rules.py | 4 +- worlds/stardew_valley/test/TestOptionFlags.py | 42 ------------------- 6 files changed, 8 insertions(+), 50 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 42790c5486ff..ae433d46e055 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -286,7 +286,7 @@ def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewVa def create_carpenter_buildings(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): building_option = world_options[options.BuildingProgression] - if building_option & options.BuildingProgression.option_vanilla: + if not building_option & options.BuildingProgression.option_progressive: return items.append(item_factory("Progressive Coop")) items.append(item_factory("Progressive Coop")) diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 1a590071384f..c23ac91f17cd 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -353,7 +353,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_mandatory_locations(randomized_locations, options) extend_backpack_locations(randomized_locations, options) - if not world_options[options.ToolProgression] & options.ToolProgression.option_vanilla: + if world_options[options.ToolProgression] & options.ToolProgression.option_progressive: randomized_locations.extend(locations_by_tag[LocationTags.TOOL_UPGRADE]) extend_elevator_locations(randomized_locations, options) @@ -363,7 +363,7 @@ def create_locations(location_collector: StardewLocationCollector, if location.mod_name is None or location.mod_name in options.mods: randomized_locations.append(location_table[location.name]) - if not world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla: + if world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive: for location in locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: if location.mod_name is None or location.mod_name in options.mods: randomized_locations.append(location_table[location.name]) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 2dbe3d094270..83fab0f89266 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -62,7 +62,7 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): def has_building(self, building: str) -> StardewRule: carpenter_rule = self.received(Event.can_construct_buildings) - if self.building_option & options.BuildingProgression.option_vanilla: + if not self.building_option & options.BuildingProgression.option_progressive: return Has(building, self.building_rules) & carpenter_rule count = 1 @@ -83,7 +83,7 @@ def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level > 3: return False_() - if not self.building_option & options.BuildingProgression.option_vanilla: + if self.building_option & options.BuildingProgression.option_progressive: return self.received(f"Progressive House", upgrade_level) & self.region.can_reach(Region.carpenter) if upgrade_level == 1: diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 49e5d8670e3e..9b2bece9bb29 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -242,7 +242,7 @@ class BuildingProgression(Choice): """ internal_name = "building_progression" display_name = "Building Progression" - default = 2 + default = 3 option_vanilla = 0b0000 # 0 option_vanilla_cheap = 0b0100 # 4 option_vanilla_very_cheap = 0b1000 # 8 diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index f1af49b2975e..938bb433ba03 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -88,7 +88,7 @@ def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): def set_tool_rules(logic: StardewLogic, multi_world, player, world_options): - if world_options[options.ToolProgression] & options.ToolProgression.option_vanilla: + if not world_options[options.ToolProgression] & options.ToolProgression.option_progressive: return MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), @@ -106,7 +106,7 @@ def set_tool_rules(logic: StardewLogic, multi_world, player, world_options): def set_building_rules(logic: StardewLogic, multi_world, player, world_options): - if world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla: + if not world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive: return for building in locations.locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: diff --git a/worlds/stardew_valley/test/TestOptionFlags.py b/worlds/stardew_valley/test/TestOptionFlags.py index bb29fe24fccb..f311156fe17e 100644 --- a/worlds/stardew_valley/test/TestOptionFlags.py +++ b/worlds/stardew_valley/test/TestOptionFlags.py @@ -13,13 +13,6 @@ def test_options_are_not_detected_as_progressive(self): self.assertFalse(tool_progressive) self.assertFalse(building_progressive) - def test_options_are_detected_as_vanilla(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla - self.assertTrue(tool_progressive) - self.assertTrue(building_progressive) - def test_tools_and_buildings_not_in_pool(self): item_names = [item.name for item in self.multiworld.itempool] self.assertNotIn("Progressive Coop", item_names) @@ -37,13 +30,6 @@ def test_options_are_not_detected_as_progressive(self): self.assertFalse(tool_progressive) self.assertFalse(building_progressive) - def test_options_are_detected_as_vanilla(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla - self.assertTrue(tool_progressive) - self.assertTrue(building_progressive) - def test_tools_and_buildings_not_in_pool(self): item_names = [item.name for item in self.multiworld.itempool] self.assertNotIn("Progressive Coop", item_names) @@ -61,13 +47,6 @@ def test_options_are_not_detected_as_progressive(self): self.assertFalse(tool_progressive) self.assertFalse(building_progressive) - def test_options_are_detected_as_vanilla(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla - self.assertTrue(tool_progressive) - self.assertTrue(building_progressive) - def test_tools_and_buildings_not_in_pool(self): item_names = [item.name for item in self.multiworld.itempool] self.assertNotIn("Progressive Coop", item_names) @@ -85,13 +64,6 @@ def test_options_are_detected_as_progressive(self): self.assertTrue(tool_progressive) self.assertTrue(building_progressive) - def test_options_are_not_detected_as_vanilla(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla - self.assertFalse(tool_progressive) - self.assertFalse(building_progressive) - def test_tools_and_buildings_in_pool(self): item_names = [item.name for item in self.multiworld.itempool] self.assertIn("Progressive Coop", item_names) @@ -109,13 +81,6 @@ def test_options_are_detected_as_progressive(self): self.assertTrue(tool_progressive) self.assertTrue(building_progressive) - def test_options_are_not_detected_as_vanilla(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla - self.assertFalse(tool_progressive) - self.assertFalse(building_progressive) - def test_tools_and_buildings_in_pool(self): item_names = [item.name for item in self.multiworld.itempool] self.assertIn("Progressive Coop", item_names) @@ -133,13 +98,6 @@ def test_options_are_detected_as_progressive(self): self.assertTrue(tool_progressive) self.assertTrue(building_progressive) - def test_options_are_not_detected_as_vanilla(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_vanilla - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_vanilla - self.assertFalse(tool_progressive) - self.assertFalse(building_progressive) - def test_tools_and_buildings_in_pool(self): item_names = [item.name for item in self.multiworld.itempool] self.assertIn("Progressive Coop", item_names) From b00bd51ced65b217e8a883e306d5f04aa7890fd0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 9 Sep 2023 01:10:26 -0400 Subject: [PATCH 066/482] - Added shipping region - added kitchen region - Addec cooksanity rules # Conflicts: # worlds/stardew_valley/options.py --- worlds/stardew_valley/__init__.py | 6 +- worlds/stardew_valley/data/locations.csv | 79 +++++++++++++++++++ worlds/stardew_valley/data/recipe_data.py | 2 + worlds/stardew_valley/locations.py | 21 ++++- worlds/stardew_valley/logic/cooking_logic.py | 24 +++++- worlds/stardew_valley/logic/logic.py | 5 +- worlds/stardew_valley/logic/shipping_logic.py | 15 +++- worlds/stardew_valley/options.py | 17 ++++ worlds/stardew_valley/regions.py | 13 ++- worlds/stardew_valley/rules.py | 63 +++++++-------- .../stardew_valley/strings/entrance_names.py | 3 + worlds/stardew_valley/strings/goal_names.py | 1 + worlds/stardew_valley/strings/region_names.py | 2 + 13 files changed, 199 insertions(+), 52 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index e1443cf9fd5d..d38a98d73855 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -224,6 +224,10 @@ def setup_victory(self): self.create_event_location(location_table[Goal.full_shipment], self.logic.shipping.can_ship_everything().simplify(), Event.victory) + elif self.options[options.Goal] == options.Goal.option_gourmet_chef: + self.create_event_location(location_table[Goal.gourmet_chef], + self.logic.cooking.can_cook_everything().simplify(), + Event.victory) elif self.options[options.Goal] == options.Goal.option_perfection: self.create_event_location(location_table[Goal.perfection], self.logic.has_everything(self.all_progression_items).simplify(), @@ -339,7 +343,7 @@ def fill_slot_data(self) -> Dict[str, Any]: "seed": self.multiworld.per_slot_randoms[self.player].randrange(1000000000), # Seed should be max 9 digits "randomized_entrances": self.randomized_entrances, "modified_bundles": modified_bundles, - "client_version": "4.0.0", + "client_version": "5.0.0", }) return slot_data diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c9df23743050..4ad814fc165f 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1702,6 +1702,85 @@ id,region,name,tags,mod_name 3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", 3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", 3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3201,Kitchen,Cook Algae Soup,"COOKSANITY" +3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS" +3203,Kitchen,Cook Autumn's Bounty,"COOKSANITY" +3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS" +3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND" +3206,Kitchen,Cook Bean Hotpot,"COOKSANITY" +3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS" +3208,Kitchen,Cook Blueberry Tart,"COOKSANITY" +3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS" +3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS" +3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS" +3212,Kitchen,Cook Cheese Cauliflower,"COOKSANITY" +3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS" +3214,Kitchen,Cook Chowder,"COOKSANITY" +3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS" +3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS" +3217,Kitchen,Cook Cookie,"COOKSANITY" +3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS" +3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS" +3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY" +3221,Kitchen,Cook Crispy Bass,"COOKSANITY" +3222,Kitchen,Cook Dish O' The Sea,"COOKSANITY" +3223,Kitchen,Cook Eggplant Parmesan,"COOKSANITY" +3224,Kitchen,Cook Escargot,"COOKSANITY" +3225,Kitchen,Cook Farmer's Lunch,"COOKSANITY" +3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS" +3227,Kitchen,Cook Fish Stew,"COOKSANITY" +3228,Kitchen,Cook Fish Taco,"COOKSANITY" +3229,Kitchen,Cook Fried Calamari,"COOKSANITY" +3230,Kitchen,Cook Fried Eel,"COOKSANITY" +3231,Kitchen,Cook Fried Egg,"COOKSANITY" +3232,Kitchen,Cook Fried Mushroom,"COOKSANITY" +3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS" +3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND" +3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS" +3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS" +3237,Kitchen,Cook Ice Cream,"COOKSANITY" +3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS" +3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS" +3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS" +3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND" +3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS" +3243,Kitchen,Cook Miner's Treat,"COOKSANITY" +3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS" +3245,Kitchen,Cook Pale Broth,"COOKSANITY" +3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS" +3247,Kitchen,Cook Parsnip Soup,"COOKSANITY" +3248,Kitchen,Cook Pepper Poppers,"COOKSANITY" +3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS" +3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS" +3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS" +3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND" +3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS" +3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS" +3255,Kitchen,Cook Pumpkin Soup,"COOKSANITY" +3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS" +3257,Kitchen,Cook Red Plate,"COOKSANITY" +3258,Kitchen,Cook Rhubarb Pie,"COOKSANITY" +3259,Kitchen,Cook Rice Pudding,"COOKSANITY" +3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS" +3261,Kitchen,Cook Roots Platter,"COOKSANITY" +3262,Kitchen,Cook Salad,"COOKSANITY" +3263,Kitchen,Cook Salmon Dinner,"COOKSANITY" +3264,Kitchen,Cook Sashimi,"COOKSANITY" +3265,Kitchen,Cook Seafoam Pudding,"COOKSANITY" +3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS" +3267,Kitchen,Cook Spaghetti,"COOKSANITY" +3268,Kitchen,Cook Spicy Eel,"COOKSANITY" +3269,Kitchen,Cook Squid Ink Ravioli,"COOKSANITY" +3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS" +3271,Kitchen,Cook Stuffing,"COOKSANITY" +3272,Kitchen,Cook Super Meal,"COOKSANITY" +3273,Kitchen,Cook Survival Burger,"COOKSANITY" +3274,Kitchen,Cook Tom Kha Soup,"COOKSANITY" +3275,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS" +3276,Kitchen,Cook Triple Shot Espresso,"COOKSANITY" +3277,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND" +3278,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS" +3279,Kitchen,Cook Vegetable Medley,"COOKSANITY" 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 9c9ddf135e93..6330fd511de5 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -164,3 +164,5 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) tropical_curry = shop_recipe(Meal.tropical_curry, Region.island_resort, 2000, {Forageable.coconut: 1, Fruit.pineapple: 1, Fruit.hot_pepper: 1}) trout_soup = queen_of_sauce_recipe(Meal.trout_soup, 1, Season.fall, 14, {Fish.rainbow_trout: 1, WaterItem.green_algae: 1}) vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Vegetable.tomato: 1, Vegetable.beet: 1}) + +all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} \ No newline at end of file diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index c23ac91f17cd..5ead40555d7c 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -72,6 +72,8 @@ class LocationTags(enum.Enum): SHIPSANITY_CROP = enum.auto() SHIPSANITY_FISH = enum.auto() SHIPSANITY_FULL_SHIPMENT = enum.auto() + COOKSANITY = enum.auto() + COOKSANITY_QOS = enum.auto() # Skill Mods LUCK_LEVEL = enum.auto() BINNING_LEVEL = enum.auto() @@ -122,12 +124,13 @@ def load_location_csv() -> List[LocationData]: LocationData(None, Region.community_center, Goal.community_center), LocationData(None, Region.mines_floor_120, Goal.bottom_of_the_mines), LocationData(None, Region.skull_cavern_100, Goal.cryptic_note), - LocationData(None, Region.farm, Goal.master_angler), + LocationData(None, Region.beach, Goal.master_angler), LocationData(None, Region.museum, Goal.complete_museum), LocationData(None, Region.farm_house, Goal.full_house), LocationData(None, Region.island_west, Goal.greatest_walnut_hunter), LocationData(None, Region.adventurer_guild, Goal.protector_of_the_valley), - LocationData(None, Region.farm, Goal.full_shipment), + LocationData(None, Region.shipping, Goal.full_shipment), + LocationData(None, Region.kitchen, Goal.gourmet_chef), LocationData(None, Region.qi_walnut_room, Goal.perfection), ] @@ -345,6 +348,19 @@ def extend_shipsanity_locations(randomized_locations: List[LocationData], world_ randomized_locations.extend(filtered_shipsanity_locations) +def extend_cooksanity_locations(randomized_locations: List[LocationData], world_options): + cooksanity = world_options[options.Cooksanity] + if cooksanity == options.Cooksanity.option_none: + return + if cooksanity == options.Cooksanity.option_queen_of_sauce: + cooksanity_locations = {location for location in locations_by_tag[LocationTags.COOKSANITY_QOS]} + else: + cooksanity_locations = {location for location in locations_by_tag[LocationTags.COOKSANITY]} + + filtered_cooksanity_locations = filter_disabled_locations(world_options, list(cooksanity_locations)) + randomized_locations.extend(filtered_cooksanity_locations) + + def create_locations(location_collector: StardewLocationCollector, options: StardewValleyOptions, random: Random): @@ -386,6 +402,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_monstersanity_locations(randomized_locations, world_options) extend_shipsanity_locations(randomized_locations, world_options) + extend_cooksanity_locations(randomized_locations, world_options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 34ef899eccd0..32d3edc60f07 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -8,15 +8,20 @@ from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic -from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe +from .. import options +from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe, \ + all_cooking_recipes_by_name from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource +from ..locations import locations_by_tag, LocationTags from ..stardew_rule import StardewRule, True_, False_, And +from ..strings.region_names import Region from ..strings.skill_names import Skill from ..strings.tv_channel_names import Channel class CookingLogic: player: int + exclude_ginger_island: int received: ReceivedLogic has: HasLogic region: RegionLogic @@ -28,9 +33,10 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + def __init__(self, player: int, exclude_ginger_island: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player + self.exclude_ginger_island = exclude_ginger_island self.received = received self.has = has self.region = region @@ -42,8 +48,11 @@ def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: self.relationship = relationship self.skill = skill + def can_cook_in_kitchen(self) -> StardewRule: + return self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) + def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: - cook_rule = self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) + cook_rule = self.region.can_reach(Region.kitchen) if recipe is None: return cook_rule @@ -73,3 +82,12 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule return False_() + + def can_cook_everything(self) -> StardewRule: + cooksanity_prefix = "Cook " + all_recipes_to_cook = [] + include_island = self.exclude_ginger_island == options.ExcludeGingerIsland.option_false + for location in locations_by_tag[LocationTags.COOKSANITY]: + if include_island or LocationTags.GINGER_ISLAND not in location.tags: + all_recipes_to_cook.append(location.name[len(cooksanity_prefix):]) + return And([self.can_cook(all_cooking_recipes_by_name[recipe_name]) for recipe_name in all_recipes_to_cook]) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 71ef79576c4d..cedc876ea925 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -119,7 +119,8 @@ def __post_init__(self): heart_size_option = self.options[options.FriendsanityHeartSize] mods_option = self.options[options.Mods] self.buildings = BuildingLogic(self.player, self.options[options.BuildingProgression], self.received, self.has, self.region, self.money, mods_option) - self.shipping = ShippingLogic(self.player, self.options[options.ExcludeGingerIsland], self.options[options.SpecialOrderLocations], self.has, self.buildings) + self.shipping = ShippingLogic(self.player, self.options[options.ExcludeGingerIsland], self.options[options.SpecialOrderLocations], self.has, + self.region, self.buildings) self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.options[options.Museumsanity], self.received, self.has, self.region, self.action) @@ -132,7 +133,7 @@ def __post_init__(self): self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.cooking = CookingLogic(self.player, self.options[options.ExcludeGingerIsland], self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.crafting = CraftingLogic(self.player, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, self.region, self.tool, self.skill, self.mine) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index f7ae8c4d2aee..0efc6283f93d 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,10 +1,12 @@ from .building_logic import BuildingLogic from .has_logic import HasLogic +from .region_logic import RegionLogic from .. import options from ..locations import LocationTags, locations_by_tag from ..stardew_rule import StardewRule, And from ..strings.building_names import Building +from ..strings.region_names import Region class ShippingLogic: @@ -12,20 +14,25 @@ class ShippingLogic: exclude_ginger_island: int special_orders_option: int has: HasLogic + region: RegionLogic buildings: BuildingLogic - def __init__(self, player: int, exclude_ginger_island: int, special_orders_option: int, has: HasLogic, buildings: BuildingLogic): + def __init__(self, player: int, exclude_ginger_island: int, special_orders_option: int, has: HasLogic, region: RegionLogic, buildings: BuildingLogic): self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_orders_option = special_orders_option self.has = has + self.region = region self.buildings = buildings + def can_use_shipping_bin(self, item: str = "") -> StardewRule: + return self.buildings.has_building(Building.shipping_bin) + def can_ship(self, item: str = "") -> StardewRule: - shipping_bin_rule = self.buildings.has_building(Building.shipping_bin) + shipping_rule = self.region.can_reach(Region.shipping) if item == "": - return shipping_bin_rule - return shipping_bin_rule & self.has(item) + return shipping_rule + return shipping_rule & self.has(item) def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 9b2bece9bb29..5e5ba1a8cc0c 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -17,6 +17,7 @@ class Goal(Choice): Greatest Walnut Hunter: Find all 130 Golden Walnuts Protector of the Valley: Complete all the monster slayer goals. Pairs well with Monstersanity Full Shipment: Ship every item in the collection tab. Pairs well with Shipsanity + Gourmet Chef: Cook every recipe. Pairs well with Chefsanity and Cooksanity Perfection: Attain Perfection, based on the vanilla definition. """ internal_name = "goal" @@ -32,6 +33,7 @@ class Goal(Choice): option_greatest_walnut_hunter = 7 option_protector_of_the_valley = 8 option_full_shipment = 9 + option_gourmet_chef = 10 # option_junimo_kart = # option_prairie_king = # option_fector_challenge = @@ -410,6 +412,20 @@ class Shipsanity(Choice): # option_quality_everything = 10 +class Cooksanity(Choice): + """Locations for cooking food? + None: There are no checks for cooking + Queen of Sauce: Every Queen of Sauce Recipe can be cooked for a check + All: Every cooking recipe can be cooked for a check + """ + internal_name = "cooksanity" + display_name = "Cooksanity" + default = 0 + option_none = 0 + option_queen_of_sauce = 1 + option_all = 2 + + class Friendsanity(Choice): """Shuffle Friendships? None: Friendship hearts are earned normally @@ -623,6 +639,7 @@ class StardewValleyOptions(PerGameCommonOptions): museumsanity: Museumsanity Monstersanity, Shipsanity, + Cooksanity, friendsanity: Friendsanity friendsanity_heart_size: FriendsanityHeartSize movement_buff_number: NumberOfMovementBuffs diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 691dca14c862..efcd2c641659 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -17,15 +17,17 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: vanilla_regions = [ RegionData(Region.menu, [Entrance.to_stardew_valley]), RegionData(Region.stardew_valley, [Entrance.to_farmhouse]), - RegionData(Region.farm_house, [Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar]), + RegionData(Region.farm_house, [Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar, Entrance.farmhouse_cooking]), RegionData(Region.cellar), + RegionData(Region.kitchen), RegionData(Region.farm, [Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse, Entrance.use_desert_obelisk, Entrance.use_island_obelisk, Entrance.enter_coop, Entrance.enter_barn, - Entrance.enter_shed, Entrance.enter_slime_hutch, Entrance.farming]), - RegionData(Region.farming), + Entrance.enter_shed, Entrance.enter_slime_hutch, + Entrance.farming, Entrance.shipping]), + RegionData(Region.shipping), RegionData(Region.backwoods, [Entrance.backwoods_to_mountain]), RegionData(Region.bus_stop, [Entrance.bus_stop_to_town, Entrance.take_bus_to_desert, Entrance.bus_stop_to_tunnel_entrance]), @@ -177,7 +179,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.volcano_dwarf_shop), RegionData(Region.volcano_floor_10), RegionData(Region.island_trader), - RegionData(Region.island_farmhouse), + RegionData(Region.island_farmhouse, [Entrance.island_cooking]), RegionData(Region.gourmand_frog_cave), RegionData(Region.colored_crystals_cave), RegionData(Region.shipwreck), @@ -240,6 +242,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.to_farmhouse, Region.farm_house), ConnectionData(Entrance.farmhouse_to_farm, Region.farm), ConnectionData(Entrance.downstairs_to_cellar, Region.cellar), + ConnectionData(Entrance.farmhouse_cooking, Region.kitchen), ConnectionData(Entrance.farm_to_backwoods, Region.backwoods), ConnectionData(Entrance.farm_to_bus_stop, Region.bus_stop), ConnectionData(Entrance.farm_to_forest, Region.forest), @@ -250,6 +253,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.enter_barn, Region.barn), ConnectionData(Entrance.enter_shed, Region.shed), ConnectionData(Entrance.enter_slime_hutch, Region.slime_hutch), + ConnectionData(Entrance.shipping, Region.shipping), ConnectionData(Entrance.use_desert_obelisk, Region.desert), ConnectionData(Entrance.use_island_obelisk, Region.island_south), ConnectionData(Entrance.use_farm_obelisk, Region.farm), @@ -411,6 +415,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.use_island_resort, Region.island_resort), ConnectionData(Entrance.island_west_to_islandfarmhouse, Region.island_farmhouse, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_cooking, Region.kitchen), ConnectionData(Entrance.island_west_to_gourmand_cave, Region.gourmand_frog_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_west_to_crystals_cave, Region.colored_crystals_cave, diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 938bb433ba03..da17200e69ee 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -230,26 +230,10 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room)).simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_mines_dwarf, player), logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_desert_obelisk, player), - logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_obelisk, player), - logic.can_use_obelisk(Transportation.island_obelisk).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_farm_obelisk, player), - logic.can_use_obelisk(Transportation.farm_obelisk).simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.buy_from_traveling_merchant, player), logic.has_traveling_merchant()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_greenhouse, player), - logic.received("Greenhouse")) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_coop, player), - logic.buildings.has_building(Building.coop)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_barn, player), - logic.buildings.has_building(Building.barn)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_shed, player), - logic.buildings.has_building(Building.shed)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_slime_hutch, player), - logic.buildings.has_building(Building.slime_hutch)) + set_farm_buildings_entrance_rules(logic, multi_world, player) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_adventurer_guild, player), logic.received("Adventurer's Guild")) @@ -265,27 +249,34 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), logic.received("Club Card")) + set_bedroom_entrance_rules(logic, multi_world, player, world_options) set_festival_entrance_rules(logic, multiworld, player) - - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), - logic.relationship.has_hearts(NPC.harvey, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_maru_room, player), - logic.relationship.has_hearts(NPC.maru, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sebastian_room, player), - (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.forest_to_leah_cottage, player), - logic.relationship.has_hearts(NPC.leah, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_elliott_house, player), - logic.relationship.has_hearts(NPC.elliott, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sunroom, player), - logic.relationship.has_hearts(NPC.caroline, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_wizard_basement, player), - logic.relationship.has_hearts(NPC.wizard, 4)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_leo_treehouse, player), - logic.received("Treehouse")) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin().simplify()) + + +def set_farm_buildings_entrance_rules(logic, multi_world, player): + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk).simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk).simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_coop, player), logic.buildings.has_building(Building.coop)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_barn, player), logic.buildings.has_building(Building.barn)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_shed, player), logic.buildings.has_building(Building.shed)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_slime_hutch, player), logic.buildings.has_building(Building.slime_hutch)) + + +def set_bedroom_entrance_rules(logic, multi_world, player, world_options): + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) if ModNames.alec in world_options[options.Mods]: - MultiWorldRules.set_rule(multi_world.get_entrance(AlecEntrance.petshop_to_bedroom, player), - (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) def set_mines_floor_entrance_rules(logic, multiworld, player): diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 5b47d369e489..2901bb41d15b 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -183,6 +183,9 @@ class Entrance: parrot_express_jungle_to_docks = "Parrot Express Jungle to Docks" parrot_express_dig_site_to_docks = "Parrot Express Dig Site to Docks" parrot_express_volcano_to_docks = "Parrot Express Volcano to Docks" + farmhouse_cooking = "Farmhouse Cooking" + island_cooking = "Island Cooking" + shipping = "Use Shipping Bin" blacksmith_copper = "Upgrade Copper Tools" blacksmith_iron = "Upgrade Iron Tools" blacksmith_gold = "Upgrade Gold Tools" diff --git a/worlds/stardew_valley/strings/goal_names.py b/worlds/stardew_valley/strings/goal_names.py index f2de1b82700b..6df0fd208168 100644 --- a/worlds/stardew_valley/strings/goal_names.py +++ b/worlds/stardew_valley/strings/goal_names.py @@ -9,4 +9,5 @@ class Goal: greatest_walnut_hunter = "Greatest Walnut Hunter" protector_of_the_valley = "Protector of the Valley" full_shipment = "Full Shipment" + gourmet_chef = "Gourmet Chef" perfection = "Perfection" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index ef9ae9b4c2ce..6d94bd35748e 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -148,6 +148,8 @@ class Region: dangerous_mines_20 = "Dangerous Mines - Floor 20" dangerous_mines_60 = "Dangerous Mines - Floor 60" dangerous_mines_100 = "Dangerous Mines - Floor 100" + kitchen = "Kitchen" + shipping = "Shipping" blacksmith_copper = "Blacksmith Copper Upgrades" blacksmith_iron = "Blacksmith Iron Upgrades" blacksmith_gold = "Blacksmith Gold Upgrades" From 0f9d18737a840e9610fda5ffd7c85a6d26d8d9ae Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 9 Sep 2023 13:52:17 -0400 Subject: [PATCH 067/482] - Added a test for the new dating rule - Added new dating rule - Improve mines logic --- worlds/stardew_valley/logic/logic.py | 1 - worlds/stardew_valley/logic/mine_logic.py | 1 + .../logic/relationship_logic.py | 11 ++++ worlds/stardew_valley/test/TestRules.py | 59 +++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index cedc876ea925..7f23a910e105 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -370,7 +370,6 @@ def __post_init__(self): Machine.lightning_rod: self.skill.has_level(Skill.foraging, 6) & self.has(MetalBar.iron) & self.has(MetalBar.quartz) & self.has(Loot.bat_wing), Machine.loom: self.skill.has_farming_level(7) & self.has(Material.wood) & self.has(Material.fiber) & self.has(ArtisanGood.pine_tar), Machine.mayonnaise_machine: self.skill.has_farming_level(2) & self.has(Material.wood) & self.has(Material.stone) & self.has("Earth Crystal") & self.has(MetalBar.copper), - Machine.oil_maker: self.skill.has_farming_level(8) & self.has(Loot.slime) & self.has(Material.hardwood) & self.has(MetalBar.gold), Machine.ostrich_incubator: self.received("Ostrich Incubator Recipe") & self.has(Fossil.bone_fragment) & self.has(Material.hardwood) & self.has(Material.cinder_shard), Machine.preserves_jar: self.skill.has_farming_level(4) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.coal), Machine.recycling_machine: self.skill.has_level(Skill.fishing, 4) & self.has(Material.wood) & self.has(Material.stone) & self.has(MetalBar.iron), diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 90589b051e7a..d53a33b6a514 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -74,6 +74,7 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: if self.skill_option == options.SkillProgression.option_progressive: combat_tier = min(10, max(0, tier * 2)) rules.append(self.skill.has_level(Skill.combat, combat_tier)) + rules.append(self.skill.has_level(Skill.mining, combat_tier)) return And(rules) def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index ea8cbc8ca03f..ea56c8f2ef47 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -44,6 +44,12 @@ def __init__(self, player: int, friendsanity_option: int, heart_size_option: int self.buildings = buildings self.mods_option = mods_option + def can_date(self, npc: str) -> StardewRule: + return self.has_hearts(npc, 8) & self.has(Gift.bouquet) + + def can_marry(self, npc: str) -> StardewRule: + return self.has_hearts(npc, 10) & self.has(Gift.mermaid_pendant) + def can_get_married(self) -> StardewRule: return self.has_hearts(Generic.bachelor, 10) & self.has(Gift.mermaid_pendant) @@ -145,6 +151,11 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: rule_if_birthday = self.season.has(villager.birthday) & self.time.has_lived_months(hearts // 2) rule_if_not_birthday = self.time.has_lived_months(hearts) earn_rule = self.can_meet(npc) & (rule_if_birthday | rule_if_not_birthday) + if villager.bachelor: + if hearts >= 8: + earn_rule = earn_rule & self.can_date(npc) + if hearts >= 10: + earn_rule = earn_rule & self.can_marry(npc) else: earn_rule = self.time.has_lived_months(min(hearts // 2, 8)) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index d60a6bda73be..105f2c4003b8 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -612,3 +612,62 @@ def test_all_shipsanity_locations_require_shipping_bin(self): self.assertTrue(can_reach_shipsanity_location) self.remove(bin_item) + +class TestFriendsanityDatingRules(SVTestBase): + options = { + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized_not_winter, + options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, + options.FriendsanityHeartSize.internal_name: 3 + } + + def test_earning_dating_heart_requires_dating(self): + month_name = "Month End" + for i in range(12): + month_item = self.world.create_item(month_name) + self.multiworld.state.collect(month_item, event=True) + self.multiworld.state.collect(self.world.create_item("Beach Bridge"), event=False) + self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False) + self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), 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") + From 059448afb7644896ce08c6b0d0aa1daa07681855 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 9 Sep 2023 14:53:33 -0400 Subject: [PATCH 068/482] - Fix hearts >= into > - Fixed mines tests to take into account the mining levels - Made all tests default to minsanity settings for performance --- .../logic/relationship_logic.py | 4 +-- worlds/stardew_valley/test/TestGeneration.py | 12 ++++--- worlds/stardew_valley/test/TestRules.py | 1 + worlds/stardew_valley/test/__init__.py | 36 ++++++++++++++++++- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index ea56c8f2ef47..f8a2b78a1811 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -152,9 +152,9 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: rule_if_not_birthday = self.time.has_lived_months(hearts) earn_rule = self.can_meet(npc) & (rule_if_birthday | rule_if_not_birthday) if villager.bachelor: - if hearts >= 8: + if hearts > 8: earn_rule = earn_rule & self.can_date(npc) - if hearts >= 10: + if hearts > 10: earn_rule = earn_rule & self.can_marry(npc) else: earn_rule = self.time.has_lived_months(min(hearts // 2, 8)) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index bffef684a71e..b7a30dbedb1b 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -1,8 +1,7 @@ from typing import List from BaseClasses import ItemClassification, MultiWorld, Item -from . import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_with_mods, \ - allsanity_options_without_mods, minimal_locations_maximal_items +from . import setup_solo_multiworld, SVTestBase, get_minsanity_options from .. import locations, items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name from ..items import items_by_group, Group, item_table @@ -254,15 +253,18 @@ def generate_items_for_mine_115(self) -> List[Item]: elevators = [self.get_item_by_name("Progressive Mine Elevator")] * 21 swords = [self.get_item_by_name("Progressive Sword")] * 3 combat_levels = [self.get_item_by_name("Combat Level")] * 4 + mining_levels = [self.get_item_by_name("Mining Level")] * 4 guild = self.get_item_by_name("Adventurer's Guild") - return [*combat_levels, *elevators, guild, *pickaxes, *swords] + return [*combat_levels, *mining_levels, *elevators, guild, *pickaxes, *swords] def generate_items_for_extra_mine_levels(self, weapon_name: str) -> List[Item]: last_pickaxe = self.get_item_by_name("Progressive Pickaxe") last_weapon = self.multiworld.create_item(weapon_name, self.player) second_last_combat_level = self.get_item_by_name("Combat Level") last_combat_level = self.get_item_by_name("Combat Level") - return [last_pickaxe, last_weapon, second_last_combat_level, last_combat_level] + second_last_mining_level = self.get_item_by_name("Mining Level") + last_mining_level = self.get_item_by_name("Mining Level") + return [last_pickaxe, last_weapon, second_last_combat_level, last_combat_level, second_last_mining_level, last_mining_level] class TestLocationGeneration(SVTestBase): @@ -287,7 +289,7 @@ def test_minimal_location_maximal_items_still_valid(self): def test_minsanity_has_fewer_than_locations(self): expected_locations = 122 - minsanity_options = self.minsanity_options() + minsanity_options = get_minsanity_options() multiworld = setup_solo_multiworld(minsanity_options) real_locations = get_real_locations(self, multiworld) number_locations = len(real_locations) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 105f2c4003b8..eecb53ddd5ce 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -275,6 +275,7 @@ 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.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) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 9bae6c7d9deb..88cb3434e750 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -15,6 +15,37 @@ BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods +def get_minsanity_options(): + minsanity = { + options.Goal.internal_name: options.Goal.option_bottom_of_the_mines, + options.BundleRandomization.internal_name: options.BundleRandomization.option_vanilla, + options.BundlePrice.internal_name: options.BundlePrice.option_very_cheap, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_disabled, + options.Cropsanity.internal_name: options.Cropsanity.option_disabled, + options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla, + options.ToolProgression.internal_name: options.ToolProgression.option_vanilla, + options.SkillProgression.internal_name: options.SkillProgression.option_vanilla, + options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla, + options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_vanilla, + options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled, + options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_disabled, + options.HelpWantedLocations.internal_name: 0, + options.Fishsanity.internal_name: options.Fishsanity.option_none, + options.Museumsanity.internal_name: options.Museumsanity.option_none, + options.Monstersanity.internal_name: options.Monstersanity.option_none, + options.Shipsanity.internal_name: options.Shipsanity.option_none, + options.Friendsanity.internal_name: options.Friendsanity.option_none, + options.FriendsanityHeartSize.internal_name: 8, + options.NumberOfMovementBuffs.internal_name: 0, + options.NumberOfLuckBuffs.internal_name: 0, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + options.TrapItems.internal_name: options.TrapItems.option_no_traps, + options.Mods.internal_name: (), + } + return minsanity + + class SVTestCase(unittest.TestCase): player: ClassVar[int] = 1 """Set to False to not skip some 'extra' tests""" @@ -24,6 +55,8 @@ class SVTestCase(unittest.TestCase): """Set to False to run tests that take long""" skip_performance_tests: bool = True + options = get_minsanity_options() + def setUp(self) -> None: super().setUp() long_tests_key = "long" @@ -54,7 +87,7 @@ def run_default_tests(self) -> bool: @cache_argsless def minimal_locations_maximal_items(): min_max_options = { -Goal.internal_name: Goal.option_bottom_of_the_mines, + Goal.internal_name: Goal.option_bottom_of_the_mines, BundleRandomization.internal_name: BundleRandomization.option_vanilla, BundlePrice.internal_name: BundlePrice.option_very_cheap, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, @@ -141,6 +174,7 @@ def allsanity_options_without_mods(): Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, Monstersanity.internal_name: Monstersanity.option_progressive_goals, + Shipsanity.internal_name: , Friendsanity.internal_name: Friendsanity.option_all_with_marriage, FriendsanityHeartSize.internal_name: 1, NumberOfMovementBuffs.internal_name: 12, From 298bbe975426670f296816297e1010451d5e34e5 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 9 Sep 2023 19:52:55 -0400 Subject: [PATCH 069/482] - Added Chefsanity --- worlds/stardew_valley/data/items.csv | 80 ++++++ worlds/stardew_valley/data/locations.csv | 239 ++++++++++++------ worlds/stardew_valley/data/recipe_data.py | 1 + worlds/stardew_valley/items.py | 33 ++- worlds/stardew_valley/locations.py | 27 ++ worlds/stardew_valley/options.py | 22 ++ worlds/stardew_valley/regions.py | 4 +- worlds/stardew_valley/rules.py | 41 ++- .../stardew_valley/strings/entrance_names.py | 1 + worlds/stardew_valley/strings/region_names.py | 1 + worlds/stardew_valley/test/TestGeneration.py | 2 + worlds/stardew_valley/test/mods/TestMods.py | 2 + 12 files changed, 367 insertions(+), 86 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index e254546bb11e..381abccd7e1f 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -319,6 +319,86 @@ id,name,classification,groups,mod_name 334,Fiber Seeds Recipe,progression,"CRAFTING_RECIPE", 335,Quality Bobber Recipe,progression,"CRAFTING_RECIPE", 337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +356,Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +370,Fried Egg Recipe,progression,"CHEFSANITY_STARTER", +371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", +417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 4ad814fc165f..816deaa741b0 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1702,85 +1702,166 @@ id,region,name,tags,mod_name 3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", 3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", 3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3201,Kitchen,Cook Algae Soup,"COOKSANITY" -3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS" -3203,Kitchen,Cook Autumn's Bounty,"COOKSANITY" -3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS" -3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND" -3206,Kitchen,Cook Bean Hotpot,"COOKSANITY" -3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS" -3208,Kitchen,Cook Blueberry Tart,"COOKSANITY" -3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS" -3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS" -3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS" -3212,Kitchen,Cook Cheese Cauliflower,"COOKSANITY" -3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS" -3214,Kitchen,Cook Chowder,"COOKSANITY" -3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS" -3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS" -3217,Kitchen,Cook Cookie,"COOKSANITY" -3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS" -3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS" -3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY" -3221,Kitchen,Cook Crispy Bass,"COOKSANITY" -3222,Kitchen,Cook Dish O' The Sea,"COOKSANITY" -3223,Kitchen,Cook Eggplant Parmesan,"COOKSANITY" -3224,Kitchen,Cook Escargot,"COOKSANITY" -3225,Kitchen,Cook Farmer's Lunch,"COOKSANITY" -3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS" -3227,Kitchen,Cook Fish Stew,"COOKSANITY" -3228,Kitchen,Cook Fish Taco,"COOKSANITY" -3229,Kitchen,Cook Fried Calamari,"COOKSANITY" -3230,Kitchen,Cook Fried Eel,"COOKSANITY" -3231,Kitchen,Cook Fried Egg,"COOKSANITY" -3232,Kitchen,Cook Fried Mushroom,"COOKSANITY" -3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS" -3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND" -3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS" -3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS" -3237,Kitchen,Cook Ice Cream,"COOKSANITY" -3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS" -3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS" -3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS" -3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND" -3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS" -3243,Kitchen,Cook Miner's Treat,"COOKSANITY" -3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS" -3245,Kitchen,Cook Pale Broth,"COOKSANITY" -3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS" -3247,Kitchen,Cook Parsnip Soup,"COOKSANITY" -3248,Kitchen,Cook Pepper Poppers,"COOKSANITY" -3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS" -3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS" -3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS" -3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND" -3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS" -3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS" -3255,Kitchen,Cook Pumpkin Soup,"COOKSANITY" -3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS" -3257,Kitchen,Cook Red Plate,"COOKSANITY" -3258,Kitchen,Cook Rhubarb Pie,"COOKSANITY" -3259,Kitchen,Cook Rice Pudding,"COOKSANITY" -3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS" -3261,Kitchen,Cook Roots Platter,"COOKSANITY" -3262,Kitchen,Cook Salad,"COOKSANITY" -3263,Kitchen,Cook Salmon Dinner,"COOKSANITY" -3264,Kitchen,Cook Sashimi,"COOKSANITY" -3265,Kitchen,Cook Seafoam Pudding,"COOKSANITY" -3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS" -3267,Kitchen,Cook Spaghetti,"COOKSANITY" -3268,Kitchen,Cook Spicy Eel,"COOKSANITY" -3269,Kitchen,Cook Squid Ink Ravioli,"COOKSANITY" -3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS" -3271,Kitchen,Cook Stuffing,"COOKSANITY" -3272,Kitchen,Cook Super Meal,"COOKSANITY" -3273,Kitchen,Cook Survival Burger,"COOKSANITY" -3274,Kitchen,Cook Tom Kha Soup,"COOKSANITY" -3275,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS" -3276,Kitchen,Cook Triple Shot Espresso,"COOKSANITY" -3277,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND" -3278,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS" -3279,Kitchen,Cook Vegetable Medley,"COOKSANITY" +3201,Kitchen,Cook Algae Soup,"COOKSANITY", +3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", +3203,Kitchen,Cook Autumn's Bounty,"COOKSANITY", +3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", +3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", +3206,Kitchen,Cook Bean Hotpot,"COOKSANITY", +3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", +3208,Kitchen,Cook Blueberry Tart,"COOKSANITY", +3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", +3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", +3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", +3212,Kitchen,Cook Cheese Cauliflower,"COOKSANITY", +3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", +3214,Kitchen,Cook Chowder,"COOKSANITY", +3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", +3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", +3217,Kitchen,Cook Cookie,"COOKSANITY", +3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", +3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", +3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY", +3221,Kitchen,Cook Crispy Bass,"COOKSANITY", +3222,Kitchen,Cook Dish O' The Sea,"COOKSANITY", +3223,Kitchen,Cook Eggplant Parmesan,"COOKSANITY", +3224,Kitchen,Cook Escargot,"COOKSANITY", +3225,Kitchen,Cook Farmer's Lunch,"COOKSANITY", +3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", +3227,Kitchen,Cook Fish Stew,"COOKSANITY", +3228,Kitchen,Cook Fish Taco,"COOKSANITY", +3229,Kitchen,Cook Fried Calamari,"COOKSANITY", +3230,Kitchen,Cook Fried Eel,"COOKSANITY", +3231,Kitchen,Cook Fried Egg,"COOKSANITY", +3232,Kitchen,Cook Fried Mushroom,"COOKSANITY", +3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", +3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", +3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", +3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", +3237,Kitchen,Cook Ice Cream,"COOKSANITY", +3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", +3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", +3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", +3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", +3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", +3243,Kitchen,Cook Miner's Treat,"COOKSANITY", +3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", +3245,Kitchen,Cook Pale Broth,"COOKSANITY", +3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", +3247,Kitchen,Cook Parsnip Soup,"COOKSANITY", +3248,Kitchen,Cook Pepper Poppers,"COOKSANITY", +3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", +3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", +3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", +3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", +3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", +3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", +3255,Kitchen,Cook Pumpkin Soup,"COOKSANITY", +3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", +3257,Kitchen,Cook Red Plate,"COOKSANITY", +3258,Kitchen,Cook Rhubarb Pie,"COOKSANITY", +3259,Kitchen,Cook Rice Pudding,"COOKSANITY", +3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", +3261,Kitchen,Cook Roots Platter,"COOKSANITY", +3262,Kitchen,Cook Salad,"COOKSANITY", +3263,Kitchen,Cook Salmon Dinner,"COOKSANITY", +3264,Kitchen,Cook Sashimi,"COOKSANITY", +3265,Kitchen,Cook Seafoam Pudding,"COOKSANITY", +3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", +3267,Kitchen,Cook Spaghetti,"COOKSANITY", +3268,Kitchen,Cook Spicy Eel,"COOKSANITY", +3269,Kitchen,Cook Squid Ink Ravioli,"COOKSANITY", +3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", +3271,Kitchen,Cook Strange Bun,"COOKSANITY", +3272,Kitchen,Cook Stuffing,"COOKSANITY", +3273,Kitchen,Cook Super Meal,"COOKSANITY", +3274,Kitchen,Cook Survival Burger,"COOKSANITY", +3275,Kitchen,Cook Tom Kha Soup,"COOKSANITY", +3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", +3277,Kitchen,Cook Triple Shot Espresso,"COOKSANITY", +3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", +3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", +3280,Kitchen,Cook Vegetable Medley,"COOKSANITY", +3301,Farm,Learn Recipe Algae Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3302,The Queen of Sauce,Learn Recipe Artichoke Dip,"CHEFSANITY,CHEFSANITY_QOS", +3303,Farm,Learn Recipe Autumn's Bounty,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3304,The Queen of Sauce,Learn Recipe Baked Fish,"CHEFSANITY,CHEFSANITY_QOS", +3305,Farm,Learn Recipe Banana Pudding,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3306,Farm,Learn Recipe Bean Hotpot,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3307,The Queen of Sauce,Learn Recipe Blackberry Cobbler,"CHEFSANITY,CHEFSANITY_QOS", +3308,Farm,Learn Recipe Blueberry Tart,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3309,The Queen of Sauce,Learn Recipe Bread,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +3310,The Queen of Sauce,Learn Recipe Bruschetta,"CHEFSANITY,CHEFSANITY_QOS", +3311,The Queen of Sauce,Learn Recipe Carp Surprise,"CHEFSANITY,CHEFSANITY_QOS", +3312,Farm,Learn Recipe Cheese Cauliflower,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3313,The Queen of Sauce,Learn Recipe Chocolate Cake,"CHEFSANITY,CHEFSANITY_QOS", +3314,Farm,Learn Recipe Chowder,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3315,The Queen of Sauce,Learn Recipe Coleslaw,"CHEFSANITY,CHEFSANITY_QOS", +3316,The Queen of Sauce,Learn Recipe Complete Breakfast,"CHEFSANITY,CHEFSANITY_QOS", +3317,Farm,Learn Recipe Cookie,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3318,The Queen of Sauce,Learn Recipe Crab Cakes,"CHEFSANITY,CHEFSANITY_QOS", +3319,The Queen of Sauce,Learn Recipe Cranberry Candy,"CHEFSANITY,CHEFSANITY_QOS", +3320,Farm,Learn Recipe Cranberry Sauce,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3321,Farm,Learn Recipe Crispy Bass,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3322,Farm,Learn Recipe Dish O' The Sea,"CHEFSANITY,CHEFSANITY_SKILL", +3323,Farm,Learn Recipe Eggplant Parmesan,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3324,Farm,Learn Recipe Escargot,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3325,Farm,Learn Recipe Farmer's Lunch,"CHEFSANITY,CHEFSANITY_SKILL", +3326,The Queen of Sauce,Learn Recipe Fiddlehead Risotto,"CHEFSANITY,CHEFSANITY_QOS", +3327,Farm,Learn Recipe Fish Stew,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3328,Farm,Learn Recipe Fish Taco,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3329,Farm,Learn Recipe Fried Calamari,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3330,Farm,Learn Recipe Fried Eel,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3331,Farm,Learn Recipe Fried Egg,"CHEFSANITY_STARTER", +3332,Farm,Learn Recipe Fried Mushroom,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3333,The Queen of Sauce,Learn Recipe Fruit Salad,"CHEFSANITY,CHEFSANITY_QOS", +3334,Farm,Learn Recipe Ginger Ale,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3335,The Queen of Sauce,Learn Recipe Glazed Yams,"CHEFSANITY,CHEFSANITY_QOS", +3336,The Queen of Sauce,Learn Recipe Hashbrowns,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3337,Farm,Learn Recipe Ice Cream,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3338,The Queen of Sauce,Learn Recipe Lobster Bisque,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +3339,The Queen of Sauce,Learn Recipe Lucky Lunch,"CHEFSANITY,CHEFSANITY_QOS", +3340,The Queen of Sauce,Learn Recipe Maki Roll,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3341,Farm,Learn Recipe Mango Sticky Rice,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3342,The Queen of Sauce,Learn Recipe Maple Bar,"CHEFSANITY,CHEFSANITY_QOS", +3343,Farm,Learn Recipe Miner's Treat,"CHEFSANITY,CHEFSANITY_SKILL", +3344,The Queen of Sauce,Learn Recipe Omelet,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3345,Farm,Learn Recipe Pale Broth,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3346,The Queen of Sauce,Learn Recipe Pancakes,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3347,Farm,Learn Recipe Parsnip Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3348,Farm,Learn Recipe Pepper Poppers,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3349,The Queen of Sauce,Learn Recipe Pink Cake,"CHEFSANITY,CHEFSANITY_QOS", +3350,The Queen of Sauce,Learn Recipe Pizza,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3351,The Queen of Sauce,Learn Recipe Plum Pudding,"CHEFSANITY,CHEFSANITY_QOS", +3352,Farm,Learn Recipe Poi,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3353,The Queen of Sauce,Learn Recipe Poppyseed Muffin,"CHEFSANITY,CHEFSANITY_QOS", +3354,The Queen of Sauce,Learn Recipe Pumpkin Pie,"CHEFSANITY,CHEFSANITY_QOS", +3355,Farm,Learn Recipe Pumpkin Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3356,The Queen of Sauce,Learn Recipe Radish Salad,"CHEFSANITY,CHEFSANITY_QOS", +3357,Farm,Learn Recipe Red Plate,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3358,Farm,Learn Recipe Rhubarb Pie,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3359,Farm,Learn Recipe Rice Pudding,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3360,The Queen of Sauce,Learn Recipe Roasted Hazelnuts,"CHEFSANITY,CHEFSANITY_QOS", +3361,Farm,Learn Recipe Roots Platter,"CHEFSANITY,CHEFSANITY_SKILL", +3362,Farm,Learn Recipe Salad,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3363,Farm,Learn Recipe Salmon Dinner,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3364,Farm,Learn Recipe Sashimi,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3365,Farm,Learn Recipe Seafoam Pudding,"CHEFSANITY,CHEFSANITY_SKILL", +3366,The Queen of Sauce,Learn Recipe Shrimp Cocktail,"CHEFSANITY,CHEFSANITY_QOS", +3367,Farm,Learn Recipe Spaghetti,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3368,Farm,Learn Recipe Spicy Eel,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3369,Farm,Learn Recipe Squid Ink Ravioli,"CHEFSANITY,CHEFSANITY_SKILL", +3370,The Queen of Sauce,Learn Recipe Stir Fry,"CHEFSANITY,CHEFSANITY_QOS", +3371,Farm,Learn Recipe Strange Bun,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3372,Farm,Learn Recipe Stuffing,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3373,Farm,Learn Recipe Super Meal,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3374,Farm,Learn Recipe Survival Burger,"CHEFSANITY,CHEFSANITY_SKILL", +3375,Farm,Learn Recipe Tom Kha Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3376,The Queen of Sauce,Learn Recipe Tortilla,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3377,Farm,Learn Recipe Triple Shot Espresso,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Farm,Learn Recipe Tropical Curry,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3379,The Queen of Sauce,Learn Recipe Trout Soup,"CHEFSANITY,CHEFSANITY_QOS", +3380,Farm,Learn Recipe Vegetable Medley,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 6330fd511de5..80125b85511b 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -153,6 +153,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) squid_ink_ravioli = skill_recipe(Meal.squid_ink_ravioli, Skill.combat, 9, {AnimalProduct.squid_ink: 1, Ingredient.wheat_flour: 1, Vegetable.tomato: 1}) stir_fry_ingredients = {Forageable.cave_carrot: 1, Forageable.common_mushroom: 1, Vegetable.kale: 1, Ingredient.sugar: 1} stir_fry_qos = queen_of_sauce_recipe(Meal.stir_fry, 1, Season.spring, 7, stir_fry_ingredients) +strange_bun = friendship_recipe(Meal.strange_bun, NPC.shane, 7, {Ingredient.wheat_flour: 1, Fish.periwinkle: 1, ArtisanGood.void_mayonnaise: 1}) stuffing = friendship_recipe(Meal.stuffing, NPC.pam, 7, {Meal.bread: 1, Fruit.cranberries: 1, Forageable.hazelnut: 1}) super_meal = friendship_recipe(Meal.super_meal, NPC.kent, 7, {Vegetable.bok_choy: 1, Fruit.cranberries: 1, Vegetable.artichoke: 1}) survival_burger = skill_recipe(Meal.survival_burger, Skill.foraging, 2, {Meal.bread: 1, Forageable.cave_carrot: 1, Vegetable.eggplant: 1}) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index ae433d46e055..00c6bab55b91 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -67,6 +67,12 @@ class Group(enum.Enum): WALNUT_PURCHASE = enum.auto() TV_CHANNEL = enum.auto() CRAFTING_RECIPE = enum.auto() + CHEFSANITY = enum.auto() + CHEFSANITY_STARTER = enum.auto() + CHEFSANITY_QOS = enum.auto() + CHEFSANITY_PURCHASE = enum.auto() + CHEFSANITY_FRIENDSHIP = enum.auto() + CHEFSANITY_SKILL = enum.auto() MAGIC_SPELL = enum.auto() @@ -199,6 +205,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_special_order_qi_rewards(item_factory, world_options, items) create_walnut_purchase_rewards(item_factory, world_options, items) create_crafting_recipes(item_factory, world_options, items) + create_cooking_recipes(item_factory, world_options, items) create_magic_mod_spells(item_factory, world_options, items) items.append(item_factory("Golden Egg")) @@ -523,10 +530,30 @@ def create_tv_channels(item_factory: StardewItemFactory, items: List[Item]): def create_crafting_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): if world_options[options.Shipsanity] == options.Shipsanity.option_everything: crafting_recipes = [reward for reward in items_by_group[Group.CRAFTING_RECIPE]] - crafting_recipes = remove_excluded_packs(crafting_recipes, world_options) + crafting_recipes = remove_excluded_items(crafting_recipes, world_options) items.extend([item_factory(item) for item in crafting_recipes]) +def create_cooking_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): + chefsanity = world_options[options.Chefsanity] + if chefsanity == options.Chefsanity.option_vanilla: + return + + chefsanity_recipes_by_name = {recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_STARTER]} # Dictionary to not make duplicates + + if chefsanity & options.Chefsanity.option_queen_of_sauce: + chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_QOS]}) + if chefsanity & options.Chefsanity.option_purchases: + chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_PURCHASE]}) + if chefsanity & options.Chefsanity.option_friendship: + chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_FRIENDSHIP]}) + if chefsanity & options.Chefsanity.option_skills: + chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_SKILL]}) + + filtered_chefsanity_recipes = remove_excluded_items(list(chefsanity_recipes_by_name.values()), world_options) + items.extend([item_factory(item) for item in filtered_chefsanity_recipes]) + + def create_filler_festival_rewards(item_factory: StardewItemFactory, world_options: StardewOptions) -> List[Item]: if world_options[options.FestivalLocations] == options.FestivalLocations.option_disabled: return [] @@ -571,7 +598,7 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true all_filler_packs = get_all_filler_items(include_traps, exclude_ginger_island) - priority_filler_items = remove_excluded_packs(priority_filler_items, exclude_ginger_island) + priority_filler_items = remove_excluded_items(priority_filler_items, exclude_ginger_island) number_priority_items = len(priority_filler_items) required_resource_pack = number_locations - len(items_already_added) @@ -609,7 +636,7 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options return items -def remove_excluded_packs(packs, exclude_ginger_island: bool): +def remove_excluded_items(packs, exclude_ginger_island: bool): included_packs = [pack for pack in packs if Group.DEPRECATED not in pack.groups] if exclude_ginger_island: included_packs = [pack for pack in included_packs if Group.GINGER_ISLAND not in pack.groups] diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 5ead40555d7c..4616649cf92b 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -74,6 +74,12 @@ class LocationTags(enum.Enum): SHIPSANITY_FULL_SHIPMENT = enum.auto() COOKSANITY = enum.auto() COOKSANITY_QOS = enum.auto() + CHEFSANITY = enum.auto() + CHEFSANITY_QOS = enum.auto() + CHEFSANITY_PURCHASE = enum.auto() + CHEFSANITY_FRIENDSHIP = enum.auto() + CHEFSANITY_SKILL = enum.auto() + CHEFSANITY_STARTER = enum.auto() # Skill Mods LUCK_LEVEL = enum.auto() BINNING_LEVEL = enum.auto() @@ -361,6 +367,26 @@ def extend_cooksanity_locations(randomized_locations: List[LocationData], world_ randomized_locations.extend(filtered_cooksanity_locations) +def extend_chefsanity_locations(randomized_locations: List[LocationData], world_options): + chefsanity = world_options[options.Chefsanity] + if chefsanity == options.Chefsanity.option_vanilla: + return + + chefsanity_locations_by_name = {} # Dictionary to not make duplicates + + if chefsanity & options.Chefsanity.option_queen_of_sauce: + chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_QOS]}) + if chefsanity & options.Chefsanity.option_purchases: + chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_PURCHASE]}) + if chefsanity & options.Chefsanity.option_friendship: + chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_FRIENDSHIP]}) + if chefsanity & options.Chefsanity.option_skills: + chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_SKILL]}) + + filtered_chefsanity_locations = filter_disabled_locations(world_options, list(chefsanity_locations_by_name.values())) + randomized_locations.extend(filtered_chefsanity_locations) + + def create_locations(location_collector: StardewLocationCollector, options: StardewValleyOptions, random: Random): @@ -403,6 +429,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_monstersanity_locations(randomized_locations, world_options) extend_shipsanity_locations(randomized_locations, world_options) extend_cooksanity_locations(randomized_locations, world_options) + extend_chefsanity_locations(randomized_locations, world_options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 5e5ba1a8cc0c..4fe4db11db43 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -426,6 +426,27 @@ class Cooksanity(Choice): option_all = 2 +class Chefsanity(Choice): + """Locations for leaning cooking recipes? + Vanilla: All cooking recipes are learned normally + Queen of Sauce: Every Queen of sauce episode is a check, all queen of sauce recipes are items + Purchases: Every purchasable recipe is a check + Friendship: Recipes obtained from friendship are checks + Skills: Recipes obtained from skills are checks + All: Learning every cooking recipe is a check + """ + internal_name = "chefsanity" + display_name = "Chefsanity" + default = 0 + option_vanilla = 0b000 # 0 + option_queen_of_sauce = 0b0001 # 1 + option_purchases = 0b0010 # 2 + option_qos_and_purchases = 0b0011 # 3 + option_friendship = 0b0100 # 4 + option_skills = 0b1000 # 8 + option_all = 0b1111 # 15 + + class Friendsanity(Choice): """Shuffle Friendships? None: Friendship hearts are earned normally @@ -640,6 +661,7 @@ class StardewValleyOptions(PerGameCommonOptions): Monstersanity, Shipsanity, Cooksanity, + Chefsanity, friendsanity: Friendsanity friendsanity_heart_size: FriendsanityHeartSize movement_buff_number: NumberOfMovementBuffs diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index efcd2c641659..6761b8b611d0 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -17,9 +17,10 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: vanilla_regions = [ RegionData(Region.menu, [Entrance.to_stardew_valley]), RegionData(Region.stardew_valley, [Entrance.to_farmhouse]), - RegionData(Region.farm_house, [Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar, Entrance.farmhouse_cooking]), + RegionData(Region.farm_house, [Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar, Entrance.farmhouse_cooking, Entrance.watch_queen_of_sauce]), RegionData(Region.cellar), RegionData(Region.kitchen), + RegionData(Region.queen_of_sauce), RegionData(Region.farm, [Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse, @@ -243,6 +244,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.farmhouse_to_farm, Region.farm), ConnectionData(Entrance.downstairs_to_cellar, Region.cellar), ConnectionData(Entrance.farmhouse_cooking, Region.kitchen), + ConnectionData(Entrance.watch_queen_of_sauce, Region.queen_of_sauce), ConnectionData(Entrance.farm_to_backwoods, Region.backwoods), ConnectionData(Entrance.farm_to_bus_stop, Region.bus_stop), ConnectionData(Entrance.farm_to_forest, Region.forest), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index da17200e69ee..79ad33c8d466 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -6,6 +6,7 @@ from . import options, locations from .bundles import Bundle from .data.monster_data import all_monsters_by_category, all_monsters_by_name +from .data.recipe_data import all_cooking_recipes_by_name from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices from .stardew_rule import And @@ -26,6 +27,7 @@ from .strings.season_names import Season from .strings.skill_names import ModSkill, Skill from .strings.tool_names import Tool, ToolMaterial +from .strings.tv_channel_names import Channel from .strings.villager_names import NPC, ModNPC from .strings.wallet_item_names import Wallet @@ -60,6 +62,8 @@ def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOption set_festival_rules(all_location_names, logic, multi_world, player) set_monstersanity_rules(all_location_names, logic, multi_world, player, world_options) set_shipsanity_rules(all_location_names, logic, multi_world, player, world_options) + set_cooksanity_rules(all_location_names, logic, multi_world, player, world_options) + set_chefsanity_rules(all_location_names, logic, multi_world, player, world_options) set_isolated_locations_rules(logic, multi_world, player) set_traveling_merchant_rules(logic, multi_world, player) set_arcade_machine_rules(logic, multi_world, player, world_options) @@ -252,7 +256,9 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: set_bedroom_entrance_rules(logic, multi_world, player, world_options) set_festival_entrance_rules(logic, multiworld, player) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin().simplify()) + MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce).simplify()) def set_farm_buildings_entrance_rules(logic, multi_world, player): @@ -696,7 +702,7 @@ def set_monstersanity_category_rules(all_location_names: List[str], logic: Stard def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): shipsanity_option = world_options[options.Shipsanity] - if shipsanity_option == options.Monstersanity.option_none: + if shipsanity_option == options.Shipsanity.option_none: return shipsanity_prefix = "Shipsanity: " @@ -704,8 +710,37 @@ def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, mul if location.name not in all_location_names: continue item_to_ship = location.name[len(shipsanity_prefix):] - MultiWorldRules.set_rule(multi_world.get_location(location.name, player), - logic.shipping.can_ship(item_to_ship)) + MultiWorldRules.set_rule(multi_world.get_location(location.name, player), logic.shipping.can_ship(item_to_ship)) + + +def set_cooksanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): + cooksanity_option = world_options[options.Cooksanity] + if cooksanity_option == options.Cooksanity.option_none: + return + + cooksanity_prefix = "Cook " + for location in locations.locations_by_tag[LocationTags.COOKSANITY]: + if location.name not in all_location_names: + continue + recipe_name = location.name[len(cooksanity_prefix):] + recipe = all_cooking_recipes_by_name[recipe_name] + cook_rule = logic.cooking.can_cook(recipe) + MultiWorldRules.set_rule(multi_world.get_location(location.name, player), cook_rule) + + +def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): + chefsanity_option = world_options[options.Chefsanity] + if chefsanity_option == options.Chefsanity.option_vanilla: + return + + chefsanity_prefix = "Learn Recipe " + for location in locations.locations_by_tag[LocationTags.CHEFSANITY]: + if location.name not in all_location_names: + continue + recipe_name = location.name[len(chefsanity_prefix):] + recipe = all_cooking_recipes_by_name[recipe_name] + learn_rule = logic.cooking.can_learn_recipe(recipe.source) + MultiWorldRules.set_rule(multi_world.get_location(location.name, player), learn_rule) def set_traveling_merchant_day_rules(logic: StardewLogic, multi_world: MultiWorld, player: int): diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 2901bb41d15b..d455479ca885 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -186,6 +186,7 @@ class Entrance: farmhouse_cooking = "Farmhouse Cooking" island_cooking = "Island Cooking" shipping = "Use Shipping Bin" + watch_queen_of_sauce = "Watch Queen of Sauce" blacksmith_copper = "Upgrade Copper Tools" blacksmith_iron = "Upgrade Iron Tools" blacksmith_gold = "Upgrade Gold Tools" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 6d94bd35748e..4550f2d7764c 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -150,6 +150,7 @@ class Region: dangerous_mines_100 = "Dangerous Mines - Floor 100" kitchen = "Kitchen" shipping = "Shipping" + queen_of_sauce = "The Queen of Sauce" blacksmith_copper = "Blacksmith Copper Upgrades" blacksmith_iron = "Blacksmith Iron Upgrades" blacksmith_gold = "Blacksmith Gold Upgrades" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index b7a30dbedb1b..89c33da5bfca 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -23,6 +23,7 @@ class TestBaseItemGeneration(SVTestBase): options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Chefsanity.internal_name: options.Chefsanity.option_all, } def test_all_progression_items_are_added_to_the_pool(self): @@ -71,6 +72,7 @@ class TestNoGingerIslandItemGeneration(SVTestBase): options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Chefsanity.internal_name: options.Chefsanity.option_all, } def test_all_progression_items_except_island_are_added_to_the_pool(self): diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index ba9669453b8a..af10f88b3700 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -53,6 +53,7 @@ class TestBaseItemGeneration(SVTestBase): options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Chefsanity.internal_name: options.Chefsanity.option_all, options.Mods.internal_name: mod_list } @@ -77,6 +78,7 @@ class TestNoGingerIslandModItemGeneration(SVTestBase): options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, options.Shipsanity.internal_name: options.Shipsanity.option_everything, + options.Chefsanity.internal_name: options.Chefsanity.option_all, options.Mods.internal_name: mod_list } From 14eae4c329be169abf2e916b16ebc54b63fbbcb3 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Sep 2023 01:11:00 -0400 Subject: [PATCH 070/482] - Updated location checks --- worlds/stardew_valley/test/TestGeneration.py | 4 ++-- worlds/stardew_valley/test/__init__.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 89c33da5bfca..d35ca957408e 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -304,7 +304,7 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1633 + expected_locations = 1792 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -318,7 +318,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 1885 + expected_locations = 2044 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 88cb3434e750..9d034d00c46a 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -158,7 +158,7 @@ def default_options(): def allsanity_options_without_mods(): allsanity = { Goal.internal_name: Goal.option_perfection, - BundleRandomization.internal_name: BundleRandomization.option_shuffled, + BundleRandomization.internal_name: BundleRandomization.option_thematic, BundlePrice.internal_name: BundlePrice.option_expensive, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, Cropsanity.internal_name: Cropsanity.option_enabled, @@ -174,7 +174,9 @@ def allsanity_options_without_mods(): Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, Monstersanity.internal_name: Monstersanity.option_progressive_goals, - Shipsanity.internal_name: , + Shipsanity.internal_name: Shipsanity.option_everything, + Cooksanity.internal_name: Cooksanity.option_all, + Chefsanity.internal_name: Chefsanity.option_all, Friendsanity.internal_name: Friendsanity.option_all_with_marriage, FriendsanityHeartSize.internal_name: 1, NumberOfMovementBuffs.internal_name: 12, From 52ae15c758dfc58684107e198c9fe297ac59e036 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Sep 2023 11:17:48 -0400 Subject: [PATCH 071/482] - Placed all shipsanity locations in the shipping region, for performance --- worlds/stardew_valley/data/locations.csv | 1146 +++++++++++----------- worlds/stardew_valley/options.py | 2 +- 2 files changed, 574 insertions(+), 574 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 816deaa741b0..44878e0ba171 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1042,579 +1042,579 @@ id,region,name,tags,mod_name 2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", 2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", 2347,Farming,Harvest Coffee Bean,"CROPSANITY", -2401,Farm,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2402,Farm,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2403,Farm,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2404,Farm,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2405,Farm,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2406,Farm,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2407,Farm,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2408,Farm,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2409,Farm,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2410,Farm,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2411,Farm,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2412,Farm,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2413,Farm,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2414,Farm,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2415,Farm,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2416,Farm,Shipsanity: Anchor,SHIPSANITY, -2417,Farm,Shipsanity: Ancient Doll,SHIPSANITY, -2418,Farm,Shipsanity: Ancient Drum,SHIPSANITY, -2419,Farm,Shipsanity: Ancient Seed,SHIPSANITY, -2420,Farm,Shipsanity: Ancient Sword,SHIPSANITY, -2421,Farm,Shipsanity: Arrowhead,SHIPSANITY, -2422,Farm,Shipsanity: Artifact Trove,SHIPSANITY, -2423,Farm,Shipsanity: Bone Flute,SHIPSANITY, -2424,Farm,Shipsanity: Chewing Stick,SHIPSANITY, -2425,Farm,Shipsanity: Chicken Statue,SHIPSANITY, -2426,Farm,Shipsanity: Chipped Amphora,SHIPSANITY, -2427,Farm,Shipsanity: Dinosaur Egg,SHIPSANITY, -2428,Farm,Shipsanity: Dried Starfish,SHIPSANITY, -2429,Farm,Shipsanity: Dwarf Gadget,SHIPSANITY, -2430,Farm,Shipsanity: Dwarf Scroll I,SHIPSANITY, -2431,Farm,Shipsanity: Dwarf Scroll II,SHIPSANITY, -2432,Farm,Shipsanity: Dwarf Scroll III,SHIPSANITY, -2433,Farm,Shipsanity: Dwarf Scroll IV,SHIPSANITY, -2434,Farm,Shipsanity: Dwarvish Helm,SHIPSANITY, -2435,Farm,Shipsanity: Elvish Jewelry,SHIPSANITY, -2436,Farm,Shipsanity: Glass Shards,SHIPSANITY, -2437,Farm,Shipsanity: Golden Mask,SHIPSANITY, -2438,Farm,Shipsanity: Golden Relic,SHIPSANITY, -2439,Farm,Shipsanity: Ornamental Fan,SHIPSANITY, -2440,Farm,Shipsanity: Prehistoric Handaxe,SHIPSANITY, -2441,Farm,Shipsanity: Prehistoric Tool,SHIPSANITY, -2442,Farm,Shipsanity: Rare Disc,SHIPSANITY, -2443,Farm,Shipsanity: Rusty Cog,SHIPSANITY, -2444,Farm,Shipsanity: Rusty Spoon,SHIPSANITY, -2445,Farm,Shipsanity: Rusty Spur,SHIPSANITY, -2446,Farm,Shipsanity: Strange Doll,SHIPSANITY, -2447,Farm,Shipsanity: Strange Doll (Green),SHIPSANITY, -2448,Farm,Shipsanity: Treasure Chest,SHIPSANITY, -2449,Farm,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2450,Farm,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2451,Farm,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2452,Farm,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2453,Farm,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2454,Farm,Shipsanity: Coffee,SHIPSANITY, -2455,Farm,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2456,Farm,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2457,Farm,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2458,Farm,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2459,Farm,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2460,Farm,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2461,Farm,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2462,Farm,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2463,Farm,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2464,Farm,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2465,Farm,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2466,Farm,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2467,Farm,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2468,Farm,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2469,Farm,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2470,Farm,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2471,Farm,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2472,Farm,Shipsanity: Algae Soup,SHIPSANITY, -2473,Farm,Shipsanity: Artichoke Dip,SHIPSANITY, -2474,Farm,Shipsanity: Autumn's Bounty,SHIPSANITY, -2475,Farm,Shipsanity: Baked Fish,SHIPSANITY, -2476,Farm,Shipsanity: Bean Hotpot,SHIPSANITY, -2477,Farm,Shipsanity: Blackberry Cobbler,SHIPSANITY, -2478,Farm,Shipsanity: Blueberry Tart,SHIPSANITY, -2479,Farm,Shipsanity: Bread,SHIPSANITY, -2480,Farm,Shipsanity: Bruschetta,SHIPSANITY, -2481,Farm,Shipsanity: Carp Surprise,SHIPSANITY, -2482,Farm,Shipsanity: Cheese Cauliflower,SHIPSANITY, -2483,Farm,Shipsanity: Chocolate Cake,SHIPSANITY, -2484,Farm,Shipsanity: Chowder,SHIPSANITY, -2485,Farm,Shipsanity: Coleslaw,SHIPSANITY, -2486,Farm,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Farm,Shipsanity: Cookie,SHIPSANITY, -2488,Farm,Shipsanity: Crab Cakes,SHIPSANITY, -2489,Farm,Shipsanity: Cranberry Candy,SHIPSANITY, -2490,Farm,Shipsanity: Cranberry Sauce,SHIPSANITY, -2491,Farm,Shipsanity: Crispy Bass,SHIPSANITY, -2492,Farm,Shipsanity: Dish O' The Sea,SHIPSANITY, -2493,Farm,Shipsanity: Eggplant Parmesan,SHIPSANITY, -2494,Farm,Shipsanity: Escargot,SHIPSANITY, -2495,Farm,Shipsanity: Farmer's Lunch,SHIPSANITY, -2496,Farm,Shipsanity: Fiddlehead Risotto,SHIPSANITY, -2497,Farm,Shipsanity: Fish Stew,SHIPSANITY, -2498,Farm,Shipsanity: Fish Taco,SHIPSANITY, -2499,Farm,Shipsanity: Fried Calamari,SHIPSANITY, -2500,Farm,Shipsanity: Fried Eel,SHIPSANITY, -2501,Farm,Shipsanity: Fried Egg,SHIPSANITY, -2502,Farm,Shipsanity: Fried Mushroom,SHIPSANITY, -2503,Farm,Shipsanity: Fruit Salad,SHIPSANITY, -2504,Farm,Shipsanity: Glazed Yams,SHIPSANITY, -2505,Farm,Shipsanity: Hashbrowns,SHIPSANITY, -2506,Farm,Shipsanity: Ice Cream,SHIPSANITY, -2507,Farm,Shipsanity: Lobster Bisque,SHIPSANITY, -2508,Farm,Shipsanity: Lucky Lunch,SHIPSANITY, -2509,Farm,Shipsanity: Maki Roll,SHIPSANITY, -2510,Farm,Shipsanity: Maple Bar,SHIPSANITY, -2511,Farm,Shipsanity: Miner's Treat,SHIPSANITY, -2512,Farm,Shipsanity: Omelet,SHIPSANITY, -2513,Farm,Shipsanity: Pale Broth,SHIPSANITY, -2514,Farm,Shipsanity: Pancakes,SHIPSANITY, -2515,Farm,Shipsanity: Parsnip Soup,SHIPSANITY, -2516,Farm,Shipsanity: Pepper Poppers,SHIPSANITY, -2517,Farm,Shipsanity: Pink Cake,SHIPSANITY, -2518,Farm,Shipsanity: Pizza,SHIPSANITY, -2519,Farm,Shipsanity: Plum Pudding,SHIPSANITY, -2520,Farm,Shipsanity: Poppyseed Muffin,SHIPSANITY, -2521,Farm,Shipsanity: Pumpkin Pie,SHIPSANITY, -2522,Farm,Shipsanity: Pumpkin Soup,SHIPSANITY, -2523,Farm,Shipsanity: Radish Salad,SHIPSANITY, -2524,Farm,Shipsanity: Red Plate,SHIPSANITY, -2525,Farm,Shipsanity: Rhubarb Pie,SHIPSANITY, -2526,Farm,Shipsanity: Rice Pudding,SHIPSANITY, -2527,Farm,Shipsanity: Roasted Hazelnuts,SHIPSANITY, -2528,Farm,Shipsanity: Roots Platter,SHIPSANITY, -2529,Farm,Shipsanity: Salad,SHIPSANITY, -2530,Farm,Shipsanity: Salmon Dinner,SHIPSANITY, -2531,Farm,Shipsanity: Sashimi,SHIPSANITY, -2532,Farm,Shipsanity: Seafoam Pudding,SHIPSANITY, -2533,Farm,Shipsanity: Shrimp Cocktail,SHIPSANITY, -2534,Farm,Shipsanity: Spaghetti,SHIPSANITY, -2535,Farm,Shipsanity: Spicy Eel,SHIPSANITY, -2536,Farm,Shipsanity: Squid Ink Ravioli,SHIPSANITY, -2537,Farm,Shipsanity: Stir Fry,SHIPSANITY, -2538,Farm,Shipsanity: Strange Bun,SHIPSANITY, -2539,Farm,Shipsanity: Stuffing,SHIPSANITY, -2540,Farm,Shipsanity: Super Meal,SHIPSANITY, -2541,Farm,Shipsanity: Survival Burger,SHIPSANITY, -2542,Farm,Shipsanity: Tom Kha Soup,SHIPSANITY, -2543,Farm,Shipsanity: Tortilla,SHIPSANITY, -2544,Farm,Shipsanity: Triple Shot Espresso,SHIPSANITY, -2545,Farm,Shipsanity: Trout Soup,SHIPSANITY, -2546,Farm,Shipsanity: Vegetable Medley,SHIPSANITY, -2547,Farm,Shipsanity: Bait,SHIPSANITY, -2548,Farm,Shipsanity: Barbed Hook,SHIPSANITY, -2549,Farm,Shipsanity: Basic Fertilizer,SHIPSANITY, -2550,Farm,Shipsanity: Basic Retaining Soil,SHIPSANITY, -2551,Farm,Shipsanity: Blue Slime Egg,SHIPSANITY, -2552,Farm,Shipsanity: Bomb,SHIPSANITY, -2553,Farm,Shipsanity: Brick Floor,SHIPSANITY, -2554,Farm,Shipsanity: Bug Steak,SHIPSANITY, -2555,Farm,Shipsanity: Cherry Bomb,SHIPSANITY, -2556,Farm,Shipsanity: Cobblestone Path,SHIPSANITY, -2557,Farm,Shipsanity: Cookout Kit,SHIPSANITY, -2558,Farm,Shipsanity: Cork Bobber,SHIPSANITY, -2559,Farm,Shipsanity: Crab Pot,SHIPSANITY, -2560,Farm,Shipsanity: Crystal Floor,SHIPSANITY, -2561,Farm,Shipsanity: Crystal Path,SHIPSANITY, -2562,Farm,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, -2563,Farm,Shipsanity: Dressed Spinner,SHIPSANITY, -2564,Farm,Shipsanity: Drum Block,SHIPSANITY, -2565,Farm,Shipsanity: Explosive Ammo,SHIPSANITY, -2566,Farm,Shipsanity: Fiber Seeds,SHIPSANITY, -2567,Farm,Shipsanity: Field Snack,SHIPSANITY, -2568,Farm,Shipsanity: Flute Block,SHIPSANITY, -2569,Farm,Shipsanity: Gate,SHIPSANITY, -2570,Farm,Shipsanity: Gravel Path,SHIPSANITY, -2571,Farm,Shipsanity: Green Slime Egg,SHIPSANITY, -2572,Farm,Shipsanity: Hardwood Fence,SHIPSANITY, -2573,Farm,Shipsanity: Iridium Sprinkler,SHIPSANITY, -2574,Farm,Shipsanity: Iron Fence,SHIPSANITY, -2575,Farm,Shipsanity: Jack-O-Lantern,SHIPSANITY, -2576,Farm,Shipsanity: Lead Bobber,SHIPSANITY, -2577,Farm,Shipsanity: Life Elixir,SHIPSANITY, -2578,Farm,Shipsanity: Magnet,SHIPSANITY, -2579,Farm,Shipsanity: Mega Bomb,SHIPSANITY, -2580,Farm,Shipsanity: Monster Musk,SHIPSANITY, -2581,Farm,Shipsanity: Oil of Garlic,SHIPSANITY, -2582,Farm,Shipsanity: Purple Slime Egg,SHIPSANITY, -2583,Farm,Shipsanity: Quality Bobber,SHIPSANITY, -2584,Farm,Shipsanity: Quality Fertilizer,SHIPSANITY, -2585,Farm,Shipsanity: Quality Retaining Soil,SHIPSANITY, -2586,Farm,Shipsanity: Quality Sprinkler,SHIPSANITY, -2587,Farm,Shipsanity: Rain Totem,SHIPSANITY, -2588,Farm,Shipsanity: Red Slime Egg,SHIPSANITY, -2589,Farm,Shipsanity: Rustic Plank Floor,SHIPSANITY, -2590,Farm,Shipsanity: Speed-Gro,SHIPSANITY, -2591,Farm,Shipsanity: Spinner,SHIPSANITY, -2592,Farm,Shipsanity: Sprinkler,SHIPSANITY, -2593,Farm,Shipsanity: Stepping Stone Path,SHIPSANITY, -2594,Farm,Shipsanity: Stone Fence,SHIPSANITY, -2595,Farm,Shipsanity: Stone Floor,SHIPSANITY, -2596,Farm,Shipsanity: Stone Walkway Floor,SHIPSANITY, -2597,Farm,Shipsanity: Straw Floor,SHIPSANITY, -2598,Farm,Shipsanity: Torch,SHIPSANITY, -2599,Farm,Shipsanity: Trap Bobber,SHIPSANITY, -2600,Farm,Shipsanity: Treasure Hunter,SHIPSANITY, -2601,Farm,Shipsanity: Tree Fertilizer,SHIPSANITY, -2602,Farm,Shipsanity: Warp Totem: Beach,SHIPSANITY, -2603,Farm,Shipsanity: Warp Totem: Desert,SHIPSANITY, -2604,Farm,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Farm,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", -2606,Farm,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Farm,Shipsanity: Weathered Floor,SHIPSANITY, -2608,Farm,Shipsanity: Wild Bait,SHIPSANITY, -2609,Farm,Shipsanity: Wood Fence,SHIPSANITY, -2610,Farm,Shipsanity: Wood Floor,SHIPSANITY, -2611,Farm,Shipsanity: Wood Path,SHIPSANITY, -2612,Farm,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2613,Farm,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2614,Farm,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2615,Farm,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2616,Farm,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2617,Farm,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2618,Farm,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2619,Farm,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2620,Farm,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2621,Farm,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2622,Farm,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2623,Farm,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2624,Farm,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2625,Farm,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2626,Farm,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2627,Farm,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2628,Farm,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2629,Farm,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2630,Farm,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2631,Farm,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2632,Farm,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2633,Farm,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2634,Farm,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2635,Farm,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2636,Farm,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2637,Farm,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2638,Farm,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2639,Farm,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2640,Farm,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2641,Farm,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2642,Farm,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2643,Farm,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2644,Farm,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2645,Farm,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2646,Farm,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2647,Farm,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2648,Farm,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2649,Farm,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2650,Farm,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2651,Farm,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2652,Farm,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2653,Farm,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2654,Farm,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2655,Farm,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", -2656,Farm,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", -2657,Farm,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", -2658,Farm,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", -2659,Farm,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", -2660,Farm,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", -2661,Farm,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", -2662,Farm,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", -2663,Farm,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", -2664,Farm,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", -2665,Farm,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", -2666,Farm,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", -2667,Farm,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", -2668,Farm,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", -2669,Farm,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", -2670,Farm,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", -2671,Farm,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", -2672,Farm,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", -2673,Farm,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", -2674,Farm,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", -2675,Farm,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", -2676,Farm,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2677,Farm,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", -2678,Farm,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", -2679,Farm,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", -2680,Farm,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", -2681,Farm,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", -2682,Farm,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", -2683,Farm,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", -2684,Farm,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", -2685,Farm,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", -2686,Farm,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", -2687,Farm,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", -2688,Farm,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", -2689,Farm,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", -2690,Farm,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", -2691,Farm,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", -2692,Farm,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", -2693,Farm,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", -2694,Farm,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2695,Farm,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", -2696,Farm,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", -2697,Farm,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", -2698,Farm,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2699,Farm,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", -2700,Farm,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", -2701,Farm,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", -2702,Farm,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2703,Farm,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", -2704,Farm,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", -2705,Farm,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", -2706,Farm,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", -2707,Farm,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", -2708,Farm,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", -2709,Farm,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2710,Farm,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", -2711,Farm,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", -2712,Farm,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", -2713,Farm,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2714,Farm,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", -2715,Farm,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", -2716,Farm,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2717,Farm,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2718,Farm,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2719,Farm,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2720,Farm,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2721,Farm,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2722,Farm,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2723,Farm,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2724,Farm,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2725,Farm,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2726,Farm,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2727,Farm,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2728,Farm,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2729,Farm,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2730,Farm,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2731,Farm,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2732,Farm,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2733,Farm,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2734,Farm,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2735,Farm,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2736,Farm,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2737,Farm,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2738,Farm,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2739,Farm,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2740,Farm,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2741,Farm,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2742,Farm,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2743,Farm,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2744,Farm,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2745,Farm,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2746,Farm,Shipsanity: Tea Set,SHIPSANITY, -2747,Farm,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2748,Farm,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2749,Farm,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2750,Farm,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2751,Farm,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2752,Farm,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2753,Farm,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2754,Farm,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2755,Farm,Shipsanity: Oil,SHIPSANITY, -2756,Farm,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2757,Farm,Shipsanity: Rice,SHIPSANITY, -2758,Farm,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2759,Farm,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2760,Farm,Shipsanity: Sugar,SHIPSANITY, -2761,Farm,Shipsanity: Vinegar,SHIPSANITY, -2762,Farm,Shipsanity: Wheat Flour,SHIPSANITY, -2763,Farm,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2764,Farm,Shipsanity: Aerinite,SHIPSANITY, -2765,Farm,Shipsanity: Alamite,SHIPSANITY, -2766,Farm,Shipsanity: Amethyst,SHIPSANITY, -2767,Farm,Shipsanity: Amphibian Fossil,SHIPSANITY, -2768,Farm,Shipsanity: Aquamarine,SHIPSANITY, -2769,Farm,Shipsanity: Baryte,SHIPSANITY, -2770,Farm,Shipsanity: Basalt,SHIPSANITY, -2771,Farm,Shipsanity: Bixite,SHIPSANITY, -2772,Farm,Shipsanity: Calcite,SHIPSANITY, -2773,Farm,Shipsanity: Celestine,SHIPSANITY, -2774,Farm,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2775,Farm,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2776,Farm,Shipsanity: Diamond,SHIPSANITY, -2777,Farm,Shipsanity: Dolomite,SHIPSANITY, -2778,Farm,Shipsanity: Earth Crystal,SHIPSANITY, -2779,Farm,Shipsanity: Emerald,SHIPSANITY, -2780,Farm,Shipsanity: Esperite,SHIPSANITY, -2781,Farm,Shipsanity: Fairy Stone,SHIPSANITY, -2782,Farm,Shipsanity: Fire Opal,SHIPSANITY, -2783,Farm,Shipsanity: Fire Quartz,SHIPSANITY, -2784,Farm,Shipsanity: Fluorapatite,SHIPSANITY, -2785,Farm,Shipsanity: Frozen Geode,SHIPSANITY, -2786,Farm,Shipsanity: Frozen Tear,SHIPSANITY, -2787,Farm,Shipsanity: Geminite,SHIPSANITY, -2788,Farm,Shipsanity: Geode,SHIPSANITY, -2789,Farm,Shipsanity: Ghost Crystal,SHIPSANITY, -2790,Farm,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2791,Farm,Shipsanity: Granite,SHIPSANITY, -2792,Farm,Shipsanity: Helvite,SHIPSANITY, -2793,Farm,Shipsanity: Hematite,SHIPSANITY, -2794,Farm,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2795,Farm,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2796,Farm,Shipsanity: Jade,SHIPSANITY, -2797,Farm,Shipsanity: Jagoite,SHIPSANITY, -2798,Farm,Shipsanity: Jamborite,SHIPSANITY, -2799,Farm,Shipsanity: Jasper,SHIPSANITY, -2800,Farm,Shipsanity: Kyanite,SHIPSANITY, -2801,Farm,Shipsanity: Lemon Stone,SHIPSANITY, -2802,Farm,Shipsanity: Limestone,SHIPSANITY, -2803,Farm,Shipsanity: Lunarite,SHIPSANITY, -2804,Farm,Shipsanity: Magma Geode,SHIPSANITY, -2805,Farm,Shipsanity: Malachite,SHIPSANITY, -2806,Farm,Shipsanity: Marble,SHIPSANITY, -2807,Farm,Shipsanity: Mudstone,SHIPSANITY, -2808,Farm,Shipsanity: Nautilus Fossil,SHIPSANITY, -2809,Farm,Shipsanity: Nekoite,SHIPSANITY, -2810,Farm,Shipsanity: Neptunite,SHIPSANITY, -2811,Farm,Shipsanity: Obsidian,SHIPSANITY, -2812,Farm,Shipsanity: Ocean Stone,SHIPSANITY, -2813,Farm,Shipsanity: Omni Geode,SHIPSANITY, -2814,Farm,Shipsanity: Opal,SHIPSANITY, -2815,Farm,Shipsanity: Orpiment,SHIPSANITY, -2816,Farm,Shipsanity: Palm Fossil,SHIPSANITY, -2817,Farm,Shipsanity: Petrified Slime,SHIPSANITY, -2818,Farm,Shipsanity: Prehistoric Rib,SHIPSANITY, -2819,Farm,Shipsanity: Prehistoric Scapula,SHIPSANITY, -2820,Farm,Shipsanity: Prehistoric Skull,SHIPSANITY, -2821,Farm,Shipsanity: Prehistoric Tibia,SHIPSANITY, -2822,Farm,Shipsanity: Prehistoric Vertebra,SHIPSANITY, -2823,Farm,Shipsanity: Prismatic Shard,SHIPSANITY, -2824,Farm,Shipsanity: Pyrite,SHIPSANITY, -2825,Farm,Shipsanity: Quartz,SHIPSANITY, -2826,Farm,Shipsanity: Ruby,SHIPSANITY, -2827,Farm,Shipsanity: Sandstone,SHIPSANITY, -2828,Farm,Shipsanity: Skeletal Hand,SHIPSANITY, -2829,Farm,Shipsanity: Skeletal Tail,SHIPSANITY, -2830,Farm,Shipsanity: Slate,SHIPSANITY, -2831,Farm,Shipsanity: Soapstone,SHIPSANITY, -2832,Farm,Shipsanity: Star Shards,SHIPSANITY, -2833,Farm,Shipsanity: Thunder Egg,SHIPSANITY, -2834,Farm,Shipsanity: Tigerseye,SHIPSANITY, -2835,Farm,Shipsanity: Topaz,SHIPSANITY, -2836,Farm,Shipsanity: Trilobite,SHIPSANITY, -2837,Farm,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Farm,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", -2839,Farm,Shipsanity: Curiosity Lure,SHIPSANITY, -2840,Farm,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2841,Farm,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2842,Farm,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2843,Farm,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2844,Farm,Shipsanity: Bouquet,SHIPSANITY, -2845,Farm,Shipsanity: Energy Tonic,SHIPSANITY, -2846,Farm,Shipsanity: Golden Pumpkin,SHIPSANITY, -2847,Farm,Shipsanity: Green Algae,SHIPSANITY, -2848,Farm,Shipsanity: Hay,SHIPSANITY, -2849,Farm,Shipsanity: Magic Rock Candy,SHIPSANITY, -2850,Farm,Shipsanity: Muscle Remedy,SHIPSANITY, -2851,Farm,Shipsanity: Pearl,SHIPSANITY, -2852,Farm,Shipsanity: Rotten Plant,SHIPSANITY, -2853,Farm,Shipsanity: Seaweed,SHIPSANITY, -2854,Farm,Shipsanity: Void Ghost Pendant,SHIPSANITY, -2855,Farm,Shipsanity: White Algae,SHIPSANITY, -2856,Farm,Shipsanity: Wilted Bouquet,SHIPSANITY, -2857,Farm,Shipsanity: Secret Note,SHIPSANITY, -2858,Farm,Shipsanity: Acorn,SHIPSANITY, -2859,Farm,Shipsanity: Amaranth Seeds,SHIPSANITY, -2860,Farm,Shipsanity: Ancient Seeds,SHIPSANITY, -2861,Farm,Shipsanity: Apple Sapling,SHIPSANITY, -2862,Farm,Shipsanity: Apricot Sapling,SHIPSANITY, -2863,Farm,Shipsanity: Artichoke Seeds,SHIPSANITY, -2864,Farm,Shipsanity: Bean Starter,SHIPSANITY, -2865,Farm,Shipsanity: Beet Seeds,SHIPSANITY, -2866,Farm,Shipsanity: Blueberry Seeds,SHIPSANITY, -2867,Farm,Shipsanity: Bok Choy Seeds,SHIPSANITY, -2868,Farm,Shipsanity: Cactus Seeds,SHIPSANITY, -2869,Farm,Shipsanity: Cauliflower Seeds,SHIPSANITY, -2870,Farm,Shipsanity: Cherry Sapling,SHIPSANITY, -2871,Farm,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2872,Farm,Shipsanity: Corn Seeds,SHIPSANITY, -2873,Farm,Shipsanity: Cranberry Seeds,SHIPSANITY, -2874,Farm,Shipsanity: Eggplant Seeds,SHIPSANITY, -2875,Farm,Shipsanity: Fairy Seeds,SHIPSANITY, -2876,Farm,Shipsanity: Fall Seeds,SHIPSANITY, -2877,Farm,Shipsanity: Garlic Seeds,SHIPSANITY, -2878,Farm,Shipsanity: Grape Starter,SHIPSANITY, -2879,Farm,Shipsanity: Grass Starter,SHIPSANITY, -2880,Farm,Shipsanity: Hops Starter,SHIPSANITY, -2881,Farm,Shipsanity: Jazz Seeds,SHIPSANITY, -2882,Farm,Shipsanity: Kale Seeds,SHIPSANITY, -2883,Farm,Shipsanity: Mahogany Seed,SHIPSANITY, -2884,Farm,Shipsanity: Maple Seed,SHIPSANITY, -2885,Farm,Shipsanity: Melon Seeds,SHIPSANITY, -2886,Farm,Shipsanity: Mixed Seeds,SHIPSANITY, -2887,Farm,Shipsanity: Orange Sapling,SHIPSANITY, -2888,Farm,Shipsanity: Parsnip Seeds,SHIPSANITY, -2889,Farm,Shipsanity: Peach Sapling,SHIPSANITY, -2890,Farm,Shipsanity: Pepper Seeds,SHIPSANITY, -2891,Farm,Shipsanity: Pine Cone,SHIPSANITY, -2892,Farm,Shipsanity: Pomegranate Sapling,SHIPSANITY, -2893,Farm,Shipsanity: Poppy Seeds,SHIPSANITY, -2894,Farm,Shipsanity: Potato Seeds,SHIPSANITY, -2895,Farm,Shipsanity: Pumpkin Seeds,SHIPSANITY, -2896,Farm,Shipsanity: Radish Seeds,SHIPSANITY, -2897,Farm,Shipsanity: Rare Seed,SHIPSANITY, -2898,Farm,Shipsanity: Red Cabbage Seeds,SHIPSANITY, -2899,Farm,Shipsanity: Rhubarb Seeds,SHIPSANITY, -2900,Farm,Shipsanity: Rice Shoot,SHIPSANITY, -2901,Farm,Shipsanity: Spangle Seeds,SHIPSANITY, -2902,Farm,Shipsanity: Spring Seeds,SHIPSANITY, -2903,Farm,Shipsanity: Starfruit Seeds,SHIPSANITY, -2904,Farm,Shipsanity: Strawberry Seeds,SHIPSANITY, -2905,Farm,Shipsanity: Summer Seeds,SHIPSANITY, -2906,Farm,Shipsanity: Sunflower Seeds,SHIPSANITY, -2907,Farm,Shipsanity: Tea Sapling,SHIPSANITY, -2908,Farm,Shipsanity: Tomato Seeds,SHIPSANITY, -2909,Farm,Shipsanity: Tulip Bulb,SHIPSANITY, -2910,Farm,Shipsanity: Wheat Seeds,SHIPSANITY, -2911,Farm,Shipsanity: Winter Seeds,SHIPSANITY, -2912,Farm,Shipsanity: Yam Seeds,SHIPSANITY, -2913,Farm,Shipsanity: Broken CD,SHIPSANITY, -2914,Farm,Shipsanity: Broken Glasses,SHIPSANITY, -2915,Farm,Shipsanity: Driftwood,SHIPSANITY, -2916,Farm,Shipsanity: Joja Cola,SHIPSANITY, -2917,Farm,Shipsanity: Soggy Newspaper,SHIPSANITY, -2918,Farm,Shipsanity: Trash,SHIPSANITY, -2919,Farm,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2920,Farm,Shipsanity: Golden Egg,SHIPSANITY, -2921,Farm,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2922,Farm,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", -2923,Farm,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", -2924,Farm,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", -2925,Farm,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", -2926,Farm,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", -2927,Farm,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", -2928,Farm,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", -2929,Farm,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", -2930,Farm,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", -2931,Farm,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", -2932,Farm,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", -2933,Farm,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", -2934,Farm,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", -2935,Farm,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", -2936,Farm,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", -2937,Farm,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", -2938,Farm,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", -2939,Farm,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", -2940,Farm,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", -2941,Farm,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", -2942,Farm,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2943,Farm,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2944,Farm,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Farm,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", -2946,Farm,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2947,Farm,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Farm,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2949,Farm,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2950,Farm,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Farm,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2952,Farm,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2953,Farm,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2954,Farm,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2955,Farm,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2956,Farm,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2957,Farm,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2958,Farm,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Farm,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2960,Farm,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2961,Farm,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2962,Farm,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2963,Farm,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2964,Farm,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2965,Farm,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Farm,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", -2967,Farm,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", -2968,Farm,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", -2969,Farm,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Farm,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2971,Farm,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", -2972,Farm,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", -2973,Farm,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Shipping,Shipsanity: Anchor,SHIPSANITY, +2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, +2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, +2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, +2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, +2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, +2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, +2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, +2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Shipping,Shipsanity: Coffee,SHIPSANITY, +2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, +2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, +2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Shipping,Shipsanity: Bread,SHIPSANITY, +2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, +2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Shipping,Shipsanity: Chowder,SHIPSANITY, +2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, +2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Shipping,Shipsanity: Cookie,SHIPSANITY, +2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Shipping,Shipsanity: Escargot,SHIPSANITY, +2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, +2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, +2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, +2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, +2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, +2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, +2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, +2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Shipping,Shipsanity: Omelet,SHIPSANITY, +2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, +2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, +2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, +2518,Shipping,Shipsanity: Pizza,SHIPSANITY, +2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, +2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, +2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, +2529,Shipping,Shipsanity: Salad,SHIPSANITY, +2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, +2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, +2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, +2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, +2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, +2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, +2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, +2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, +2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, +2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Shipping,Shipsanity: Bait,SHIPSANITY, +2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Shipping,Shipsanity: Bomb,SHIPSANITY, +2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, +2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, +2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, +2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, +2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, +2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, +2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, +2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, +2569,Shipping,Shipsanity: Gate,SHIPSANITY, +2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, +2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, +2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, +2578,Shipping,Shipsanity: Magnet,SHIPSANITY, +2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, +2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, +2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Shipping,Shipsanity: Spinner,SHIPSANITY, +2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, +2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, +2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, +2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, +2598,Shipping,Shipsanity: Torch,SHIPSANITY, +2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", +2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, +2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, +2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, +2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, +2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, +2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, +2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Shipping,Shipsanity: Oil,SHIPSANITY, +2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Shipping,Shipsanity: Rice,SHIPSANITY, +2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Shipping,Shipsanity: Sugar,SHIPSANITY, +2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, +2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, +2765,Shipping,Shipsanity: Alamite,SHIPSANITY, +2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, +2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, +2769,Shipping,Shipsanity: Baryte,SHIPSANITY, +2770,Shipping,Shipsanity: Basalt,SHIPSANITY, +2771,Shipping,Shipsanity: Bixite,SHIPSANITY, +2772,Shipping,Shipsanity: Calcite,SHIPSANITY, +2773,Shipping,Shipsanity: Celestine,SHIPSANITY, +2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Shipping,Shipsanity: Diamond,SHIPSANITY, +2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, +2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Shipping,Shipsanity: Emerald,SHIPSANITY, +2780,Shipping,Shipsanity: Esperite,SHIPSANITY, +2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, +2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Shipping,Shipsanity: Geminite,SHIPSANITY, +2788,Shipping,Shipsanity: Geode,SHIPSANITY, +2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Shipping,Shipsanity: Granite,SHIPSANITY, +2792,Shipping,Shipsanity: Helvite,SHIPSANITY, +2793,Shipping,Shipsanity: Hematite,SHIPSANITY, +2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Shipping,Shipsanity: Jade,SHIPSANITY, +2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, +2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, +2799,Shipping,Shipsanity: Jasper,SHIPSANITY, +2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, +2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Shipping,Shipsanity: Limestone,SHIPSANITY, +2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, +2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, +2805,Shipping,Shipsanity: Malachite,SHIPSANITY, +2806,Shipping,Shipsanity: Marble,SHIPSANITY, +2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, +2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, +2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, +2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, +2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, +2814,Shipping,Shipsanity: Opal,SHIPSANITY, +2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, +2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, +2825,Shipping,Shipsanity: Quartz,SHIPSANITY, +2826,Shipping,Shipsanity: Ruby,SHIPSANITY, +2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, +2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Shipping,Shipsanity: Slate,SHIPSANITY, +2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, +2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, +2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, +2835,Shipping,Shipsanity: Topaz,SHIPSANITY, +2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, +2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", +2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, +2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, +2848,Shipping,Shipsanity: Hay,SHIPSANITY, +2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Shipping,Shipsanity: Pearl,SHIPSANITY, +2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, +2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Shipping,Shipsanity: White Algae,SHIPSANITY, +2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, +2858,Shipping,Shipsanity: Acorn,SHIPSANITY, +2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, +2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, +2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, +2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, +2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, +2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, +2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, +2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, +2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, +2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, +2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Shipping,Shipsanity: Trash,SHIPSANITY, +2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, +2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", +2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Shipping,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", +2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", 3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", 3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", 3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 4fe4db11db43..23a18b181115 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -438,7 +438,7 @@ class Chefsanity(Choice): internal_name = "chefsanity" display_name = "Chefsanity" default = 0 - option_vanilla = 0b000 # 0 + option_vanilla = 0b0000 # 0 option_queen_of_sauce = 0b0001 # 1 option_purchases = 0b0010 # 2 option_qos_and_purchases = 0b0011 # 3 From a97988e7e3f9419acf59b332b4240d5400030c51 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 16 Sep 2023 23:00:31 -0400 Subject: [PATCH 072/482] - Renamed cookies - Improved regions - switch skills and friendship on chefsanity --- worlds/stardew_valley/data/locations.csv | 10 +++++----- worlds/stardew_valley/options.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 44878e0ba171..1196f078db39 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1128,7 +1128,7 @@ id,region,name,tags,mod_name 2484,Shipping,Shipsanity: Chowder,SHIPSANITY, 2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, 2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Shipping,Shipsanity: Cookie,SHIPSANITY, +2487,Shipping,Shipsanity: Cookies,SHIPSANITY, 2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, 2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, 2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, @@ -1718,7 +1718,7 @@ id,region,name,tags,mod_name 3214,Kitchen,Cook Chowder,"COOKSANITY", 3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", 3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", -3217,Kitchen,Cook Cookie,"COOKSANITY", +3217,Kitchen,Cook Cookies,"COOKSANITY", 3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", 3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", 3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY", @@ -1798,7 +1798,7 @@ id,region,name,tags,mod_name 3314,Farm,Learn Recipe Chowder,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3315,The Queen of Sauce,Learn Recipe Coleslaw,"CHEFSANITY,CHEFSANITY_QOS", 3316,The Queen of Sauce,Learn Recipe Complete Breakfast,"CHEFSANITY,CHEFSANITY_QOS", -3317,Farm,Learn Recipe Cookie,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3317,Farm,Learn Recipe Cookies,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3318,The Queen of Sauce,Learn Recipe Crab Cakes,"CHEFSANITY,CHEFSANITY_QOS", 3319,The Queen of Sauce,Learn Recipe Cranberry Candy,"CHEFSANITY,CHEFSANITY_QOS", 3320,Farm,Learn Recipe Cranberry Sauce,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", @@ -1858,8 +1858,8 @@ id,region,name,tags,mod_name 3374,Farm,Learn Recipe Survival Burger,"CHEFSANITY,CHEFSANITY_SKILL", 3375,Farm,Learn Recipe Tom Kha Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3376,The Queen of Sauce,Learn Recipe Tortilla,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3377,Farm,Learn Recipe Triple Shot Espresso,"CHEFSANITY,CHEFSANITY_PURCHASE", -3378,Farm,Learn Recipe Tropical Curry,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3377,Saloon,Learn Recipe Triple Shot Espresso,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Island Resort,Learn Recipe Tropical Curry,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", 3379,The Queen of Sauce,Learn Recipe Trout Soup,"CHEFSANITY,CHEFSANITY_QOS", 3380,Farm,Learn Recipe Vegetable Medley,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 23a18b181115..3716731f15bb 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -442,8 +442,8 @@ class Chefsanity(Choice): option_queen_of_sauce = 0b0001 # 1 option_purchases = 0b0010 # 2 option_qos_and_purchases = 0b0011 # 3 - option_friendship = 0b0100 # 4 - option_skills = 0b1000 # 8 + option_skills = 0b0100 # 4 + option_friendship = 0b1000 # 8 option_all = 0b1111 # 15 From 64e86a34f2a7d61bfa2d651ba8401e44787c4ea7 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 18 Sep 2023 00:00:10 -0400 Subject: [PATCH 073/482] - Fix name for Cookies --- worlds/stardew_valley/strings/food_names.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index cc5ff6a8edad..d05a9b8515a0 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -17,7 +17,7 @@ class Meal: chowder = "Chowder" coleslaw = "Coleslaw" complete_breakfast = "Complete Breakfast" - cookie = "Cookie" + cookie = "Cookies" crab_cakes = "Crab Cakes" cranberry_candy = "Cranberry Candy" cranberry_sauce = "Cranberry Sauce" From 608c60f502837872908c6d79c14742d3c22f52de Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 20 Sep 2023 00:56:31 -0400 Subject: [PATCH 074/482] - Rebase from main --- worlds/stardew_valley/logic/logic.py | 5 +++-- worlds/stardew_valley/logic/relationship_logic.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 7f23a910e105..a2b7f2caf600 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -623,14 +623,15 @@ def has_traveling_merchant(self, tier: int = 1): def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: item_rules = [] highest_quality_yet = 0 + can_speak_junimo = self.region.can_reach(Region.wizard_tower) for bundle_item in bundle_requirements: if bundle_item.item.item_id == -1: - return self.money.can_spend(bundle_item.amount) + return can_speak_junimo & self.money.can_spend(bundle_item.amount) else: item_rules.append(bundle_item.item.name) if bundle_item.quality > highest_quality_yet: highest_quality_yet = bundle_item.quality - return self.region.can_reach(Region.wizard_tower) & self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) + return can_speak_junimo & self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) def can_grow_gold_quality(self, quality: int) -> StardewRule: if quality <= 0: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index f8a2b78a1811..f8e4688bf75b 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -102,7 +102,8 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: return self.can_earn_relationship(npc, hearts) if self.friendsanity_option == options.Friendsanity.option_starting_npcs and not villager.available: return self.can_earn_relationship(npc, hearts) - if self.friendsanity_option != options.Friendsanity.option_all_with_marriage and villager.bachelor and hearts > 8: + is_capped_at_8 = villager.bachelor and self.friendsanity_option != options.Friendsanity.option_all_with_marriage + if is_capped_at_8 and hearts > 8: return self.received_hearts(villager, 8) & self.can_earn_relationship(npc, hearts) return self.received_hearts(villager, hearts) From 0978aa459ded0827728500602b31dda13dabacdd Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 20 Sep 2023 11:53:12 -0400 Subject: [PATCH 075/482] - Chefsanity tests # Conflicts: # worlds/stardew_valley/test/TestRules.py --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/items.py | 2 +- worlds/stardew_valley/locations.py | 2 +- worlds/stardew_valley/logic/cooking_logic.py | 33 +++++- worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/options.py | 2 +- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/test/TestRules.py | 114 ++++++++++++------- 8 files changed, 106 insertions(+), 53 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 381abccd7e1f..f420aced9d1f 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -335,7 +335,7 @@ id,name,classification,groups,mod_name 353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", 355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -356,Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", 358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", 359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 00c6bab55b91..61df9dc7941b 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -536,7 +536,7 @@ def create_crafting_recipes(item_factory: StardewItemFactory, world_options: Sta def create_cooking_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): chefsanity = world_options[options.Chefsanity] - if chefsanity == options.Chefsanity.option_vanilla: + if chefsanity == options.Chefsanity.option_none: return chefsanity_recipes_by_name = {recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_STARTER]} # Dictionary to not make duplicates diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 4616649cf92b..9ad0dcbedabe 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -369,7 +369,7 @@ def extend_cooksanity_locations(randomized_locations: List[LocationData], world_ def extend_chefsanity_locations(randomized_locations: List[LocationData], world_options): chefsanity = world_options[options.Chefsanity] - if chefsanity == options.Chefsanity.option_vanilla: + if chefsanity == options.Chefsanity.option_none: return chefsanity_locations_by_name = {} # Dictionary to not make duplicates diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 32d3edc60f07..53eaa7af8439 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -21,6 +21,7 @@ class CookingLogic: player: int + chefsanity_option: int exclude_ginger_island: int received: ReceivedLogic has: HasLogic @@ -33,9 +34,10 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, exclude_ginger_island: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + def __init__(self, player: int, chefsanity_option: int, exclude_ginger_island: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player + self.chefsanity_option = chefsanity_option self.exclude_ginger_island = exclude_ginger_island self.received = received self.has = has @@ -56,17 +58,34 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: if recipe is None: return cook_rule - learn_rule = self.can_learn_recipe(recipe.source) + recipe_rule = self.knows_recipe(recipe.source, recipe.meal) ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) time_rule = self.time.has_lived_months(number_ingredients) - return cook_rule & learn_rule & ingredients_rule & time_rule + return cook_rule & recipe_rule & ingredients_rule & time_rule + + def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: + if self.chefsanity_option == options.Chefsanity.option_none: + return self.can_learn_recipe(source) + if isinstance(source, StarterSource): + return self.received_recipe(meal_name) + if isinstance(source, ShopTradeSource) and self.chefsanity_option & options.Chefsanity.option_purchases: + return self.received_recipe(meal_name) + if isinstance(source, ShopSource) and self.chefsanity_option & options.Chefsanity.option_purchases: + return self.received_recipe(meal_name) + if isinstance(source, SkillSource) and self.chefsanity_option & options.Chefsanity.option_skills: + return self.received_recipe(meal_name) + if isinstance(source, CutsceneSource) and self.chefsanity_option & options.Chefsanity.option_friendship: + return self.received_recipe(meal_name) + if isinstance(source, FriendshipSource) and self.chefsanity_option & options.Chefsanity.option_friendship: + return self.received_recipe(meal_name) + if isinstance(source, QueenOfSauceSource) and self.chefsanity_option & options.Chefsanity.option_queen_of_sauce: + return self.received_recipe(meal_name) + return self.can_learn_recipe(source) def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() - if isinstance(source, ArchipelagoSource): - return self.received(source.ap_item, len(source.ap_item)) if isinstance(source, ShopTradeSource): return self.money.can_trade_at(source.region, source.currency, source.price) if isinstance(source, ShopSource): @@ -80,9 +99,11 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, QueenOfSauceSource): year_rule = self.time.has_year_two() if source.year == 2 else self.time.has_year_three() return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule - return False_() + def received_recipe(self, meal_name: str): + return self.received(f"{meal_name} Recipe") + def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " all_recipes_to_cook = [] diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index a2b7f2caf600..0853f66e6e20 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -133,7 +133,7 @@ def __post_init__(self): self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.options[options.ExcludeGingerIsland], self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.cooking = CookingLogic(self.player, self.options[options.Chefsanity], self.options[options.ExcludeGingerIsland], self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.crafting = CraftingLogic(self.player, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, self.region, self.tool, self.skill, self.mine) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 3716731f15bb..6dfcf096f2fc 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -438,7 +438,7 @@ class Chefsanity(Choice): internal_name = "chefsanity" display_name = "Chefsanity" default = 0 - option_vanilla = 0b0000 # 0 + option_none = 0b0000 # 0 option_queen_of_sauce = 0b0001 # 1 option_purchases = 0b0010 # 2 option_qos_and_purchases = 0b0011 # 3 diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 79ad33c8d466..ba2d0c3f020e 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -730,7 +730,7 @@ def set_cooksanity_rules(all_location_names: List[str], logic: StardewLogic, mul def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): chefsanity_option = world_options[options.Chefsanity] - if chefsanity_option == options.Chefsanity.option_vanilla: + if chefsanity_option == options.Chefsanity.option_none: return chefsanity_prefix = "Learn Recipe " diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index eecb53ddd5ce..b55e8a745678 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -353,52 +353,84 @@ def test_has_rules(self): self.assertFalse(self.world.logic.region.can_reach_location(location)(self.multiworld.state)) -class TestRecipeLogic(SVTestBase): +class TestRecipeLearnLogic(SVTestBase): options = { options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, - options.SkillProgression.internal_name: options.SkillProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_enabled, + options.Cooksanity.internal_name: options.Cooksanity.option_all, + options.Chefsanity.internal_name: options.Chefsanity.option_none, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, } - # I wanted to make a test for different ways to obtain a pizza, but I'm stuck not knowing how to block the immediate purchase from Gus - # def test_pizza(self): - # world = self.world - # logic = world.logic - # multiworld = self.multiworld - # - # self.assertTrue(logic.has(Ingredient.wheat_flour)(multiworld.state)) - # self.assertTrue(logic.can_spend_money_at(Region.saloon, 150)(multiworld.state)) - # self.assertFalse(logic.has(Meal.pizza)(multiworld.state)) - # - # self.assertFalse(logic.can_cook()(multiworld.state)) - # self.collect(world.create_item("Progressive House")) - # self.assertTrue(logic.can_cook()(multiworld.state)) - # self.assertFalse(logic.has(Meal.pizza)(multiworld.state)) - # - # self.assertFalse(logic.has(Seed.tomato)(multiworld.state)) - # self.collect(world.create_item(Seed.tomato)) - # self.assertTrue(logic.has(Seed.tomato)(multiworld.state)) - # self.assertFalse(logic.has(Meal.pizza)(multiworld.state)) - # - # self.assertFalse(logic.has(Vegetable.tomato)(multiworld.state)) - # self.collect(world.create_item(Season.summer)) - # self.assertTrue(logic.has(Vegetable.tomato)(multiworld.state)) - # self.assertFalse(logic.has(Meal.pizza)(multiworld.state)) - # - # self.assertFalse(logic.has(Animal.cow)(multiworld.state)) - # self.assertFalse(logic.has(AnimalProduct.cow_milk)(multiworld.state)) - # self.collect(world.create_item("Progressive Barn")) - # self.assertTrue(logic.has(Animal.cow)(multiworld.state)) - # self.assertTrue(logic.has(AnimalProduct.cow_milk)(multiworld.state)) - # self.assertFalse(logic.has(Meal.pizza)(multiworld.state)) - # - # self.assertFalse(logic.has(Machine.cheese_press)(self.multiworld.state)) - # self.assertFalse(logic.has(ArtisanGood.cheese)(self.multiworld.state)) - # self.collect(world.create_item(item) for item in ["Farming Level"] * 6) - # self.collect(world.create_item(item) for item in ["Progressive Axe"] * 2) - # self.assertTrue(logic.has(Machine.cheese_press)(self.multiworld.state)) - # self.assertTrue(logic.has(ArtisanGood.cheese)(self.multiworld.state)) - # self.assertTrue(logic.has(Meal.pizza)(self.multiworld.state)) + def test_can_learn_qos_recipe(self): + location = "Cook Radish Salad" + rule = self.world.logic.region.can_reach_location(location) + self.assertFalse(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([self.world.create_item("Month End")] * 10) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("The Queen of Sauce"), event=False) + self.assertTrue(rule(self.multiworld.state)) + + +class TestRecipeReceiveLogic(SVTestBase): + options = { + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.Cooksanity.internal_name: options.Cooksanity.option_all, + options.Chefsanity.internal_name: options.Chefsanity.option_all, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + } + + def test_can_learn_qos_recipe(self): + location = "Cook Radish Salad" + rule = self.world.logic.region.can_reach_location(location) + self.assertFalse(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([self.world.create_item("Month End")] * 10) + self.assertFalse(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.assertFalse(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.assertTrue(rule(self.multiworld.state)) + + def test_get_chefsanity_check_recipe(self): + location = "Learn Recipe Radish Salad" + rule = self.world.logic.region.can_reach_location(location) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Spring"), event=False) + self.collect([self.world.create_item("Month End")] * 10) + self.assertFalse(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.assertFalse(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.assertTrue(rule(self.multiworld.state)) class TestDonationLogicAll(SVTestBase): From 5a72668c439558e54de5c8f851847f457dd93b0a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 25 Sep 2023 23:15:17 -0400 Subject: [PATCH 076/482] - Added craftsanity --- worlds/stardew_valley/data/common_data.py | 3 - worlds/stardew_valley/data/craftable_data.py | 21 +- worlds/stardew_valley/data/items.csv | 60 ++++- worlds/stardew_valley/data/locations.csv | 244 ++++++++++++++---- worlds/stardew_valley/data/museum_data.py | 66 ++--- worlds/stardew_valley/data/recipe_source.py | 11 + worlds/stardew_valley/items.py | 25 +- worlds/stardew_valley/locations.py | 13 + worlds/stardew_valley/logic/combat_logic.py | 18 +- worlds/stardew_valley/logic/crafting_logic.py | 66 +++-- worlds/stardew_valley/logic/fishing_logic.py | 2 +- worlds/stardew_valley/logic/logic.py | 71 ++--- worlds/stardew_valley/logic/mine_logic.py | 1 + worlds/stardew_valley/logic/monster_logic.py | 28 +- .../logic/special_order_logic.py | 2 +- worlds/stardew_valley/options.py | 13 + worlds/stardew_valley/regions.py | 3 +- worlds/stardew_valley/rules.py | 36 ++- .../stardew_valley/strings/entrance_names.py | 1 + .../strings/special_order_names.py | 2 +- worlds/stardew_valley/test/TestGeneration.py | 2 + worlds/stardew_valley/test/TestRules.py | 49 ++++ worlds/stardew_valley/test/mods/TestMods.py | 2 + 23 files changed, 543 insertions(+), 196 deletions(-) diff --git a/worlds/stardew_valley/data/common_data.py b/worlds/stardew_valley/data/common_data.py index 8a2d0f5eecfc..ad34b1ba59e7 100644 --- a/worlds/stardew_valley/data/common_data.py +++ b/worlds/stardew_valley/data/common_data.py @@ -1,6 +1,3 @@ -fishing_chest = "Fishing Chest" -secret_note = "Secret Note" - quality_dict = { 0: "", 1: "Silver", diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 5b1471890d31..f88c6ac8d040 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -1,7 +1,7 @@ from typing import Dict, List from .recipe_source import RecipeSource, StarterSource, QueenOfSauceSource, ShopSource, SkillSource, FriendshipSource, ShopTradeSource, CutsceneSource, \ - ArchipelagoSource, LogicSource + ArchipelagoSource, LogicSource, SpecialOrderSource from ..strings.artisan_good_names import ArtisanGood from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, Fishing, Ring, Consumable, Edible, Lighting, Storage, Furniture, Sign, Craftable from ..strings.crop_names import Fruit, Vegetable @@ -18,6 +18,7 @@ from ..strings.region_names import Region from ..strings.seed_names import Seed, TreeSeed from ..strings.skill_names import Skill +from ..strings.special_order_names import SpecialOrder from ..strings.villager_names import NPC @@ -69,6 +70,11 @@ def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredien return create_recipe(name, ingredients, source) +def special_order_recipe(name: str, special_order: str, ingredients: Dict[str, int]) -> CraftingRecipe: + source = SpecialOrderSource(special_order) + return create_recipe(name, ingredients, source) + + def starter_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe: source = StarterSource() return create_recipe(name, ingredients, source) @@ -134,7 +140,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) grass_starter = shop_recipe(WildSeeds.grass_starter, Region.pierre_store, 1000, {Material.fiber: 10}) for wild_seeds in [WildSeeds.spring, WildSeeds.summer, WildSeeds.fall, WildSeeds.winter]: tea_sapling = cutscene_recipe(WildSeeds.tea_sapling, Region.sunroom, NPC.caroline, 2, {wild_seeds: 2, Material.fiber: 5, Material.wood: 5}) -fiber_seeds = ap_recipe(WildSeeds.fiber, {Seed.mixed: 1, Material.sap: 5, Material.clay: 1}) +fiber_seeds = special_order_recipe(WildSeeds.fiber, SpecialOrder.community_cleanup, {Seed.mixed: 1, Material.sap: 5, Material.clay: 1}) wood_floor = shop_recipe(Floor.wood, Region.carpenter, 100, {Material.wood: 1}) rustic_floor = shop_recipe(Floor.rustic, Region.carpenter, 200, {Material.wood: 1}) @@ -153,7 +159,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) spinner = skill_recipe(Fishing.spinner, Skill.fishing, 6, {MetalBar.iron: 2}) trap_bobber = skill_recipe(Fishing.trap_bobber, Skill.fishing, 6, {MetalBar.copper: 1, Material.sap: 10}) cork_bobber = skill_recipe(Fishing.cork_bobber, Skill.fishing, 7, {Material.wood: 10, Material.hardwood: 5, Loot.slime: 10}) -quality_bobber = ap_recipe(Fishing.quality_bobber, {MetalBar.copper: 1, Material.sap: 20, Loot.solar_essence: 5}) +quality_bobber = special_order_recipe(Fishing.quality_bobber, SpecialOrder.juicy_bugs_wanted, {MetalBar.copper: 1, Material.sap: 20, Loot.solar_essence: 5}) treasure_hunter = skill_recipe(Fishing.treasure_hunter, Skill.fishing, 7, {MetalBar.gold: 2}) dressed_spinner = skill_recipe(Fishing.dressed_spinner, Skill.fishing, 8, {MetalBar.iron: 2, ArtisanGood.cloth: 1}) barbed_hook = skill_recipe(Fishing.barbed_hook, Skill.fishing, 8, {MetalBar.copper: 1, MetalBar.iron: 1, MetalBar.gold: 1}) @@ -197,7 +203,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) marble_brazier = shop_recipe(Lighting.marble_brazier, Region.carpenter, 5000, {Mineral.marble: 1, Mineral.aquamarine: 1, Material.stone: 100}) wood_lamp_post = shop_recipe(Lighting.wood_lamp_post, Region.carpenter, 500, {Material.wood: 50, ArtisanGood.battery_pack: 1}) iron_lamp_post = shop_recipe(Lighting.iron_lamp_post, Region.carpenter, 1000, {MetalBar.iron: 1, ArtisanGood.battery_pack: 1}) -jack_o_lantern = ap_recipe(Lighting.jack_o_lantern, {Vegetable.pumpkin: 1, Lighting.torch: 1}) +jack_o_lantern = shop_recipe(Lighting.jack_o_lantern, Region.spirit_eve, 2000, {Vegetable.pumpkin: 1, Lighting.torch: 1}) bone_mill = ap_recipe(Machine.bone_mill, {Fossil.bone_fragment: 10, Material.clay: 3, Material.stone: 20}) charcoal_kiln = skill_recipe(Machine.charcoal_kiln, Skill.foraging, 4, {Material.wood: 20, MetalBar.copper: 2}) @@ -215,7 +221,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) tapper = skill_recipe(Machine.tapper, Skill.foraging, 3, {Material.wood: 40, MetalBar.copper: 2}) worm_bin = skill_recipe(Machine.worm_bin, Skill.fishing, 8, {Material.hardwood: 25, MetalBar.gold: 1, MetalBar.iron: 1, Material.fiber: 50}) -tub_o_flowers = ap_recipe(Furniture.tub_o_flowers, {Material.wood: 15, Seed.tulip: 1, Seed.jazz: 1, Seed.poppy: 1, Seed.spangle: 1}) +tub_o_flowers = shop_recipe(Furniture.tub_o_flowers, Region.flower_dance, 2000, {Material.wood: 15, Seed.tulip: 1, Seed.jazz: 1, Seed.poppy: 1, Seed.spangle: 1}) wicked_statue = shop_recipe(Furniture.wicked_statue, Region.sewer, 1000, {Material.stone: 25, Material.coal: 5}) flute_block = cutscene_recipe(Furniture.flute_block, Region.carpenter, NPC.robin, 6, {Material.wood: 10, Ore.copper: 2, Material.fiber: 20}) drum_block = cutscene_recipe(Furniture.drum_block, Region.carpenter, NPC.robin, 6, {Material.stone: 10, Ore.copper: 2, Material.fiber: 20}) @@ -238,4 +244,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) mini_obelisk = ap_recipe(Craftable.mini_obelisk, {Material.hardwood: 30, Loot.solar_essence: 20, MetalBar.gold: 3}) farm_computer = ap_recipe(Craftable.farm_computer, {Artifact.dwarf_gadget: 1, ArtisanGood.battery_pack: 1, MetalBar.quartz: 10}) hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1}) -cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 9, {Material.wood: 15, Material.fiber: 10, Material.coal: 3}) \ No newline at end of file +cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 9, {Material.wood: 15, Material.fiber: 10, Material.coal: 3}) + + +all_crafting_recipes_by_name = {recipe.item: recipe for recipe in all_crafting_recipes} diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index f420aced9d1f..f3bfea0a4ff6 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -79,7 +79,7 @@ id,name,classification,groups,mod_name 93,Shipping Bin,progression,BUILDING, 94,Beach Bridge,progression,, 95,Adventurer's Guild,progression,, -96,Club Card,useful,, +96,Club Card,progression,, 97,Magnifying Glass,progression,, 98,Bear's Knowledge,useful,, 99,Iridium Snake Milk,useful,, @@ -307,17 +307,16 @@ id,name,classification,groups,mod_name 322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" 324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -325,Fairy Dust Recipe,progression,"CRAFTING_RECIPE", -326,Heavy Tapper Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", -327,Hyper Speed-Gro Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", -328,Deluxe Fertilizer Recipe,progression,"CRAFTING_RECIPE", -329,Hopper Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", -330,Magic Bait Recipe,progression,"CRAFTING_RECIPE,GINGER_ISLAND", -331,Jack-O-Lantern Recipe,progression,"CRAFTING_RECIPE", -332,Fiber Seeds Recipe,progression,"CRAFTING_RECIPE", -333,Tub o' Flowers Recipe,progression,"CRAFTING_RECIPE", -334,Fiber Seeds Recipe,progression,"CRAFTING_RECIPE", -335,Quality Bobber Recipe,progression,"CRAFTING_RECIPE", +325,Fairy Dust Recipe,progression,, +326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +328,Deluxe Fertilizer Recipe,progression,"QI_CRAFTING_RECIPE", +329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +331,Jack-O-Lantern Recipe,progression,"FESTIVAL", +332,Fiber Seeds Recipe,progression,"SPECIAL_ORDER_BOARD", +333,Tub o' Flowers Recipe,progression,"FESTIVAL", +334,Quality Bobber Recipe,progression,"SPECIAL_ORDER_BOARD", 337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", @@ -399,6 +398,43 @@ id,name,classification,groups,mod_name 417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", 418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", 419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +425,Gate Recipe,progression,"CRAFTSANITY", +426,Wood Fence Recipe,progression,"CRAFTSANITY", +427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY", +428,Grass Starter Recipe,progression,"CRAFTSANITY", +429,Wood Floor Recipe,progression,"CRAFTSANITY", +430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", +431,Straw Floor Recipe,progression,"CRAFTSANITY", +432,Weathered Floor Recipe,progression,"CRAFTSANITY", +433,Crystal Floor Recipe,progression,"CRAFTSANITY", +434,Stone Floor Recipe,progression,"CRAFTSANITY", +435,Stone Walkway Floor Recipe,progression,"CRAFTSANITY", +436,Brick Floor Recipe,progression,"CRAFTSANITY", +437,Wood Path Recipe,progression,"CRAFTSANITY", +438,Gravel Path Recipe,progression,"CRAFTSANITY", +439,Cobblestone Path Recipe,progression,"CRAFTSANITY", +440,Stepping Stone Path Recipe,progression,"CRAFTSANITY", +441,Crystal Path Recipe,progression,"CRAFTSANITY", +442,Wedding Ring Recipe,progression,"CRAFTSANITY", +443,Warp Totem: Desert Recipe,progression,"CRAFTSANITY", +444,Warp Totem: Island Recipe,progression,"CRAFTSANITY", +445,Torch Recipe,progression,"CRAFTSANITY", +446,Campfire Recipe,progression,"CRAFTSANITY", +447,Wooden Brazier Recipe,progression,"CRAFTSANITY", +448,Stone Brazier Recipe,progression,"CRAFTSANITY", +449,Gold Brazier Recipe,progression,"CRAFTSANITY", +450,Carved Brazier Recipe,progression,"CRAFTSANITY", +451,Stump Brazier Recipe,progression,"CRAFTSANITY", +452,Barrel Brazier Recipe,progression,"CRAFTSANITY", +453,Skull Brazier Recipe,progression,"CRAFTSANITY", +454,Marble Brazier Recipe,progression,"CRAFTSANITY", +455,Wood Lamp-post Recipe,progression,"CRAFTSANITY", +456,Iron Lamp-post Recipe,progression,"CRAFTSANITY", +457,Furnace Recipe,progression,"CRAFTSANITY", +458,Wicked Statue Recipe,progression,"CRAFTSANITY", +459,Chest Recipe,progression,"CRAFTSANITY", +460,Wood Sign Recipe,progression,"CRAFTSANITY", +461,Stone Sign Recipe,progression,"CRAFTSANITY", 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 1196f078db39..a95795afc29e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -906,50 +906,50 @@ id,region,name,tags,mod_name 1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, 1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, 1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, -1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, -1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, -1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, -1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, -1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, -1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, -1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, -1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, -1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, -1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, -1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, -1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, -1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, -1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, -2001,Egg Festival,Egg Hunt Victory,FESTIVAL, -2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, -2003,Flower Dance,Dance with someone,FESTIVAL, -2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, -2005,Luau,Luau Soup,FESTIVAL, -2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, -2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, -2008,Stardew Valley Fair,Grange Display,FESTIVAL, -2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, -2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, -2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, -2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, -2013,Festival of Ice,Win Fishing Competition,FESTIVAL, -2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, -2015,Night Market,Mermaid Pearl,FESTIVAL, -2016,Night Market,Cone Hat,FESTIVAL_HARD, -2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, -2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, -2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, -2020,Night Market,Lupini: Red Eagle,FESTIVAL, -2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, -2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, -2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, -2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, -2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, -2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, -2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, -2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, -2029,Feast of the Winter Star,Secret Santa,FESTIVAL, -2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, +1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, +1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, +1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, +1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, +1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, +1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, +1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, +1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, +1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, +1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, +1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, +1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, +1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, +1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, +2001,Egg Festival,Egg Hunt Victory,FESTIVAL, +2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, +2003,Flower Dance,Dance with someone,FESTIVAL, +2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, +2005,Luau,Luau Soup,FESTIVAL, +2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, +2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, +2008,Stardew Valley Fair,Grange Display,FESTIVAL, +2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, +2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, +2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, +2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, +2013,Festival of Ice,Win Fishing Competition,FESTIVAL, +2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, +2015,Night Market,Mermaid Pearl,FESTIVAL, +2016,Night Market,Cone Hat,FESTIVAL_HARD, +2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, +2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, +2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, +2020,Night Market,Lupini: Red Eagle,FESTIVAL, +2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, +2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, +2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, +2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, +2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, +2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, +2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, +2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, +2029,Feast of the Winter Star,Secret Santa,FESTIVAL, +2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, 2031,Farm,Collect All Rarecrows,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, @@ -1248,7 +1248,7 @@ id,region,name,tags,mod_name 2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, 2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", 2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, +2607,Shipping,Shipsanity: Weathered Floor,"SHIPSANITY", 2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, 2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, 2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, @@ -1862,6 +1862,160 @@ id,region,name,tags,mod_name 3378,Island Resort,Learn Recipe Tropical Curry,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", 3379,The Queen of Sauce,Learn Recipe Trout Soup,"CHEFSANITY,CHEFSANITY_QOS", 3380,Farm,Learn Recipe Vegetable Medley,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3401,Farm,Craft Cherry Bomb,"CRAFTSANITY", +3402,Farm,Craft Bomb,"CRAFTSANITY", +3403,Farm,Craft Mega Bomb,"CRAFTSANITY", +3404,Farm,Craft Gate,"CRAFTSANITY", +3405,Farm,Craft Wood Fence,"CRAFTSANITY", +3406,Farm,Craft Stone Fence,"CRAFTSANITY", +3407,Farm,Craft Iron Fence,"CRAFTSANITY", +3408,Farm,Craft Hardwood Fence,"CRAFTSANITY", +3409,Farm,Craft Sprinkler,"CRAFTSANITY", +3410,Farm,Craft Quality Sprinkler,"CRAFTSANITY", +3411,Farm,Craft Iridium Sprinkler,"CRAFTSANITY", +3412,Farm,Craft Bee House,"CRAFTSANITY", +3413,Farm,Craft Cask,"CRAFTSANITY", +3414,Farm,Craft Cheese Press,"CRAFTSANITY", +3415,Farm,Craft Keg,"CRAFTSANITY", +3416,Farm,Craft Loom,"CRAFTSANITY", +3417,Farm,Craft Mayonnaise Machine,"CRAFTSANITY", +3418,Farm,Craft Oil Maker,"CRAFTSANITY", +3419,Farm,Craft Preserves Jar,"CRAFTSANITY", +3420,Farm,Craft Basic Fertilizer,"CRAFTSANITY", +3421,Farm,Craft Quality Fertilizer,"CRAFTSANITY", +3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY", +3423,Farm,Craft Speed-Gro,"CRAFTSANITY", +3424,Farm,Craft Deluxe Speed-Gro,"CRAFTSANITY", +3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", +3426,Farm,Craft Basic Retaining Soil,"CRAFTSANITY", +3427,Farm,Craft Quality Retaining Soil,"CRAFTSANITY", +3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY", +3429,Farm,Craft Tree Fertilizer,"CRAFTSANITY", +3430,Farm,Craft Spring Seeds,"CRAFTSANITY", +3431,Farm,Craft Summer Seeds,"CRAFTSANITY", +3432,Farm,Craft Fall Seeds,"CRAFTSANITY", +3433,Farm,Craft Winter Seeds,"CRAFTSANITY", +3434,Farm,Craft Ancient Seeds,"CRAFTSANITY", +3435,Farm,Craft Grass Starter,"CRAFTSANITY", +3436,Farm,Craft Tea Sapling,"CRAFTSANITY", +3437,Farm,Craft Fiber Seeds,"CRAFTSANITY", +3438,Farm,Craft Wood Floor,"CRAFTSANITY", +3439,Farm,Craft Rustic Plank Floor,"CRAFTSANITY", +3440,Farm,Craft Straw Floor,"CRAFTSANITY", +3441,Farm,Craft Weathered Floor,"CRAFTSANITY", +3442,Farm,Craft Crystal Floor,"CRAFTSANITY", +3443,Farm,Craft Stone Floor,"CRAFTSANITY", +3444,Farm,Craft Stone Walkway Floor,"CRAFTSANITY", +3445,Farm,Craft Brick Floor,"CRAFTSANITY", +3446,Farm,Craft Wood Path,"CRAFTSANITY", +3447,Farm,Craft Gravel Path,"CRAFTSANITY", +3448,Farm,Craft Cobblestone Path,"CRAFTSANITY", +3449,Farm,Craft Stepping Stone Path,"CRAFTSANITY", +3450,Farm,Craft Crystal Path,"CRAFTSANITY", +3451,Farm,Craft Spinner,"CRAFTSANITY", +3452,Farm,Craft Trap Bobber,"CRAFTSANITY", +3453,Farm,Craft Cork Bobber,"CRAFTSANITY", +3454,Farm,Craft Quality Bobber,"CRAFTSANITY", +3455,Farm,Craft Treasure Hunter,"CRAFTSANITY", +3456,Farm,Craft Dressed Spinner,"CRAFTSANITY", +3457,Farm,Craft Barbed Hook,"CRAFTSANITY", +3458,Farm,Craft Magnet,"CRAFTSANITY", +3459,Farm,Craft Bait,"CRAFTSANITY", +3460,Farm,Craft Wild Bait,"CRAFTSANITY", +3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", +3462,Farm,Craft Crab Pot,"CRAFTSANITY", +3463,Farm,Craft Sturdy Ring,"CRAFTSANITY", +3464,Farm,Craft Warrior Ring,"CRAFTSANITY", +3465,Farm,Craft Ring of Yoba,"CRAFTSANITY", +3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", +3467,Farm,Craft Glowstone Ring,"CRAFTSANITY", +3468,Farm,Craft Iridium Band,"CRAFTSANITY", +3469,Farm,Craft Wedding Ring,"CRAFTSANITY", +3470,Farm,Craft Field Snack,"CRAFTSANITY", +3471,Farm,Craft Bug Steak,"CRAFTSANITY", +3472,Farm,Craft Life Elixir,"CRAFTSANITY", +3473,Farm,Craft Oil of Garlic,"CRAFTSANITY", +3474,Farm,Craft Monster Musk,"CRAFTSANITY", +3475,Farm,Craft Fairy Dust,"CRAFTSANITY", +3476,Farm,Craft Warp Totem: Beach,"CRAFTSANITY", +3477,Farm,Craft Warp Totem: Mountains,"CRAFTSANITY", +3478,Farm,Craft Warp Totem: Farm,"CRAFTSANITY", +3479,Farm,Craft Warp Totem: Desert,"CRAFTSANITY", +3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", +3481,Farm,Craft Rain Totem,"CRAFTSANITY", +3482,Farm,Craft Torch,"CRAFTSANITY", +3483,Farm,Craft Campfire,"CRAFTSANITY", +3484,Farm,Craft Wooden Brazier,"CRAFTSANITY", +3485,Farm,Craft Stone Brazier,"CRAFTSANITY", +3486,Farm,Craft Gold Brazier,"CRAFTSANITY", +3487,Farm,Craft Carved Brazier,"CRAFTSANITY", +3488,Farm,Craft Stump Brazier,"CRAFTSANITY", +3489,Farm,Craft Barrel Brazier,"CRAFTSANITY", +3490,Farm,Craft Skull Brazier,"CRAFTSANITY", +3491,Farm,Craft Marble Brazier,"CRAFTSANITY", +3492,Farm,Craft Wood Lamp-post,"CRAFTSANITY", +3493,Farm,Craft Iron Lamp-post,"CRAFTSANITY", +3494,Farm,Craft Jack-O-Lantern,"CRAFTSANITY", +3495,Farm,Craft Bone Mill,"CRAFTSANITY", +3496,Farm,Craft Charcoal Kiln,"CRAFTSANITY", +3497,Farm,Craft Crystalarium,"CRAFTSANITY", +3498,Farm,Craft Furnace,"CRAFTSANITY", +3499,Farm,Craft Geode Crusher,"CRAFTSANITY", +3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", +3501,Farm,Craft Lightning Rod,"CRAFTSANITY", +3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", +3503,Farm,Craft Recycling Machine,"CRAFTSANITY", +3504,Farm,Craft Seed Maker,"CRAFTSANITY", +3505,Farm,Craft Slime Egg-Press,"CRAFTSANITY", +3506,Farm,Craft Slime Incubator,"CRAFTSANITY", +3507,Farm,Craft Solar Panel,"CRAFTSANITY", +3508,Farm,Craft Tapper,"CRAFTSANITY", +3509,Farm,Craft Worm Bin,"CRAFTSANITY", +3510,Farm,Craft Tub o' Flowers,"CRAFTSANITY", +3511,Farm,Craft Wicked Statue,"CRAFTSANITY", +3512,Farm,Craft Flute Block,"CRAFTSANITY", +3513,Farm,Craft Drum Block,"CRAFTSANITY", +3514,Farm,Craft Chest,"CRAFTSANITY", +3515,Farm,Craft Stone Chest,"CRAFTSANITY", +3516,Farm,Craft Wood Sign,"CRAFTSANITY", +3517,Farm,Craft Stone Sign,"CRAFTSANITY", +3518,Farm,Craft Dark Sign,"CRAFTSANITY", +3519,Farm,Craft Garden Pot,"CRAFTSANITY", +3520,Farm,Craft Scarecrow,"CRAFTSANITY", +3521,Farm,Craft Deluxe Scarecrow,"CRAFTSANITY", +3522,Farm,Craft Staircase,"CRAFTSANITY", +3523,Farm,Craft Explosive Ammo,"CRAFTSANITY", +3524,Farm,Craft Transmute (Fe),"CRAFTSANITY", +3525,Farm,Craft Transmute (Au),"CRAFTSANITY", +3526,Farm,Craft Mini-Jukebox,"CRAFTSANITY", +3527,Farm,Craft Mini-Obelisk,"CRAFTSANITY", +3528,Farm,Craft Farm Computer,"CRAFTSANITY", +3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", +3530,Farm,Craft Cookout Kit,"CRAFTSANITY", +3551,Farm,Grass Starter Recipe,"CRAFTSANITY", +3552,Farm,Wood Floor Recipe,"CRAFTSANITY", +3553,Farm,Rustic Plank Floor Recipe,"CRAFTSANITY", +3554,Farm,Straw Floor Recipe,"CRAFTSANITY", +3555,Farm,Weathered Floor Recipe,"CRAFTSANITY", +3556,Farm,Crystal Floor Recipe,"CRAFTSANITY", +3557,Farm,Stone Floor Recipe,"CRAFTSANITY", +3558,Farm,Stone Walkway Floor Recipe,"CRAFTSANITY", +3559,Farm,Brick Floor Recipe,"CRAFTSANITY", +3560,Farm,Stepping Stone Path Recipe,"CRAFTSANITY", +3561,Farm,Crystal Path Recipe,"CRAFTSANITY", +3562,Farm,Wedding Ring Recipe,"CRAFTSANITY", +3563,Farm,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", +3564,Farm,Wooden Brazier Recipe,"CRAFTSANITY", +3565,Farm,Stone Brazier Recipe,"CRAFTSANITY", +3566,Farm,Gold Brazier Recipe,"CRAFTSANITY", +3567,Farm,Carved Brazier Recipe,"CRAFTSANITY", +3568,Farm,Stump Brazier Recipe,"CRAFTSANITY", +3569,Farm,Barrel Brazier Recipe,"CRAFTSANITY", +3570,Farm,Skull Brazier Recipe,"CRAFTSANITY", +3571,Farm,Marble Brazier Recipe,"CRAFTSANITY", +3572,Farm,Wood Lamp-post Recipe,"CRAFTSANITY", +3573,Farm,Iron Lamp-post Recipe,"CRAFTSANITY", +3574,Farm,Wicked Statue Recipe,"CRAFTSANITY,REQUIRES_MUSEUM", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index 82d8ed75e27b..cec0cd289724 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -6,6 +6,8 @@ from . import common_data as common from .game_item import GameItem from worlds.stardew_valley.strings.monster_names import Monster +from ..strings.fish_names import WaterChest +from ..strings.forageable_names import Forageable from ..strings.region_names import Region from ..strings.geode_names import Geode @@ -97,41 +99,41 @@ class Artifact: arrowhead = create_artifact("Arrowhead", 101, 8.5, (Region.mountain, Region.forest, Region.bus_stop), geodes=Geode.artifact_trove) ancient_doll = create_artifact("Ancient Doll", 103, 13.1, (Region.mountain, Region.forest, Region.bus_stop), - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) elvish_jewelry = create_artifact("Elvish Jewelry", 104, 5.3, Region.forest, - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) chewing_stick = create_artifact("Chewing Stick", 105, 10.3, (Region.mountain, Region.forest, Region.town), - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) ornamental_fan = create_artifact("Ornamental Fan", 106, 7.4, (Region.beach, Region.forest, Region.town), - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) dinosaur_egg = create_artifact("Dinosaur Egg", 107, 11.4, (Region.mountain, Region.skull_cavern), - geodes=common.fishing_chest, + geodes=WaterChest.fishing_chest, monsters=Monster.pepper_rex) rare_disc = create_artifact("Rare Disc", 108, 5.6, Region.stardew_valley, - geodes=(Geode.artifact_trove, common.fishing_chest), + geodes=(Geode.artifact_trove, WaterChest.fishing_chest), monsters=unlikely) ancient_sword = create_artifact("Ancient Sword", 109, 5.8, (Region.forest, Region.mountain), - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) rusty_spoon = create_artifact("Rusty Spoon", 110, 9.6, Region.town, - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) rusty_spur = create_artifact("Rusty Spur", 111, 15.6, Region.farm, - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) rusty_cog = create_artifact("Rusty Cog", 112, 9.6, Region.mountain, - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) chicken_statue = create_artifact("Chicken Statue", 113, 13.5, Region.farm, - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) ancient_seed = create_artifact("Ancient Seed", 114, 8.4, (Region.forest, Region.mountain), - geodes=(Geode.artifact_trove, common.fishing_chest), + geodes=(Geode.artifact_trove, WaterChest.fishing_chest), monsters=unlikely) prehistoric_tool = create_artifact("Prehistoric Tool", 115, 11.1, (Region.mountain, Region.forest, Region.bus_stop), - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) dried_starfish = create_artifact("Dried Starfish", 116, 12.5, Region.beach, - geodes=(Geode.artifact_trove, common.fishing_chest)) - anchor = create_artifact("Anchor", 117, 8.5, Region.beach, geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) + anchor = create_artifact("Anchor", 117, 8.5, Region.beach, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) glass_shards = create_artifact("Glass Shards", 118, 11.5, Region.beach, - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) bone_flute = create_artifact("Bone Flute", 119, 6.3, (Region.mountain, Region.forest, Region.town), - geodes=(Geode.artifact_trove, common.fishing_chest)) + geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) prehistoric_handaxe = create_artifact("Prehistoric Handaxe", 120, 13.7, (Region.mountain, Region.forest, Region.bus_stop), geodes=Geode.artifact_trove) @@ -146,9 +148,9 @@ class Artifact: golden_relic = create_artifact("Golden Relic", 125, 9.7, Region.desert, geodes=Geode.artifact_trove) strange_doll_green = create_artifact("Strange Doll (Green)", 126, 10, Region.town, - geodes=common.secret_note) + geodes=Forageable.secret_note) strange_doll = create_artifact("Strange Doll", 127, 10, Region.desert, - geodes=common.secret_note) + geodes=Forageable.secret_note) prehistoric_scapula = create_artifact("Prehistoric Scapula", 579, 6.2, (Region.dig_site, Region.forest, Region.town)) prehistoric_tibia = create_artifact("Prehistoric Tibia", 580, 16.6, @@ -160,11 +162,11 @@ class Artifact: prehistoric_vertebra = create_artifact("Prehistoric Vertebra", 584, 12.7, (Region.dig_site, Region.bus_stop), monsters=Monster.pepper_rex) skeletal_tail = create_artifact("Skeletal Tail", 585, 5.1, (Region.dig_site, Region.mines_floor_20), - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) nautilus_fossil = create_artifact("Nautilus Fossil", 586, 6.9, (Region.dig_site, Region.beach), - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) amphibian_fossil = create_artifact("Amphibian Fossil", 587, 6.3, (Region.dig_site, Region.forest, Region.mountain), - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) palm_fossil = create_artifact("Palm Fossil", 588, 10.2, (Region.dig_site, Region.desert, Region.forest, Region.beach)) trilobite = create_artifact("Trilobite", 589, 7.4, (Region.dig_site, Region.desert, Region.forest, Region.beach)) @@ -173,30 +175,30 @@ class Artifact: class Mineral: quartz = create_mineral("Quartz", 80, Region.mines_floor_20) fire_quartz = create_mineral("Fire Quartz", 82, Region.mines_floor_100, - geodes=(Geode.magma, Geode.omni, common.fishing_chest), + geodes=(Geode.magma, Geode.omni, WaterChest.fishing_chest), difficulty=1.0 / 12.0) frozen_tear = create_mineral("Frozen Tear", 84, Region.mines_floor_60, - geodes=(Geode.frozen, Geode.omni, common.fishing_chest), + geodes=(Geode.frozen, Geode.omni, WaterChest.fishing_chest), monsters=unlikely, difficulty=1.0 / 12.0) earth_crystal = create_mineral("Earth Crystal", 86, Region.mines_floor_20, - geodes=(Geode.geode, Geode.omni, common.fishing_chest), + geodes=(Geode.geode, Geode.omni, WaterChest.fishing_chest), monsters=Monster.duggy, difficulty=1.0 / 12.0) emerald = create_mineral("Emerald", 60, Region.mines_floor_100, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) aquamarine = create_mineral("Aquamarine", 62, Region.mines_floor_60, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) ruby = create_mineral("Ruby", 64, Region.mines_floor_100, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) amethyst = create_mineral("Amethyst", 66, Region.mines_floor_20, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) topaz = create_mineral("Topaz", 68, Region.mines_floor_20, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) jade = create_mineral("Jade", 70, Region.mines_floor_60, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) diamond = create_mineral("Diamond", 72, Region.mines_floor_60, - geodes=common.fishing_chest) + geodes=WaterChest.fishing_chest) prismatic_shard = create_mineral("Prismatic Shard", 74, Region.skull_cavern_100, geodes=unlikely, monsters=unlikely) diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index aa307b42569a..f2b1e6837970 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -106,3 +106,14 @@ def __init__(self, region: str, currency: str, price: int): def __repr__(self): return f"ShopTradeSource at {self.region} costing {self.price} {self.currency}" + + +class SpecialOrderSource(RecipeSource): + special_order: str + + def __init__(self, special_order: str): + self.special_order = special_order + + + def __repr__(self): + return f"SpecialOrderSource from {special_order}" diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 61df9dc7941b..31e276bcab9d 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -66,13 +66,15 @@ class Group(enum.Enum): GINGER_ISLAND = enum.auto() WALNUT_PURCHASE = enum.auto() TV_CHANNEL = enum.auto() - CRAFTING_RECIPE = enum.auto() + QI_CRAFTING_RECIPE = enum.auto() CHEFSANITY = enum.auto() CHEFSANITY_STARTER = enum.auto() CHEFSANITY_QOS = enum.auto() CHEFSANITY_PURCHASE = enum.auto() CHEFSANITY_FRIENDSHIP = enum.auto() CHEFSANITY_SKILL = enum.auto() + CRAFTSANITY = enum.auto() + # Mods MAGIC_SPELL = enum.auto() @@ -326,6 +328,7 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[I items.append(item_factory("Magnifying Glass")) items.append(item_factory("Bear's Knowledge")) items.append(item_factory("Iridium Snake Milk")) + items.append(item_factory("Fairy Dust Recipe")) def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -495,10 +498,10 @@ def create_walnut_purchase_rewards(item_factory: StardewItemFactory, options: St def create_special_order_board_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): if options.special_order_locations == SpecialOrderLocations.option_disabled: return - need_all_recipes = world_is_perfection(world_options) - items_and_classifications = {item: (special_order_board_item_classification(item, need_all_recipes)) for item in items_by_group[Group.SPECIAL_ORDER_BOARD]} - items.extend([item_factory(item, items_and_classifications[item]) for item in items_and_classifications]) + special_order_board_items = {item for item in items_by_group[Group.SPECIAL_ORDER_BOARD]} + + items.extend([item_factory(item) for item in special_order_board_items]) def special_order_board_item_classification(item: ItemData, need_all_recipes: bool) -> ItemClassification: @@ -528,10 +531,16 @@ def create_tv_channels(item_factory: StardewItemFactory, items: List[Item]): def create_crafting_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - if world_options[options.Shipsanity] == options.Shipsanity.option_everything: - crafting_recipes = [reward for reward in items_by_group[Group.CRAFTING_RECIPE]] - crafting_recipes = remove_excluded_items(crafting_recipes, world_options) - items.extend([item_factory(item) for item in crafting_recipes]) + has_shipsanity = world_options[options.Shipsanity] == options.Shipsanity.option_everything + has_craftsanity = world_options[options.Craftsanity] == options.Craftsanity.option_all + need_qi_recipes = has_shipsanity or has_craftsanity + crafting_recipes = [] + if need_qi_recipes: + crafting_recipes.extend([recipe for recipe in items_by_group[Group.QI_CRAFTING_RECIPE]]) + if has_craftsanity: + crafting_recipes.extend([recipe for recipe in items_by_group[Group.CRAFTSANITY]]) + crafting_recipes = remove_excluded_items(crafting_recipes, world_options) + items.extend([item_factory(item) for item in crafting_recipes]) def create_cooking_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 9ad0dcbedabe..48c41fc2fc2b 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -80,6 +80,8 @@ class LocationTags(enum.Enum): CHEFSANITY_FRIENDSHIP = enum.auto() CHEFSANITY_SKILL = enum.auto() CHEFSANITY_STARTER = enum.auto() + CRAFTSANITY = enum.auto() + # Mods # Skill Mods LUCK_LEVEL = enum.auto() BINNING_LEVEL = enum.auto() @@ -387,6 +389,16 @@ def extend_chefsanity_locations(randomized_locations: List[LocationData], world_ randomized_locations.extend(filtered_chefsanity_locations) +def extend_craftsanity_locations(randomized_locations: List[LocationData], world_options): + craftsanity = world_options[options.Craftsanity] + if craftsanity == options.Craftsanity.option_none: + return + + craftsanity_locations = [craft for craft in locations_by_tag[LocationTags.CRAFTSANITY]] + filtered_chefsanity_locations = filter_disabled_locations(world_options, craftsanity_locations) + randomized_locations.extend(filtered_chefsanity_locations) + + def create_locations(location_collector: StardewLocationCollector, options: StardewValleyOptions, random: Random): @@ -430,6 +442,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_shipsanity_locations(randomized_locations, world_options) extend_cooksanity_locations(randomized_locations, world_options) extend_chefsanity_locations(randomized_locations, world_options) + extend_craftsanity_locations(randomized_locations, world_options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 42f25a7abaea..b48e9986465a 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,10 +1,7 @@ -from typing import Iterable - from .received_logic import ReceivedLogic from .region_logic import RegionLogic -from ..data.monster_data import StardewMonster from ..mods.logic.magic_logic import MagicLogic -from ..stardew_rule import StardewRule, Or, And +from ..stardew_rule import StardewRule, Or from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.performance_names import Performance from ..strings.region_names import Region @@ -80,16 +77,3 @@ def can_buy_weapon(self, weapon_rule: StardewRule = None) -> StardewRule: if weapon_rule is None: return adventure_guild_rule return adventure_guild_rule & weapon_rule - - def can_kill_monster(self, monster: StardewMonster) -> StardewRule: - region_rule = self.region.can_reach_any(monster.locations) - combat_rule = self.can_fight_at_level(monster.difficulty) - return region_rule & combat_rule - - def can_kill_any_monster(self, monsters: Iterable[StardewMonster]) -> StardewRule: - rules = [self.can_kill_monster(monster) for monster in monsters] - return Or(rules) - - def can_kill_all_monsters(self, monsters: Iterable[StardewMonster]) -> StardewRule: - rules = [self.can_kill_monster(monster) for monster in monsters] - return And(rules) diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 85cba9d190f0..f2561389f7ad 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -4,16 +4,20 @@ from .region_logic import RegionLogic from .relationship_logic import RelationshipLogic from .skill_logic import SkillLogic +from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogic +from .. import options from ..data.craftable_data import CraftingRecipe from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource -from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource +from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region class CraftingLogic: player: int + craftsanity_option: int + special_orders_option: int received: ReceivedLogic has: HasLogic region: RegionLogic @@ -21,10 +25,13 @@ class CraftingLogic: money: MoneyLogic relationship: RelationshipLogic skill: SkillLogic + special_orders: SpecialOrderLogic - def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, money: MoneyLogic, - relationship: RelationshipLogic, skill: SkillLogic): + def __init__(self, player: int, craftsanity_option: int, special_orders_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): self.player = player + self.craftsanity_option = craftsanity_option + self.special_orders_option = special_orders_option self.received = received self.has = has self.region = region @@ -32,35 +39,54 @@ def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: self.money = money self.relationship = relationship self.skill = skill + self.special_orders = special_orders def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: craft_rule = True_() if recipe is None: return craft_rule - learn_rule = self.can_learn_recipe(recipe.source) + learn_rule = self.knows_recipe(recipe) ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) // 10 time_rule = self.time.has_lived_months(number_ingredients) return craft_rule & learn_rule & ingredients_rule & time_rule - def can_learn_recipe(self, source: RecipeSource) -> StardewRule: - if isinstance(source, StarterSource): + def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: + if isinstance(recipe.source, ArchipelagoSource): + return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) + if self.craftsanity_option == options.Craftsanity.option_none: + return self.can_learn_recipe(recipe) + if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance(recipe.source, ShopSource): + return self.received_recipe(recipe.item) + if isinstance(recipe.source, SpecialOrderSource) and self.special_orders_option != options.SpecialOrderLocations.option_disabled: + return self.received_recipe(recipe.item) + return self.can_learn_recipe(recipe) + + def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: + if isinstance(recipe.source, StarterSource): return True_() - if isinstance(source, ArchipelagoSource): - return self.received(source.ap_item, len(source.ap_item)) - if isinstance(source, ShopTradeSource): - return self.money.can_trade_at(source.region, source.currency, source.price) - if isinstance(source, ShopSource): - return self.money.can_spend_at(source.region, source.price) - if isinstance(source, SkillSource): - return self.skill.has_level(source.skill, source.level) - if isinstance(source, CutsceneSource): - return self.region.can_reach(source.region) & self.relationship.has_hearts(source.friend, source.hearts) - if isinstance(source, FriendshipSource): - return self.relationship.has_hearts(source.friend, source.hearts) - if isinstance(source, LogicSource): - if source.logic_rule == "Cellar": + if isinstance(recipe.source, ArchipelagoSource): + return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) + if isinstance(recipe.source, ShopTradeSource): + return self.money.can_trade_at(recipe.source.region, recipe.source.currency, recipe.source.price) + if isinstance(recipe.source, ShopSource): + return self.money.can_spend_at(recipe.source.region, recipe.source.price) + if isinstance(recipe.source, SkillSource): + return self.skill.has_level(recipe.source.skill, recipe.source.level) + if isinstance(recipe.source, CutsceneSource): + return self.region.can_reach(recipe.source.region) & self.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) + if isinstance(recipe.source, FriendshipSource): + return self.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) + if isinstance(recipe.source, SpecialOrderSource): + if self.special_orders_option == options.SpecialOrderLocations.option_disabled: + return self.special_orders.can_complete_special_order(recipe.source.special_order) + return self.received_recipe(recipe.item) + if isinstance(recipe.source, LogicSource): + if recipe.source.logic_rule == "Cellar": return self.region.can_reach(Region.cellar) return False_() + + def received_recipe(self, item_name: str): + return self.received(f"{item_name} Recipe") diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index e1fd9799479c..8d0764e8dbbf 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -26,7 +26,7 @@ def has_max_fishing(self) -> StardewRule: return self.tool.has_fishing_rod(4) & skill_rule def can_fish_chests(self) -> StardewRule: - skill_rule = self.skill.has_level(Skill.fishing, 4) + skill_rule = self.skill.has_level(Skill.fishing, 6) return self.tool.has_fishing_rod(4) & skill_rule def can_fish_at(self, region: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 0853f66e6e20..5fe4888f930a 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -16,6 +16,7 @@ from .gift_logic import GiftLogic from .mine_logic import MineLogic from .money_logic import MoneyLogic +from .monster_logic import MonsterLogic from .museum_logic import MuseumLogic from .pet_logic import PetLogic from .received_logic import ReceivedLogic @@ -126,6 +127,7 @@ def __post_init__(self): self.museum = MuseumLogic(self.player, self.options[options.Museumsanity], self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) self.combat = CombatLogic(self.player, self.received, self.region) + self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) self.crop = CropLogic(self.player, self.has, self.region, self.season, self.tool) @@ -134,11 +136,12 @@ def __post_init__(self): self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) self.cooking = CookingLogic(self.player, self.options[options.Chefsanity], self.options[options.ExcludeGingerIsland], self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) - self.crafting = CraftingLogic(self.player, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) + self.crafting = CraftingLogic(self.player, self.options[options.Craftsanity], self.options[options.SpecialOrderLocations], self.received, self.has, + self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability) @@ -291,7 +294,7 @@ def __post_init__(self): Fish.periwinkle: self.skill.can_crab_pot(Region.town), Fish.shrimp: self.skill.can_crab_pot(Region.beach), Fish.snail: self.skill.can_crab_pot(Region.town), - Fishing.curiosity_lure: self.combat.can_kill_monster(all_monsters_by_name[Monster.mummy]), + Fishing.curiosity_lure: self.monster.can_kill(all_monsters_by_name[Monster.mummy]), Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200), Forageable.blackberry: self.tool.can_forage(Season.fall), Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), @@ -325,7 +328,7 @@ def __post_init__(self): Forageable.wild_horseradish: self.tool.can_forage(Season.spring), Forageable.wild_plum: self.tool.can_forage(Season.fall), Forageable.winter_root: self.tool.can_forage(Season.winter, Region.forest, True), - Fossil.bone_fragment: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), + Fossil.bone_fragment: (self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe)) | self.monster.can_kill(Monster.skeleton), Fossil.fossilized_leg: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), Fossil.fossilized_ribs: self.region.can_reach(Region.island_south) & self.tool.has_tool(Tool.hoe), Fossil.fossilized_skull: self.action.can_open_geode(Geode.golden_coconut), @@ -507,36 +510,36 @@ def __post_init__(self): self.quest_rules.update(self.mod.quests.get_modded_quest_rules()) self.festival_rules.update({ - FestivalCheck.egg_hunt: self.season.has(Season.spring) & self.region.can_reach(Region.town) & self.can_win_egg_hunt(), - FestivalCheck.strawberry_seeds: self.season.has(Season.spring) & self.region.can_reach(Region.town) & self.money.can_spend(1000), - FestivalCheck.dance: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.has_hearts(Generic.bachelor, 4), - FestivalCheck.rarecrow_5: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.money.can_spend(2500), - FestivalCheck.luau_soup: self.season.has(Season.summer) & self.region.can_reach(Region.beach) & self.can_succeed_luau_soup(), - FestivalCheck.moonlight_jellies: self.season.has(Season.summer) & self.region.can_reach(Region.beach), - FestivalCheck.smashing_stone: self.season.has(Season.fall) & self.region.can_reach(Region.town), - FestivalCheck.grange_display: self.season.has(Season.fall) & self.region.can_reach(Region.town) & self.can_succeed_grange_display(), - FestivalCheck.rarecrow_1: self.season.has(Season.fall) & self.region.can_reach(Region.town), # only cost star tokens - FestivalCheck.fair_stardrop: self.season.has(Season.fall) & self.region.can_reach(Region.town), # only cost star tokens - FestivalCheck.spirit_eve_maze: self.season.has(Season.fall) & self.region.can_reach(Region.town), - FestivalCheck.rarecrow_2: self.season.has(Season.fall) & self.region.can_reach(Region.town) & self.money.can_spend(5000), - FestivalCheck.fishing_competition: self.season.has(Season.winter) & self.region.can_reach(Region.forest) & self.can_win_fishing_competition(), - FestivalCheck.rarecrow_4: self.season.has(Season.winter) & self.region.can_reach(Region.forest) & self.money.can_spend(5000), - FestivalCheck.mermaid_pearl: self.season.has(Season.winter) & self.region.can_reach(Region.beach), - FestivalCheck.cone_hat: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(2500), - FestivalCheck.iridium_fireplace: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(15000), - FestivalCheck.rarecrow_7: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_donate_museum_artifacts(20), - FestivalCheck.rarecrow_8: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(5000) & self.museum.can_donate_museum_items(40), - FestivalCheck.lupini_red_eagle: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), - FestivalCheck.lupini_portrait_mermaid: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), - FestivalCheck.lupini_solar_kingdom: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.money.can_spend(1200), - FestivalCheck.lupini_clouds: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_two() & self.money.can_spend(1200), - FestivalCheck.lupini_1000_years: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_two() & self.money.can_spend(1200), - FestivalCheck.lupini_three_trees: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_two() & self.money.can_spend(1200), - FestivalCheck.lupini_the_serpent: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_three() & self.money.can_spend(1200), - FestivalCheck.lupini_tropical_fish: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_three() & self.money.can_spend(1200), - FestivalCheck.lupini_land_of_clay: self.season.has(Season.winter) & self.region.can_reach(Region.beach) & self.time.has_year_three() & self.money.can_spend(1200), - FestivalCheck.secret_santa: self.season.has(Season.winter) & self.region.can_reach(Region.town) & self.gifts.has_any_universal_love(), - FestivalCheck.legend_of_the_winter_star: self.season.has(Season.winter) & self.region.can_reach(Region.town), + FestivalCheck.egg_hunt: self.can_win_egg_hunt(), + FestivalCheck.strawberry_seeds: self.money.can_spend(1000), + FestivalCheck.dance: self.relationship.has_hearts(Generic.bachelor, 4), + FestivalCheck.rarecrow_5: self.money.can_spend(2500), + FestivalCheck.luau_soup: self.can_succeed_luau_soup(), + FestivalCheck.moonlight_jellies: True_(), + FestivalCheck.smashing_stone: True_(), + FestivalCheck.grange_display: self.can_succeed_grange_display(), + FestivalCheck.rarecrow_1: True_(), # only cost star tokens + FestivalCheck.fair_stardrop: True_(), # only cost star tokens + FestivalCheck.spirit_eve_maze: True_(), + FestivalCheck.rarecrow_2: self.money.can_spend(5000), + FestivalCheck.fishing_competition: self.can_win_fishing_competition(), + FestivalCheck.rarecrow_4: self.money.can_spend(5000), + FestivalCheck.mermaid_pearl: self.has(Forageable.secret_note), + FestivalCheck.cone_hat: self.money.can_spend(2500), + FestivalCheck.iridium_fireplace: self.money.can_spend(15000), + FestivalCheck.rarecrow_7: self.money.can_spend(5000) & self.museum.can_donate_museum_artifacts(20), + FestivalCheck.rarecrow_8: self.money.can_spend(5000) & self.museum.can_donate_museum_items(40), + FestivalCheck.lupini_red_eagle: self.money.can_spend(1200), + FestivalCheck.lupini_portrait_mermaid: self.money.can_spend(1200), + FestivalCheck.lupini_solar_kingdom: self.money.can_spend(1200), + FestivalCheck.lupini_clouds: self.time.has_year_two() & self.money.can_spend(1200), + FestivalCheck.lupini_1000_years: self.time.has_year_two() & self.money.can_spend(1200), + FestivalCheck.lupini_three_trees: self.time.has_year_two() & self.money.can_spend(1200), + FestivalCheck.lupini_the_serpent: self.time.has_year_three() & self.money.can_spend(1200), + FestivalCheck.lupini_tropical_fish: self.time.has_year_three() & self.money.can_spend(1200), + FestivalCheck.lupini_land_of_clay: self.time.has_year_three() & self.money.can_spend(1200), + FestivalCheck.secret_santa: self.gifts.has_any_universal_love(), + FestivalCheck.legend_of_the_winter_star: True_(), FestivalCheck.all_rarecrows: self.region.can_reach(Region.farm) & self.has_all_rarecrows(), }) @@ -710,7 +713,7 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: for category in all_monsters_by_category: if exclude_island and all(monster.locations[0] in island_regions for monster in all_monsters_by_category[category]): continue - rules.append(self.combat.can_kill_any_monster(all_monsters_by_category[category])) + rules.append(self.monster.can_kill_any(all_monsters_by_category[category])) return And(rules) diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index d53a33b6a514..a01fb2c18938 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -87,6 +87,7 @@ def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule if self.skill_option == options.SkillProgression.option_progressive: combat_tier = min(10, max(0, tier * 2)) rules.append(self.skill.has_level(Skill.combat, combat_tier)) + rules.append(self.skill.has_level(Skill.mining, combat_tier)) return And(rules) def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 0720340d1844..60f36e6f9e47 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,26 +1,27 @@ +from typing import Iterable, Union + from .combat_logic import CombatLogic from .region_logic import RegionLogic -from .time_logic import TimeLogic -from .. import StardewOptions -from ..data.monster_data import StardewMonster -from ..stardew_rule import StardewRule +from .time_logic import TimeLogic, MAX_MONTHS +from ..data.monster_data import StardewMonster, all_monsters_by_name +from ..stardew_rule import StardewRule, Or, And class MonsterLogic: player: int - options: StardewOptions region: RegionLogic time: TimeLogic combat: CombatLogic - def __init__(self, player: int, options: StardewOptions, region: RegionLogic, time: TimeLogic, combat: CombatLogic): + def __init__(self, player: int, region: RegionLogic, time: TimeLogic, combat: CombatLogic): self.player = player - self.options: options self.region = region self.time = time self.combat = combat - def can_kill(self, monster: StardewMonster, amount_tier: int = 0) -> StardewRule: + def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> StardewRule: + if isinstance(monster, str): + monster = all_monsters_by_name[monster] region_rule = self.region.can_reach_any(monster.locations) combat_rule = self.combat.can_fight_at_level(monster.difficulty) if amount_tier <= 0: @@ -28,3 +29,14 @@ def can_kill(self, monster: StardewMonster, amount_tier: int = 0) -> StardewRule time_rule = self.time.has_lived_months(amount_tier * 2) return region_rule & combat_rule & time_rule + def can_kill_max(self, monster: StardewMonster) -> StardewRule: + return self.can_kill(monster, MAX_MONTHS) + + def can_kill_any(self, monsters: Iterable[StardewMonster], amount_tier: int = 0) -> StardewRule: + rules = [self.can_kill(monster, amount_tier) for monster in monsters] + return Or(rules) + + def can_kill_all(self, monsters: Iterable[StardewMonster], amount_tier: int = 0) -> StardewRule: + rules = [self.can_kill(monster, amount_tier) for monster in monsters] + return And(rules) + diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index c18ad900588f..ce9b10d6f342 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -94,7 +94,7 @@ def initialize_rules(self): SpecialOrder.robins_project: self.relationship.can_meet(NPC.robin) & self.region.can_reach(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Material.hardwood), SpecialOrder.robins_resource_rush: self.relationship.can_meet(NPC.robin) & self.region.can_reach(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted_yum: self.region.can_reach(Region.beach) & self.has(Loot.bug_meat), + SpecialOrder.juicy_bugs_wanted: self.region.can_reach(Region.beach) & self.has(Loot.bug_meat), SpecialOrder.tropical_fish: self.relationship.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), SpecialOrder.a_curious_substance: self.region.can_reach(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 6dfcf096f2fc..2db5027e7b92 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -447,6 +447,18 @@ class Chefsanity(Choice): option_all = 0b1111 # 15 +class Craftsanity(Choice): + """Checks for crafting items? + If enabled, all recipes purchased in shops will be checks as well. + Recipes obtained from other sources will depend on related archipelago settings + """ + internal_name = "craftsanity" + display_name = "Craftsanity" + default = 0 + option_none = 0 + option_all = 1 + + class Friendsanity(Choice): """Shuffle Friendships? None: Friendship hearts are earned normally @@ -662,6 +674,7 @@ class StardewValleyOptions(PerGameCommonOptions): Shipsanity, Cooksanity, Chefsanity, + Craftsanity, friendsanity: Friendsanity friendsanity_heart_size: FriendsanityHeartSize movement_buff_number: NumberOfMovementBuffs diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 6761b8b611d0..d2b57ae34b97 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -72,8 +72,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: Entrance.town_to_clint_blacksmith, Entrance.town_to_museum, Entrance.town_to_jojamart, Entrance.purchase_movie_ticket, - Entrance.attend_egg_festival, Entrance.attend_fair, - Entrance.attend_spirit_eve, Entrance.attend_winter_star]), + Entrance.attend_egg_festival, Entrance.attend_fair, Entrance.attend_spirit_eve, Entrance.attend_winter_star]), RegionData(Region.beach, [Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, Entrance.fishing, Entrance.attend_luau, Entrance.attend_moonlight_jellies, Entrance.attend_night_market]), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index ba2d0c3f020e..8e2b0a851334 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -5,6 +5,7 @@ from worlds.generic import Rules as MultiWorldRules from . import options, locations from .bundles import Bundle +from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .data.recipe_data import all_cooking_recipes_by_name from .logic.logic import StardewLogic @@ -64,6 +65,7 @@ def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOption set_shipsanity_rules(all_location_names, logic, multi_world, player, world_options) set_cooksanity_rules(all_location_names, logic, multi_world, player, world_options) set_chefsanity_rules(all_location_names, logic, multi_world, player, world_options) + set_craftsanity_rules(all_location_names, logic, multi_world, player, world_options) set_isolated_locations_rules(logic, multi_world, player) set_traveling_merchant_rules(logic, multi_world, player) set_arcade_machine_rules(logic, multi_world, player, world_options) @@ -646,9 +648,10 @@ def set_monstersanity_monster_rules(all_location_names: List[str], logic: Starde if location_name not in all_location_names: continue location = multi_world.get_location(location_name, player) - rule = logic.combat.can_kill_monster(all_monsters_by_name[monster_name]) if monstersanity_option == options.Monstersanity.option_split_goals: - rule = rule & logic.time.has_lived_max_months() + rule = logic.monster.can_kill_max(all_monsters_by_name[monster_name]) + else: + rule = logic.monster.can_kill(all_monsters_by_name[monster_name]) MultiWorldRules.set_rule(location, rule.simplify()) @@ -673,9 +676,9 @@ def set_monstersanity_progressive_category_rule(all_location_names: List[str], l return location = multi_world.get_location(location_name, player) if goal_index < 3: - rule = logic.combat.can_kill_any_monster(all_monsters_by_category[monster_category]) & logic.time.has_lived_months((goal_index + 1) * 2) + rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category], goal_index + 1) else: - rule = logic.combat.can_kill_all_monsters(all_monsters_by_category[monster_category]) & logic.time.has_lived_months(goal_index * 3) + rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], goal_index * 2) MultiWorldRules.set_rule(location, rule.simplify()) @@ -694,9 +697,9 @@ def set_monstersanity_category_rules(all_location_names: List[str], logic: Stard continue location = multi_world.get_location(location_name, player) if monstersanity_option == options.Monstersanity.option_one_per_category: - rule = logic.combat.can_kill_any_monster(all_monsters_by_category[monster_category]) + rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category]) else: - rule = logic.combat.can_kill_all_monsters(all_monsters_by_category[monster_category]) & logic.time.has_lived_max_months() + rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], 8) MultiWorldRules.set_rule(location, rule.simplify()) @@ -743,6 +746,27 @@ def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, mul MultiWorldRules.set_rule(multi_world.get_location(location.name, player), learn_rule) +def set_craftsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): + craftsanity_option = world_options[options.Craftsanity] + if craftsanity_option == options.Craftsanity.option_none: + return + + craft_prefix = "Craft " + craft_suffix = " Recipe" + for location in locations.locations_by_tag[LocationTags.CRAFTSANITY]: + if location.name not in all_location_names: + continue + if location.name.endswith(craft_suffix): + recipe_name = location.name[:-len(craft_suffix)] + recipe = all_crafting_recipes_by_name[recipe_name] + craft_rule = logic.crafting.can_learn_recipe(recipe) + else: + recipe_name = location.name[len(craft_prefix):] + recipe = all_crafting_recipes_by_name[recipe_name] + craft_rule = logic.crafting.can_craft(recipe) + MultiWorldRules.set_rule(multi_world.get_location(location.name, player), craft_rule) + + def set_traveling_merchant_day_rules(logic: StardewLogic, multi_world: MultiWorld, player: int): for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index d455479ca885..0dbcc066766c 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -203,6 +203,7 @@ class Entrance: attend_night_market = "Attend Night Market" attend_winter_star = "Attend Feast of the Winter Star" + # Skull Cavern Elevator diff --git a/worlds/stardew_valley/strings/special_order_names.py b/worlds/stardew_valley/strings/special_order_names.py index 04eec828c0b0..f7b49cdf05e9 100644 --- a/worlds/stardew_valley/strings/special_order_names.py +++ b/worlds/stardew_valley/strings/special_order_names.py @@ -13,7 +13,7 @@ class SpecialOrder: pierres_prime_produce = "Pierre's Prime Produce" robins_project = "Robin's Project" robins_resource_rush = "Robin's Resource Rush" - juicy_bugs_wanted_yum = "Juicy Bugs Wanted!" + juicy_bugs_wanted = "Juicy Bugs Wanted!" tropical_fish = "Tropical Fish" a_curious_substance = "A Curious Substance" prismatic_jelly = "Prismatic Jelly" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index d35ca957408e..4563a482bed4 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -24,6 +24,7 @@ class TestBaseItemGeneration(SVTestBase): options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, options.Shipsanity.internal_name: options.Shipsanity.option_everything, options.Chefsanity.internal_name: options.Chefsanity.option_all, + options.Craftsanity.internal_name: options.Craftsanity.option_all, } def test_all_progression_items_are_added_to_the_pool(self): @@ -73,6 +74,7 @@ class TestNoGingerIslandItemGeneration(SVTestBase): options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, options.Shipsanity.internal_name: options.Shipsanity.option_everything, options.Chefsanity.internal_name: options.Chefsanity.option_all, + options.Craftsanity.internal_name: options.Craftsanity.option_all, } def test_all_progression_items_except_island_are_added_to_the_pool(self): diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index b55e8a745678..667648b01a93 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -2,6 +2,7 @@ from . import SVTestBase from .. import options +from ..data.craftable_data import all_crafting_recipes_by_name from ..locations import locations_by_tag, LocationTags, location_table from ..strings.animal_names import Animal from ..strings.animal_product_names import AnimalProduct @@ -433,6 +434,54 @@ def test_get_chefsanity_check_recipe(self): self.assertTrue(rule(self.multiworld.state)) +class TestCraftsanityLogic(SVTestBase): + options = { + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.Craftsanity.internal_name: options.Craftsanity.option_all, + options.ExcludeGingerIsland.internal_name: options.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([self.world.create_item("Month End")] * 12) + self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Marble Brazier Recipe"), event=False) + self.assertTrue(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.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Month End"), event=False) + self.assertTrue(rule(self.multiworld.state)) + + +class TestNoCraftsanityLogic(SVTestBase): + options = { + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.ExcludeGingerIsland.internal_name: options.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.assertTrue(rule(self.multiworld.state)) + + class TestDonationLogicAll(SVTestBase): options = { options.Museumsanity.internal_name: options.Museumsanity.option_all diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index af10f88b3700..f2fd112354d3 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -54,6 +54,7 @@ class TestBaseItemGeneration(SVTestBase): options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, options.Shipsanity.internal_name: options.Shipsanity.option_everything, options.Chefsanity.internal_name: options.Chefsanity.option_all, + options.Craftsanity.internal_name: options.Craftsanity.option_all, options.Mods.internal_name: mod_list } @@ -79,6 +80,7 @@ class TestNoGingerIslandModItemGeneration(SVTestBase): options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, options.Shipsanity.internal_name: options.Shipsanity.option_everything, options.Chefsanity.internal_name: options.Chefsanity.option_all, + options.Craftsanity.internal_name: options.Craftsanity.option_all, options.Mods.internal_name: mod_list } From 87705ebf8e39fcac1b5c3750353de241dd16b12d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 26 Sep 2023 12:32:32 -0400 Subject: [PATCH 077/482] - Added a few crafting recipe festival checks --- worlds/stardew_valley/data/craftable_data.py | 11 +++- worlds/stardew_valley/data/locations.csv | 2 + worlds/stardew_valley/data/recipe_source.py | 6 ++ worlds/stardew_valley/logic/crafting_logic.py | 11 +++- worlds/stardew_valley/logic/logic.py | 9 ++- .../strings/festival_check_names.py | 4 ++ worlds/stardew_valley/test/TestRules.py | 66 +++++++++++++++++++ 7 files changed, 102 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index f88c6ac8d040..4ac8c614b72f 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -1,7 +1,7 @@ from typing import Dict, List from .recipe_source import RecipeSource, StarterSource, QueenOfSauceSource, ShopSource, SkillSource, FriendshipSource, ShopTradeSource, CutsceneSource, \ - ArchipelagoSource, LogicSource, SpecialOrderSource + ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource from ..strings.artisan_good_names import ArtisanGood from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, Fishing, Ring, Consumable, Edible, Lighting, Storage, Furniture, Sign, Craftable from ..strings.crop_names import Fruit, Vegetable @@ -60,6 +60,11 @@ def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) return create_recipe(name, ingredients, source) +def festival_shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe: + source = FestivalShopSource(region, price) + return create_recipe(name, ingredients, source) + + def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe: source = ShopTradeSource(region, currency, price) return create_recipe(name, ingredients, source) @@ -203,7 +208,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) marble_brazier = shop_recipe(Lighting.marble_brazier, Region.carpenter, 5000, {Mineral.marble: 1, Mineral.aquamarine: 1, Material.stone: 100}) wood_lamp_post = shop_recipe(Lighting.wood_lamp_post, Region.carpenter, 500, {Material.wood: 50, ArtisanGood.battery_pack: 1}) iron_lamp_post = shop_recipe(Lighting.iron_lamp_post, Region.carpenter, 1000, {MetalBar.iron: 1, ArtisanGood.battery_pack: 1}) -jack_o_lantern = shop_recipe(Lighting.jack_o_lantern, Region.spirit_eve, 2000, {Vegetable.pumpkin: 1, Lighting.torch: 1}) +jack_o_lantern = festival_shop_recipe(Lighting.jack_o_lantern, Region.spirit_eve, 2000, {Vegetable.pumpkin: 1, Lighting.torch: 1}) bone_mill = ap_recipe(Machine.bone_mill, {Fossil.bone_fragment: 10, Material.clay: 3, Material.stone: 20}) charcoal_kiln = skill_recipe(Machine.charcoal_kiln, Skill.foraging, 4, {Material.wood: 20, MetalBar.copper: 2}) @@ -221,7 +226,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) tapper = skill_recipe(Machine.tapper, Skill.foraging, 3, {Material.wood: 40, MetalBar.copper: 2}) worm_bin = skill_recipe(Machine.worm_bin, Skill.fishing, 8, {Material.hardwood: 25, MetalBar.gold: 1, MetalBar.iron: 1, Material.fiber: 50}) -tub_o_flowers = shop_recipe(Furniture.tub_o_flowers, Region.flower_dance, 2000, {Material.wood: 15, Seed.tulip: 1, Seed.jazz: 1, Seed.poppy: 1, Seed.spangle: 1}) +tub_o_flowers = festival_shop_recipe(Furniture.tub_o_flowers, Region.flower_dance, 2000, {Material.wood: 15, Seed.tulip: 1, Seed.jazz: 1, Seed.poppy: 1, Seed.spangle: 1}) wicked_statue = shop_recipe(Furniture.wicked_statue, Region.sewer, 1000, {Material.stone: 25, Material.coal: 5}) flute_block = cutscene_recipe(Furniture.flute_block, Region.carpenter, NPC.robin, 6, {Material.wood: 10, Ore.copper: 2, Material.fiber: 20}) drum_block = cutscene_recipe(Furniture.drum_block, Region.carpenter, NPC.robin, 6, {Material.stone: 10, Ore.copper: 2, Material.fiber: 20}) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a95795afc29e..0e68f2afdfcf 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -951,6 +951,8 @@ id,region,name,tags,mod_name 2029,Feast of the Winter Star,Secret Santa,FESTIVAL, 2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, 2031,Farm,Collect All Rarecrows,FESTIVAL, +2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, +2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, 2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index f2b1e6837970..5db2fab17c11 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -96,6 +96,12 @@ def __repr__(self): return f"ShopSource at {self.region} costing {self.price}g" +class FestivalShopSource(ShopSource): + + def __init__(self, region: str, price: int): + super().__init__(region, price) + + class ShopTradeSource(ShopSource): currency: str diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index f2561389f7ad..15cf9af427a5 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -9,7 +9,7 @@ from .. import options from ..data.craftable_data import CraftingRecipe from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource -from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource +from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region @@ -17,6 +17,7 @@ class CraftingLogic: player: int craftsanity_option: int + festivals_option: int special_orders_option: int received: ReceivedLogic has: HasLogic @@ -27,10 +28,11 @@ class CraftingLogic: skill: SkillLogic special_orders: SpecialOrderLogic - def __init__(self, player: int, craftsanity_option: int, special_orders_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, craftsanity_option: int, festivals_option: int, special_orders_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): self.player = player self.craftsanity_option = craftsanity_option + self.festivals_option = festivals_option self.special_orders_option = special_orders_option self.received = received self.has = has @@ -55,6 +57,11 @@ def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, ArchipelagoSource): return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) + if isinstance(recipe.source, FestivalShopSource): + if self.festivals_option == options.FestivalLocations.option_disabled: + return self.can_learn_recipe(recipe) + else: + return self.received_recipe(recipe.item) if self.craftsanity_option == options.Craftsanity.option_none: return self.can_learn_recipe(recipe) if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance(recipe.source, ShopSource): diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 5fe4888f930a..b5f3725809bb 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -140,8 +140,9 @@ def __post_init__(self): self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) - self.crafting = CraftingLogic(self.player, self.options[options.Craftsanity], self.options[options.SpecialOrderLocations], self.received, self.has, - self.region, self.time, self.money, self.relationship, self.skill, self.special_order) + self.crafting = CraftingLogic(self.player, self.options[options.Craftsanity], self.options[options.FestivalLocations], + self.options[options.SpecialOrderLocations], self.received, self.has, self.region, self.time, self.money, + self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability) @@ -513,14 +514,18 @@ def __post_init__(self): FestivalCheck.egg_hunt: self.can_win_egg_hunt(), FestivalCheck.strawberry_seeds: self.money.can_spend(1000), FestivalCheck.dance: self.relationship.has_hearts(Generic.bachelor, 4), + FestivalCheck.tub_o_flowers: self.money.can_spend(2000), FestivalCheck.rarecrow_5: self.money.can_spend(2500), FestivalCheck.luau_soup: self.can_succeed_luau_soup(), FestivalCheck.moonlight_jellies: True_(), + FestivalCheck.moonlight_jellies_banner: self.money.can_spend(800), + FestivalCheck.starport_decal: self.money.can_spend(1000), FestivalCheck.smashing_stone: True_(), FestivalCheck.grange_display: self.can_succeed_grange_display(), FestivalCheck.rarecrow_1: True_(), # only cost star tokens FestivalCheck.fair_stardrop: True_(), # only cost star tokens FestivalCheck.spirit_eve_maze: True_(), + FestivalCheck.jack_o_lantern: self.money.can_spend(2000), FestivalCheck.rarecrow_2: self.money.can_spend(5000), FestivalCheck.fishing_competition: self.can_win_fishing_competition(), FestivalCheck.rarecrow_4: self.money.can_spend(5000), diff --git a/worlds/stardew_valley/strings/festival_check_names.py b/worlds/stardew_valley/strings/festival_check_names.py index 404878999fc7..ff34c59e8aad 100644 --- a/worlds/stardew_valley/strings/festival_check_names.py +++ b/worlds/stardew_valley/strings/festival_check_names.py @@ -30,3 +30,7 @@ class FestivalCheck: spirit_eve_maze = "Spirit's Eve Maze" strawberry_seeds = "Egg Festival: Strawberry Seeds" all_rarecrows = "Collect All Rarecrows" + tub_o_flowers = "Tub o' Flowers Recipe" + jack_o_lantern = "Jack-O-Lantern Recipe" + moonlight_jellies_banner = "Moonlight Jellies Banner" + starport_decal = "Starport Decal" diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 667648b01a93..6c0524c7620d 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -467,11 +467,48 @@ def test_can_learn_crafting_recipe(self): self.multiworld.state.collect(self.world.create_item("Month End"), event=False) self.assertTrue(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) + rule = self.world.logic.crafting.can_craft(recipe) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Fall"), event=False) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Jack-O-Lantern Recipe"), event=False) + self.assertTrue(rule(self.multiworld.state)) + + +class TestCraftsanityWithFestivalsLogic(SVTestBase): + options = { + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.FestivalLocations.internal_name: options.FestivalLocations.option_easy, + options.Craftsanity.internal_name: options.Craftsanity.option_all, + options.ExcludeGingerIsland.internal_name: options.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) + rule = self.world.logic.crafting.can_craft(recipe) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Jack-O-Lantern Recipe"), event=False) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Torch Recipe"), event=False) + self.assertTrue(rule(self.multiworld.state)) + class TestNoCraftsanityLogic(SVTestBase): options = { options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, options.Craftsanity.internal_name: options.Craftsanity.option_none, options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, } @@ -481,6 +518,35 @@ def test_can_craft_recipe(self): rule = self.world.logic.crafting.can_craft(recipe) self.assertTrue(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) + rule = self.world.logic.crafting.can_craft(recipe) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Fall"), event=False) + self.assertTrue(rule(self.multiworld.state)) + + +class TestNoCraftsanityWithFestivalsLogic(SVTestBase): + options = { + options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.FestivalLocations.internal_name: options.FestivalLocations.option_easy, + options.Craftsanity.internal_name: options.Craftsanity.option_none, + options.ExcludeGingerIsland.internal_name: options.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) + rule = self.world.logic.crafting.can_craft(recipe) + self.assertFalse(rule(self.multiworld.state)) + + self.multiworld.state.collect(self.world.create_item("Jack-O-Lantern Recipe"), event=False) + self.assertTrue(rule(self.multiworld.state)) + class TestDonationLogicAll(SVTestBase): options = { From 1c0b0e5389ad3b1166ff235320d920d4ca886b7e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 26 Sep 2023 12:40:18 -0400 Subject: [PATCH 078/482] - Updated tests and added two items for the new festival checks --- worlds/stardew_valley/data/items.csv | 2 ++ worlds/stardew_valley/test/TestGeneration.py | 4 ++-- worlds/stardew_valley/test/__init__.py | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index f3bfea0a4ff6..48344c9d0c0a 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -435,6 +435,8 @@ id,name,classification,groups,mod_name 459,Chest Recipe,progression,"CRAFTSANITY", 460,Wood Sign Recipe,progression,"CRAFTSANITY", 461,Stone Sign Recipe,progression,"CRAFTSANITY", +480,Moonlight Jellies Banner,filler,FESTIVAL, +481,Starport Decal,filler,FESTIVAL, 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 4563a482bed4..3fb6b442d3bb 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -306,7 +306,7 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1792 + expected_locations = 1948 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -320,7 +320,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2044 + expected_locations = 2200 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 9d034d00c46a..f9e34c6bdcf3 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -177,6 +177,7 @@ def allsanity_options_without_mods(): Shipsanity.internal_name: Shipsanity.option_everything, Cooksanity.internal_name: Cooksanity.option_all, Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, Friendsanity.internal_name: Friendsanity.option_all_with_marriage, FriendsanityHeartSize.internal_name: 1, NumberOfMovementBuffs.internal_name: 12, From d86285a1d60ac218691e0bc87d8ec3dc290ceb77 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 26 Sep 2023 15:54:49 -0400 Subject: [PATCH 079/482] - Set proper regions for craftsanity recipes --- worlds/stardew_valley/data/locations.csv | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 0e68f2afdfcf..f593dd93be87 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1994,30 +1994,30 @@ id,region,name,tags,mod_name 3528,Farm,Craft Farm Computer,"CRAFTSANITY", 3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", 3530,Farm,Craft Cookout Kit,"CRAFTSANITY", -3551,Farm,Grass Starter Recipe,"CRAFTSANITY", -3552,Farm,Wood Floor Recipe,"CRAFTSANITY", -3553,Farm,Rustic Plank Floor Recipe,"CRAFTSANITY", -3554,Farm,Straw Floor Recipe,"CRAFTSANITY", -3555,Farm,Weathered Floor Recipe,"CRAFTSANITY", -3556,Farm,Crystal Floor Recipe,"CRAFTSANITY", -3557,Farm,Stone Floor Recipe,"CRAFTSANITY", -3558,Farm,Stone Walkway Floor Recipe,"CRAFTSANITY", -3559,Farm,Brick Floor Recipe,"CRAFTSANITY", -3560,Farm,Stepping Stone Path Recipe,"CRAFTSANITY", -3561,Farm,Crystal Path Recipe,"CRAFTSANITY", -3562,Farm,Wedding Ring Recipe,"CRAFTSANITY", -3563,Farm,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", -3564,Farm,Wooden Brazier Recipe,"CRAFTSANITY", -3565,Farm,Stone Brazier Recipe,"CRAFTSANITY", -3566,Farm,Gold Brazier Recipe,"CRAFTSANITY", -3567,Farm,Carved Brazier Recipe,"CRAFTSANITY", -3568,Farm,Stump Brazier Recipe,"CRAFTSANITY", -3569,Farm,Barrel Brazier Recipe,"CRAFTSANITY", -3570,Farm,Skull Brazier Recipe,"CRAFTSANITY", -3571,Farm,Marble Brazier Recipe,"CRAFTSANITY", -3572,Farm,Wood Lamp-post Recipe,"CRAFTSANITY", -3573,Farm,Iron Lamp-post Recipe,"CRAFTSANITY", -3574,Farm,Wicked Statue Recipe,"CRAFTSANITY,REQUIRES_MUSEUM", +3551,Carpenter Shop,Grass Starter Recipe,"CRAFTSANITY", +3552,Carpenter Shop,Wood Floor Recipe,"CRAFTSANITY", +3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", +3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", +3555,Mines Dwarf Shop,Weathered Floor Recipe,"CRAFTSANITY", +3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY", +3557,Carpenter Shop,Stone Floor Recipe,"CRAFTSANITY", +3558,Carpenter Shop,Stone Walkway Floor Recipe,"CRAFTSANITY", +3559,Carpenter Shop,Brick Floor Recipe,"CRAFTSANITY", +3560,Carpenter Shop,Stepping Stone Path Recipe,"CRAFTSANITY", +3561,Carpenter Shop,Crystal Path Recipe,"CRAFTSANITY", +3562,Traveling Cart,Wedding Ring Recipe,"CRAFTSANITY", +3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", +3564,Carpenter Shop,Wooden Brazier Recipe,"CRAFTSANITY", +3565,Carpenter Shop,Stone Brazier Recipe,"CRAFTSANITY", +3566,Carpenter Shop,Gold Brazier Recipe,"CRAFTSANITY", +3567,Carpenter Shop,Carved Brazier Recipe,"CRAFTSANITY", +3568,Carpenter Shop,Stump Brazier Recipe,"CRAFTSANITY", +3569,Carpenter Shop,Barrel Brazier Recipe,"CRAFTSANITY", +3570,Carpenter Shop,Skull Brazier Recipe,"CRAFTSANITY", +3571,Carpenter Shop,Marble Brazier Recipe,"CRAFTSANITY", +3572,Carpenter Shop,Wood Lamp-post Recipe,"CRAFTSANITY", +3573,Carpenter Shop,Iron Lamp-post Recipe,"CRAFTSANITY", +3574,Sewer,Wicked Statue Recipe,"CRAFTSANITY,REQUIRES_MUSEUM", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill From 73a1bca58db412f2b0bcdef8082ab10bcc193172 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 27 Sep 2023 00:30:27 -0400 Subject: [PATCH 080/482] - Add some requires museum flags --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 8 ++++---- worlds/stardew_valley/items.py | 3 +++ worlds/stardew_valley/test/TestRules.py | 6 ++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 48344c9d0c0a..40302115f012 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -406,7 +406,7 @@ id,name,classification,groups,mod_name 430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", 431,Straw Floor Recipe,progression,"CRAFTSANITY", 432,Weathered Floor Recipe,progression,"CRAFTSANITY", -433,Crystal Floor Recipe,progression,"CRAFTSANITY", +433,Crystal Floor Recipe,progression,"CRAFTSANITY,REQUIRES_MUSEUM", 434,Stone Floor Recipe,progression,"CRAFTSANITY", 435,Stone Walkway Floor Recipe,progression,"CRAFTSANITY", 436,Brick Floor Recipe,progression,"CRAFTSANITY", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f593dd93be87..7b715abfb706 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1203,7 +1203,7 @@ id,region,name,tags,mod_name 2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, 2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, 2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, +2560,Shipping,Shipsanity: Crystal Floor,"SHIPSANITY,REQUIRES_MUSEUM", 2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, 2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, 2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, @@ -1905,7 +1905,7 @@ id,region,name,tags,mod_name 3439,Farm,Craft Rustic Plank Floor,"CRAFTSANITY", 3440,Farm,Craft Straw Floor,"CRAFTSANITY", 3441,Farm,Craft Weathered Floor,"CRAFTSANITY", -3442,Farm,Craft Crystal Floor,"CRAFTSANITY", +3442,Farm,Craft Crystal Floor,"CRAFTSANITY,REQUIRES_MUSEUM", 3443,Farm,Craft Stone Floor,"CRAFTSANITY", 3444,Farm,Craft Stone Walkway Floor,"CRAFTSANITY", 3445,Farm,Craft Brick Floor,"CRAFTSANITY", @@ -1974,7 +1974,7 @@ id,region,name,tags,mod_name 3508,Farm,Craft Tapper,"CRAFTSANITY", 3509,Farm,Craft Worm Bin,"CRAFTSANITY", 3510,Farm,Craft Tub o' Flowers,"CRAFTSANITY", -3511,Farm,Craft Wicked Statue,"CRAFTSANITY", +3511,Farm,Craft Wicked Statue,"CRAFTSANITY,REQUIRES_MUSEUM", 3512,Farm,Craft Flute Block,"CRAFTSANITY", 3513,Farm,Craft Drum Block,"CRAFTSANITY", 3514,Farm,Craft Chest,"CRAFTSANITY", @@ -1999,7 +1999,7 @@ id,region,name,tags,mod_name 3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", 3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", 3555,Mines Dwarf Shop,Weathered Floor Recipe,"CRAFTSANITY", -3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY", +3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY,REQUIRES_MUSEUM", 3557,Carpenter Shop,Stone Floor Recipe,"CRAFTSANITY", 3558,Carpenter Shop,Stone Walkway Floor Recipe,"CRAFTSANITY", 3559,Carpenter Shop,Brick Floor Recipe,"CRAFTSANITY", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 31e276bcab9d..83ee7a615dfc 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -74,6 +74,7 @@ class Group(enum.Enum): CHEFSANITY_FRIENDSHIP = enum.auto() CHEFSANITY_SKILL = enum.auto() CRAFTSANITY = enum.auto() + REQUIRES_MUSEUM = enum.auto() # Mods MAGIC_SPELL = enum.auto() @@ -649,6 +650,8 @@ def remove_excluded_items(packs, exclude_ginger_island: bool): included_packs = [pack for pack in packs if Group.DEPRECATED not in pack.groups] if exclude_ginger_island: included_packs = [pack for pack in included_packs if Group.GINGER_ISLAND not in pack.groups] + if world_options[options.Museumsanity] == options.Museumsanity.option_none: + included_packs = [pack for pack in included_packs if Group.REQUIRES_MUSEUM not in pack.groups] return included_packs diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 6c0524c7620d..d1495d852b93 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -507,6 +507,7 @@ def test_can_craft_festival_recipe(self): class TestNoCraftsanityLogic(SVTestBase): options = { options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, options.Craftsanity.internal_name: options.Craftsanity.option_none, @@ -522,9 +523,10 @@ 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) rule = self.world.logic.crafting.can_craft(recipe) - self.assertFalse(rule(self.multiworld.state)) + result = rule(self.multiworld.state) + self.assertFalse(result) - self.multiworld.state.collect(self.world.create_item("Fall"), event=False) + self.collect([self.world.create_item("Progressive Season")] * 2) self.assertTrue(rule(self.multiworld.state)) From cea75e6b5b4b70a9700e0f9788bbaafbc2fb53c4 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 27 Sep 2023 19:13:28 -0400 Subject: [PATCH 081/482] - Got rid of the concept of "requires museum", as it's easy to give a rusty key anyway # Conflicts: # worlds/stardew_valley/items.py --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 32 +++++++++---------- worlds/stardew_valley/items.py | 9 +----- worlds/stardew_valley/logic/wallet_logic.py | 9 +----- worlds/stardew_valley/test/TestGeneration.py | 4 +-- worlds/stardew_valley/test/__init__.py | 3 ++ .../test/checks/world_checks.py | 4 ++- .../test/long/TestOptionsLong.py | 12 ++++++- 8 files changed, 38 insertions(+), 37 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 40302115f012..48344c9d0c0a 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -406,7 +406,7 @@ id,name,classification,groups,mod_name 430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", 431,Straw Floor Recipe,progression,"CRAFTSANITY", 432,Weathered Floor Recipe,progression,"CRAFTSANITY", -433,Crystal Floor Recipe,progression,"CRAFTSANITY,REQUIRES_MUSEUM", +433,Crystal Floor Recipe,progression,"CRAFTSANITY", 434,Stone Floor Recipe,progression,"CRAFTSANITY", 435,Stone Walkway Floor Recipe,progression,"CRAFTSANITY", 436,Brick Floor Recipe,progression,"CRAFTSANITY", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 7b715abfb706..588db4bc6f87 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -213,7 +213,7 @@ id,region,name,tags,mod_name 543,Desert,Exotic Spirits,"MANDATORY,QUEST", 544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", 545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Railroad,Dark Talisman,"MANDATORY,QUEST,REQUIRES_MUSEUM", +546,Railroad,Dark Talisman,"MANDATORY,QUEST", 547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", 548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", 601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", @@ -781,16 +781,16 @@ id,region,name,tags,mod_name 1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, 1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, 1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY,REQUIRES_MUSEUM", -1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY,REQUIRES_MUSEUM", +1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY", +1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY", +1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY", +1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY", +1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY", +1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY", +1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY", +1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY", +1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY", +1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY", 1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", 1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", 1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", @@ -1203,7 +1203,7 @@ id,region,name,tags,mod_name 2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, 2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, 2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,"SHIPSANITY,REQUIRES_MUSEUM", +2560,Shipping,Shipsanity: Crystal Floor,"SHIPSANITY", 2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, 2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, 2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, @@ -1905,7 +1905,7 @@ id,region,name,tags,mod_name 3439,Farm,Craft Rustic Plank Floor,"CRAFTSANITY", 3440,Farm,Craft Straw Floor,"CRAFTSANITY", 3441,Farm,Craft Weathered Floor,"CRAFTSANITY", -3442,Farm,Craft Crystal Floor,"CRAFTSANITY,REQUIRES_MUSEUM", +3442,Farm,Craft Crystal Floor,"CRAFTSANITY", 3443,Farm,Craft Stone Floor,"CRAFTSANITY", 3444,Farm,Craft Stone Walkway Floor,"CRAFTSANITY", 3445,Farm,Craft Brick Floor,"CRAFTSANITY", @@ -1974,7 +1974,7 @@ id,region,name,tags,mod_name 3508,Farm,Craft Tapper,"CRAFTSANITY", 3509,Farm,Craft Worm Bin,"CRAFTSANITY", 3510,Farm,Craft Tub o' Flowers,"CRAFTSANITY", -3511,Farm,Craft Wicked Statue,"CRAFTSANITY,REQUIRES_MUSEUM", +3511,Farm,Craft Wicked Statue,"CRAFTSANITY", 3512,Farm,Craft Flute Block,"CRAFTSANITY", 3513,Farm,Craft Drum Block,"CRAFTSANITY", 3514,Farm,Craft Chest,"CRAFTSANITY", @@ -1999,7 +1999,7 @@ id,region,name,tags,mod_name 3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", 3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", 3555,Mines Dwarf Shop,Weathered Floor Recipe,"CRAFTSANITY", -3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY,REQUIRES_MUSEUM", +3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY", 3557,Carpenter Shop,Stone Floor Recipe,"CRAFTSANITY", 3558,Carpenter Shop,Stone Walkway Floor Recipe,"CRAFTSANITY", 3559,Carpenter Shop,Brick Floor Recipe,"CRAFTSANITY", @@ -2017,7 +2017,7 @@ id,region,name,tags,mod_name 3571,Carpenter Shop,Marble Brazier Recipe,"CRAFTSANITY", 3572,Carpenter Shop,Wood Lamp-post Recipe,"CRAFTSANITY", 3573,Carpenter Shop,Iron Lamp-post Recipe,"CRAFTSANITY", -3574,Sewer,Wicked Statue Recipe,"CRAFTSANITY,REQUIRES_MUSEUM", +3574,Sewer,Wicked Statue Recipe,"CRAFTSANITY", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 83ee7a615dfc..d340826beef2 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -74,7 +74,6 @@ class Group(enum.Enum): CHEFSANITY_FRIENDSHIP = enum.auto() CHEFSANITY_SKILL = enum.auto() CRAFTSANITY = enum.auto() - REQUIRES_MUSEUM = enum.auto() # Mods MAGIC_SPELL = enum.auto() @@ -270,15 +269,11 @@ def create_tools(item_factory: StardewItemFactory, world_options: StardewOptions def create_skills(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - needs_level_10 = world_is_perfection(world_options) or world_options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_disabled if world_options[options.SkillProgression] == options.SkillProgression.option_progressive: for item in items_by_group[Group.SKILL_LEVEL_UP]: if item.mod_name not in options.mods and item.mod_name is not None: continue - level_progression = 10 if needs_level_10 else 9 - level_useful = 10 - level_progression - items.extend(item_factory(item) for item in [item.name] * level_progression) - items.extend(item_factory(item, ItemClassification.useful) for item in [item.name] * level_useful) + items.extend(item_factory(item) for item in [item.name] * 10) def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -650,8 +645,6 @@ def remove_excluded_items(packs, exclude_ginger_island: bool): included_packs = [pack for pack in packs if Group.DEPRECATED not in pack.groups] if exclude_ginger_island: included_packs = [pack for pack in included_packs if Group.GINGER_ISLAND not in pack.groups] - if world_options[options.Museumsanity] == options.Museumsanity.option_none: - included_packs = [pack for pack in included_packs if Group.REQUIRES_MUSEUM not in pack.groups] return included_packs diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index b661f2386428..98c3f461d479 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,7 +1,5 @@ from .museum_logic import MuseumLogic -from .. import options -from ..data.museum_data import dwarf_scrolls, all_museum_items -from ..stardew_rule import StardewRule, And +from ..stardew_rule import StardewRule from .received_logic import ReceivedLogic from ..strings.wallet_item_names import Wallet @@ -17,12 +15,7 @@ def __init__(self, player: int, received: ReceivedLogic, museum: MuseumLogic): self.museum = museum def can_speak_dwarf(self) -> StardewRule: - if self.museum.museum_option == options.Museumsanity.option_none: - return And([self.museum.can_donate_museum_item(item) for item in dwarf_scrolls]) return self.received("Dwarvish Translation Guide") def has_rusty_key(self) -> StardewRule: - if self.museum.museum_option == options.Museumsanity.option_none: - required_donations = 80 # It's 60, but without a metal detector I'd rather overshoot so players don't get screwed by RNG - return self.museum.can_donate_many([item.name for item in all_museum_items], required_donations) return self.received(Wallet.rusty_key) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 3fb6b442d3bb..0e0ccc730db8 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -292,7 +292,7 @@ def test_minimal_location_maximal_items_still_valid(self): print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items}") def test_minsanity_has_fewer_than_locations(self): - expected_locations = 122 + expected_locations = 123 minsanity_options = get_minsanity_options() multiworld = setup_solo_multiworld(minsanity_options) real_locations = get_real_locations(self, multiworld) @@ -300,7 +300,7 @@ def test_minsanity_has_fewer_than_locations(self): self.assertLessEqual(number_locations, expected_locations) print(f"Stardew Valley - Minsanity Locations: {number_locations}") if number_locations != expected_locations: - print(f"\tNew locations detected!" + print(f"\tDisappeared Locations Detected!" f"\n\tPlease update test_minsanity_has_fewer_than_locations" f"\n\t\tExpected: {expected_locations}" f"\n\t\tActual: {number_locations}") diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index f9e34c6bdcf3..43e5c7d4a9ef 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -35,6 +35,9 @@ def get_minsanity_options(): options.Museumsanity.internal_name: options.Museumsanity.option_none, options.Monstersanity.internal_name: options.Monstersanity.option_none, options.Shipsanity.internal_name: options.Shipsanity.option_none, + options.Cooksanity.internal_name: options.Cooksanity.option_none, + options.Chefsanity.internal_name: options.Chefsanity.option_none, + options.Craftsanity.internal_name: options.Craftsanity.option_none, options.Friendsanity.internal_name: options.Friendsanity.option_none, options.FriendsanityHeartSize.internal_name: 8, options.NumberOfMovementBuffs.internal_name: 0, diff --git a/worlds/stardew_valley/test/checks/world_checks.py b/worlds/stardew_valley/test/checks/world_checks.py index 9bd9fd614c26..5ee20534b3e3 100644 --- a/worlds/stardew_valley/test/checks/world_checks.py +++ b/worlds/stardew_valley/test/checks/world_checks.py @@ -20,7 +20,9 @@ def assert_victory_exists(tester: unittest.TestCase, multiworld: MultiWorld): def collect_all_then_assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): for item in multiworld.get_items(): multiworld.state.collect(item) - tester.assertTrue(multiworld.find_item("Victory", 1).can_reach(multiworld.state)) + victory = multiworld.find_item("Victory", 1) + can_win = victory.can_reach(multiworld.state) + tester.assertTrue(can_win) def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index e3da6968ed43..5ead8f0e0767 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -38,4 +38,14 @@ def test_given_option_pair_when_generate_then_basic_checks(self): choices = {option1.internal_name: option1_choices[key1], option2.internal_name: option2_choices[key2]} multiworld = setup_solo_multiworld(choices) - basic_checks(self, multiworld) \ No newline at end of file + basic_checks(self, multiworld) + + +class TestDynamicOptionDebug(SVTestBase): + options = { + "goal": "full_shipment", + "museumsanity": "none" + } + + def test_option_pair_debug(self): + basic_checks(self, self.multiworld) From 720f938f0e0f5975557feb4cba1475240060ec15 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 28 Sep 2023 15:56:30 -0400 Subject: [PATCH 082/482] - Removed the last friendship heart being not progression, as that messes with recipes and stuff --- worlds/stardew_valley/items.py | 22 ------------------- worlds/stardew_valley/logic/logic.py | 5 ++--- .../test/long/TestOptionsLong.py | 4 ++-- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index d340826beef2..b610b2a280db 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -359,10 +359,6 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S exclude_ginger_island = world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true mods = world_options[options.Mods] heart_size = world_options[options.FriendsanityHeartSize] - need_all_hearts_up_to_date = world_is_perfection(world_options) - government_assigned_bachelor = random.choice([villager.name for villager in all_villagers if villager.bachelor and - (villager.mod_name is None or villager.mod_name in mods)]) - need_recipes = world_options[options.Shipsanity] == options.Shipsanity.option_everything for villager in all_villagers: if villager.mod_name not in mods and villager.mod_name is not None: continue @@ -381,9 +377,6 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S break if heart % heart_size == 0 or heart == heart_cap: items.append(item_factory(f"{villager.name} <3", classification)) - if should_next_hearts_be_useful(need_all_hearts_up_to_date, government_assigned_bachelor, need_recipes, - villager, heart, heart_size, heart_cap): - classification = ItemClassification.useful if not exclude_non_bachelors: need_pet = world_options[options.Goal] == options.Goal.option_grandpa_evaluation for heart in range(1, 6): @@ -391,21 +384,6 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S items.append(item_factory(f"Pet <3", ItemClassification.progression_skip_balancing if need_pet else ItemClassification.useful)) -def should_next_hearts_be_useful(need_all_hearts_up_to_date: bool, government_assigned_bachelor: str, need_recipes: bool, villager, heart: int, - heart_size: int, heart_cap: int) -> bool: - if heart + heart_size < heart_cap: # If the next heart isn't the last one, it has to be progression - return False - if villager.name == government_assigned_bachelor: - return False - if need_all_hearts_up_to_date and (heart <= 8 or (heart <= 10 and not villager.bachelor)): - return False - if need_recipes and heart <= 7: - return False - if need_recipes and villager.name == "Willy": - return False - return True - - def create_babies(item_factory: StardewItemFactory, items: List[Item], random: Random): baby_items = [item for item in items_by_group[Group.BABY]] for i in range(2): diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index b5f3725809bb..5d8d36f35435 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -192,10 +192,9 @@ def __post_init__(self): self.seed_rules.update({seed.name: self.can_buy_seed(seed) for seed in all_purchasable_seeds}) self.crop_rules.update({crop.name: self.crop.can_grow(crop) for crop in all_crops}) self.crop_rules.update({ - Seed.coffee: (self.season.has(Season.spring) | self.season.has( - Season.summer)) & self.can_buy_seed(crops_by_name[Seed.coffee].seed), + Seed.coffee: (self.season.has(Season.spring) | self.season.has(Season.summer)) & self.can_buy_seed(crops_by_name[Seed.coffee].seed), Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & - self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), + self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), }) self.item_rules.update({ diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index 5ead8f0e0767..4e46cf2e0207 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -43,8 +43,8 @@ def test_given_option_pair_when_generate_then_basic_checks(self): class TestDynamicOptionDebug(SVTestBase): options = { - "goal": "full_shipment", - "museumsanity": "none" + "goal": "gourmet_chef", + "friendsanity": "bachelors" } def test_option_pair_debug(self): From 7834b98785199d25f6ea77fa56794a909f6ff398 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 28 Sep 2023 16:48:16 -0400 Subject: [PATCH 083/482] - Grass starter recipe is at Pierre --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 588db4bc6f87..02b95b295de3 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1994,7 +1994,7 @@ id,region,name,tags,mod_name 3528,Farm,Craft Farm Computer,"CRAFTSANITY", 3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", 3530,Farm,Craft Cookout Kit,"CRAFTSANITY", -3551,Carpenter Shop,Grass Starter Recipe,"CRAFTSANITY", +3551,Pierre's General Store,Grass Starter Recipe,"CRAFTSANITY", 3552,Carpenter Shop,Wood Floor Recipe,"CRAFTSANITY", 3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", 3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", From 3ea73aa02ca74d34984a3ab074e66952aac4b5f8 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 29 Sep 2023 12:28:26 -0400 Subject: [PATCH 084/482] - Added the moonlight jellies shop items --- worlds/stardew_valley/data/items.csv | 4 +-- worlds/stardew_valley/data/locations.csv | 2 ++ .../test/checks/option_checks.py | 36 +++++++++++++++++-- .../test/long/TestRandomWorlds.py | 18 +++++----- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 48344c9d0c0a..528a15b58889 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -317,6 +317,8 @@ id,name,classification,groups,mod_name 332,Fiber Seeds Recipe,progression,"SPECIAL_ORDER_BOARD", 333,Tub o' Flowers Recipe,progression,"FESTIVAL", 334,Quality Bobber Recipe,progression,"SPECIAL_ORDER_BOARD", +335,Moonlight Jellies Banner,filler,FESTIVAL, +336,Starport Decal,filler,FESTIVAL, 337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", @@ -435,8 +437,6 @@ id,name,classification,groups,mod_name 459,Chest Recipe,progression,"CRAFTSANITY", 460,Wood Sign Recipe,progression,"CRAFTSANITY", 461,Stone Sign Recipe,progression,"CRAFTSANITY", -480,Moonlight Jellies Banner,filler,FESTIVAL, -481,Starport Decal,filler,FESTIVAL, 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 02b95b295de3..6d237f98b4cc 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -953,6 +953,8 @@ id,region,name,tags,mod_name 2031,Farm,Collect All Rarecrows,FESTIVAL, 2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, 2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, +2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, +2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, 2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, diff --git a/worlds/stardew_valley/test/checks/option_checks.py b/worlds/stardew_valley/test/checks/option_checks.py index c9d9860cf52b..358be9f1bea0 100644 --- a/worlds/stardew_valley/test/checks/option_checks.py +++ b/worlds/stardew_valley/test/checks/option_checks.py @@ -18,6 +18,26 @@ def get_stardew_options(multiworld: MultiWorld) -> options.StardewValleyOptions: return get_stardew_world(multiworld).options +def assert_has_item(tester: SVTestBase, multiworld: MultiWorld, item: str): + all_item_names = set(get_all_item_names(multiworld)) + tester.assertIn(item, all_item_names) + + +def assert_has_not_item(tester: SVTestBase, multiworld: MultiWorld, item: str): + all_item_names = set(get_all_item_names(multiworld)) + tester.assertNotIn(item, all_item_names) + + +def assert_has_location(tester: SVTestBase, multiworld: MultiWorld, item: str): + all_location_names = set(get_all_location_names(multiworld)) + tester.assertIn(item, all_location_names) + + +def assert_has_not_location(tester: SVTestBase, multiworld: MultiWorld, item: str): + all_location_names = set(get_all_location_names(multiworld)) + tester.assertNotIn(item, all_location_names) + + def assert_can_reach_island(tester: SVTestBase, multiworld: MultiWorld): all_item_names = get_all_item_names(multiworld) tester.assertIn(Transportation.boat_repair, all_item_names) @@ -58,8 +78,7 @@ def assert_all_rarecrows_exist(tester: SVTestBase, multiworld: MultiWorld): def assert_has_deluxe_scarecrow_recipe(tester: SVTestBase, multiworld: MultiWorld): - all_item_names = set(get_all_item_names(multiworld)) - tester.assertIn(f"Deluxe Scarecrow Recipe", all_item_names) + assert_has_item(tester, multiworld, "Deluxe Scarecrow Recipe") def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestBase, multiworld: MultiWorld): @@ -70,3 +89,16 @@ def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestBase, multiwo assert_all_rarecrows_exist(tester, multiworld) assert_has_deluxe_scarecrow_recipe(tester, multiworld) + + +def assert_has_festival_recipes(tester: SVTestBase, multiworld: MultiWorld): + has_festivals = is_not_setting(multiworld, options.FestivalLocations.internal_name, options.FestivalLocations.option_disabled) + festival_items = ["Tub o' Flowers Recipe", "Jack-O-Lantern Recipe", "Moonlight Jellies Banner", "Starport Decal"] + for festival_item in festival_items: + if has_festivals: + assert_has_item(tester, multiworld, festival_item) + assert_has_location(tester, multiworld, festival_item) + else: + assert_has_not_item(tester, multiworld, festival_item) + assert_has_not_location(tester, multiworld, festival_item) + diff --git a/worlds/stardew_valley/test/long/TestRandomWorlds.py b/worlds/stardew_valley/test/long/TestRandomWorlds.py index 1f1d59652c5e..35e4fec22c9d 100644 --- a/worlds/stardew_valley/test/long/TestRandomWorlds.py +++ b/worlds/stardew_valley/test/long/TestRandomWorlds.py @@ -7,7 +7,7 @@ from .. import setup_solo_multiworld, SVTestCase from ..checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid from ..checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ - assert_festivals_give_access_to_deluxe_scarecrow + assert_festivals_give_access_to_deluxe_scarecrow, assert_has_festival_recipes from ..checks.world_checks import assert_same_number_items_locations, assert_victory_exists @@ -57,18 +57,20 @@ def get_number_log_steps(number_worlds: int) -> int: return 100 -def generate_many_worlds(number_worlds: int, start_index: int) -> Dict[int, MultiWorld]: +def generate_and_check_many_worlds(tester: SVTestBase, number_worlds: int, start_index: int) -> Dict[int, MultiWorld]: num_steps = get_number_log_steps(number_worlds) log_step = number_worlds / num_steps multiworlds = dict() print(f"Generating {number_worlds} Solo Multiworlds [Start Seed: {start_index}] for Stardew Valley...") for world_number in range(0, number_worlds + 1): world_id = world_number + start_index - multiworld = generate_random_multiworld(world_id) - multiworlds[world_id] = multiworld + with tester.subTest(f"Multiworld: {world_id}"): + multiworld = generate_random_multiworld(world_id) + multiworlds[world_id] = multiworld + check_multiworld_is_valid(tester, world_id, multiworld) if world_number > 0 and world_number % log_step == 0: - print(f"Generated {world_number}/{number_worlds} worlds [{(world_number * 100) // number_worlds}%]") - print(f"Finished generating {number_worlds} Solo Multiworlds for Stardew Valley") + print(f"Generated and Verified {world_number}/{number_worlds} worlds [{(world_number * 100) // number_worlds}%]") + print(f"Finished generating and verifying {number_worlds} Solo Multiworlds for Stardew Valley") return multiworlds @@ -86,6 +88,7 @@ def check_multiworld_is_valid(tester: SVTestCase, multiworld_id: int, multiworld assert_can_reach_island_if_should(tester, multiworld) assert_cropsanity_same_number_items_and_locations(tester, multiworld) assert_festivals_give_access_to_deluxe_scarecrow(tester, multiworld) + assert_has_festival_recipes(tester, multiworld) class TestGenerateManyWorlds(SVTestCase): @@ -94,5 +97,4 @@ def test_generate_many_worlds_then_check_results(self): return number_worlds = 1000 start_index = random.Random().randint(0, 9999999999) - multiworlds = generate_many_worlds(number_worlds, start_index) - check_every_multiworld_is_valid(self, multiworlds) + multiworlds = generate_and_check_many_worlds(self, number_worlds, start_index) From 6e50070750eda22df7af4020cfdbaaea746182e7 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 11 Oct 2023 13:39:51 -0400 Subject: [PATCH 085/482] - Fixes after big rebase from 993 # Conflicts: # worlds/stardew_valley/test/TestRules.py --- worlds/stardew_valley/__init__.py | 18 +- worlds/stardew_valley/items.py | 143 ++--- worlds/stardew_valley/locations.py | 133 +++-- worlds/stardew_valley/logic/ability_logic.py | 9 +- worlds/stardew_valley/logic/arcade_logic.py | 5 +- worlds/stardew_valley/logic/building_logic.py | 14 +- worlds/stardew_valley/logic/cooking_logic.py | 27 +- worlds/stardew_valley/logic/crafting_logic.py | 15 +- worlds/stardew_valley/logic/logic.py | 65 ++- worlds/stardew_valley/logic/mine_logic.py | 15 +- worlds/stardew_valley/logic/money_logic.py | 9 +- worlds/stardew_valley/logic/museum_logic.py | 5 +- worlds/stardew_valley/logic/pet_logic.py | 9 +- .../logic/relationship_logic.py | 21 +- worlds/stardew_valley/logic/season_logic.py | 10 +- worlds/stardew_valley/logic/shipping_logic.py | 13 +- worlds/stardew_valley/logic/skill_logic.py | 9 +- worlds/stardew_valley/logic/tool_logic.py | 9 +- .../mods/logic/buildings_logic.py | 5 +- .../mods/logic/deepwoods_logic.py | 12 +- .../mods/logic/elevator_logic.py | 9 +- .../stardew_valley/mods/logic/magic_logic.py | 5 +- worlds/stardew_valley/mods/logic/mod_logic.py | 3 +- .../mods/logic/mod_skills_levels.py | 3 +- .../stardew_valley/mods/logic/quests_logic.py | 7 +- .../stardew_valley/mods/logic/skills_logic.py | 10 +- .../mods/logic/special_orders_logic.py | 5 +- worlds/stardew_valley/options.py | 10 +- worlds/stardew_valley/rules.py | 522 +++++++++--------- worlds/stardew_valley/test/TestGeneration.py | 106 ++-- worlds/stardew_valley/test/TestOptionFlags.py | 64 +-- worlds/stardew_valley/test/TestRegions.py | 4 +- worlds/stardew_valley/test/TestRules.py | 202 +++---- worlds/stardew_valley/test/__init__.py | 67 +-- .../stardew_valley/test/checks/goal_checks.py | 2 +- .../test/checks/option_checks.py | 2 +- .../test/mods/TestBiggerBackpack.py | 14 +- worlds/stardew_valley/test/mods/TestMods.py | 31 +- 38 files changed, 786 insertions(+), 826 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index d38a98d73855..36183a384110 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -18,7 +18,7 @@ from worlds.generic.Rules import set_rule from .stardew_rule import True_, StardewRule from .strings.ap_names.event_names import Event -from .strings.goal_names import Goal +from .strings.goal_names import Goal as GoalName client_version = 0 @@ -216,20 +216,20 @@ def setup_victory(self): self.create_event_location(location_table[GoalName.greatest_walnut_hunter], self.logic.has_walnut(130).simplify(), Event.victory) - elif self.options[options.Goal] == options.Goal.option_protector_of_the_valley: - self.create_event_location(location_table[Goal.protector_of_the_valley], + elif self.options.goal == options.Goal.option_protector_of_the_valley: + self.create_event_location(location_table[GoalName.protector_of_the_valley], self.logic.can_complete_all_monster_slaying_goals().simplify(), Event.victory) - elif self.options[options.Goal] == options.Goal.option_full_shipment: - self.create_event_location(location_table[Goal.full_shipment], + elif self.options.goal == options.Goal.option_full_shipment: + self.create_event_location(location_table[GoalName.full_shipment], self.logic.shipping.can_ship_everything().simplify(), Event.victory) - elif self.options[options.Goal] == options.Goal.option_gourmet_chef: - self.create_event_location(location_table[Goal.gourmet_chef], + elif self.options.goal == options.Goal.option_gourmet_chef: + self.create_event_location(location_table[GoalName.gourmet_chef], self.logic.cooking.can_cook_everything().simplify(), Event.victory) - elif self.options[options.Goal] == options.Goal.option_perfection: - self.create_event_location(location_table[Goal.perfection], + elif self.options.goal == options.Goal.option_perfection: + self.create_event_location(location_table[GoalName.perfection], self.logic.has_everything(self.all_progression_items).simplify(), Event.victory) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index b610b2a280db..be0c1f74fea9 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -10,8 +10,10 @@ from . import data from .data.villagers_data import all_villagers from .mods.mod_data import ModNames -from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, Friendsanity, Museumsanity, \ - Fishsanity, BuildingProgression, SkillProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations +from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, \ + Friendsanity, Museumsanity, \ + Fishsanity, BuildingProgression, SkillProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations, Monstersanity, Goal, \ + Shipsanity, Chefsanity, Craftsanity from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff from .strings.ap_names.event_names import Event @@ -181,7 +183,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items.append(item_factory("Progressive Movie Theater")) # It is a community reward, but we need two of them create_backpack_items(item_factory, options, items) - create_weapons(item_factory, world_options, items) + create_weapons(item_factory, options, items) items.append(item_factory("Skull Key")) create_elevators(item_factory, options, items) create_tools(item_factory, options, items) @@ -198,17 +200,17 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_player_buffs(item_factory, options, items) create_traveling_merchant_items(item_factory, items) items.append(item_factory("Return Scepter")) - create_seasons(item_factory, world_options, items) - create_seeds(item_factory, world_options, items) - create_friendsanity_items(item_factory, world_options, items, random) - create_festival_rewards(item_factory, world_options, items) + create_seasons(item_factory, options, items) + create_seeds(item_factory, options, items) + create_friendsanity_items(item_factory, options, items, random) + create_festival_rewards(item_factory, options, items) create_babies(item_factory, items, random) - create_special_order_board_rewards(item_factory, world_options, items) - create_special_order_qi_rewards(item_factory, world_options, items) - create_walnut_purchase_rewards(item_factory, world_options, items) - create_crafting_recipes(item_factory, world_options, items) - create_cooking_recipes(item_factory, world_options, items) - create_magic_mod_spells(item_factory, world_options, items) + create_special_order_board_rewards(item_factory, options, items) + create_special_order_qi_rewards(item_factory, options, items) + create_walnut_purchase_rewards(item_factory, options, items) + create_crafting_recipes(item_factory, options, items) + create_cooking_recipes(item_factory, options, items) + create_magic_mod_spells(item_factory, options, items) items.append(item_factory("Golden Egg")) return items @@ -222,11 +224,10 @@ def create_backpack_items(item_factory: StardewItemFactory, options: StardewVall items.append(item_factory("Progressive Backpack")) -def create_weapons(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): +def create_weapons(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): items.extend(item_factory(item) for item in [APWeapon.slingshot] * 2) - monstersanity = options.Monstersanity - monstersanity_option = world_options[monstersanity] - if monstersanity_option == options.Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons + monstersanity = options.monstersanity + if monstersanity == Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons items.extend(item_factory(item) for item in [APWeapon.weapon] * 5) items.extend(item_factory(item) for item in [APWeapon.footwear] * 3) # 1-2 | 3-4 | 6-7-8 return @@ -235,18 +236,18 @@ def create_weapons(item_factory: StardewItemFactory, world_options: StardewOptio items.extend(item_factory(item) for item in [APWeapon.club] * 5) items.extend(item_factory(item) for item in [APWeapon.dagger] * 5) items.extend(item_factory(item) for item in [APWeapon.footwear] * 4) # 1-2 | 3-4 | 6-7-8 | 11-13 - if monstersanity_option == monstersanity.option_goals or monstersanity_option == monstersanity.option_one_per_category or \ - monstersanity_option == monstersanity.option_short_goals or monstersanity_option == monstersanity.option_very_short_goals: + if monstersanity == Monstersanity.option_goals or monstersanity == Monstersanity.option_one_per_category or \ + monstersanity == Monstersanity.option_short_goals or monstersanity == Monstersanity.option_very_short_goals: return - if world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + if options.exclude_ginger_island == ExcludeGingerIsland.option_true: rings_items = [item for item in items_by_group[Group.RING] if item.classification is not ItemClassification.filler] else: rings_items = [item for item in items_by_group[Group.RING]] items.extend(item_factory(item) for item in rings_items) -def create_elevators(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - if world_options[options.ElevatorProgression] == options.ElevatorProgression.option_vanilla: +def create_elevators(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if options.elevator_progression == ElevatorProgression.option_vanilla: return items.extend([item_factory(item) for item in ["Progressive Mine Elevator"] * 24]) @@ -256,8 +257,8 @@ def create_elevators(item_factory: StardewItemFactory, world_options: StardewOpt items.extend([item_factory(item) for item in ["Progressive Skull Cavern Elevator"] * 8]) -def create_tools(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - if world_options[options.ToolProgression] & options.ToolProgression.option_progressive: +def create_tools(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if options.tool_progression & ToolProgression.option_progressive: for item_data in items_by_group[Group.PROGRESSIVE_TOOLS]: name = item_data.name if "Trash Can" in name: @@ -268,8 +269,8 @@ def create_tools(item_factory: StardewItemFactory, world_options: StardewOptions items.append(item_factory("Golden Scythe")) -def create_skills(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - if world_options[options.SkillProgression] == options.SkillProgression.option_progressive: +def create_skills(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if options.skill_progression == SkillProgression.option_progressive: for item in items_by_group[Group.SKILL_LEVEL_UP]: if item.mod_name not in options.mods and item.mod_name is not None: continue @@ -277,7 +278,7 @@ def create_skills(item_factory: StardewItemFactory, world_options: StardewOption def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - useless_buildings_classification = ItemClassification.progression_skip_balancing if world_is_perfection(world_options) else ItemClassification.useful + useless_buildings_classification = ItemClassification.progression_skip_balancing if world_is_perfection(options) else ItemClassification.useful items.append(item_factory("Earth Obelisk", useless_buildings_classification)) items.append(item_factory("Water Obelisk", useless_buildings_classification)) items.append(item_factory("Desert Obelisk")) @@ -289,9 +290,9 @@ def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewVa items.append(item_factory("Woods Obelisk")) -def create_carpenter_buildings(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - building_option = world_options[options.BuildingProgression] - if not building_option & options.BuildingProgression.option_progressive: +def create_carpenter_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + building_option = options.building_progression + if not building_option & BuildingProgression.option_progressive: return items.append(item_factory("Progressive Coop")) items.append(item_factory("Progressive Coop")) @@ -307,14 +308,14 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, world_options: items.append(item_factory("Fish Pond")) items.append(item_factory("Stable")) items.append(item_factory("Slime Hutch")) - needs_early_bin = building_option & options.BuildingProgression.option_progressive_early_shipping_bin - has_shipsanity = world_options[options.Shipsanity] != options.Shipsanity.option_none - need_shipping = needs_early_bin or has_shipsanity or world_is_perfection(world_options) + needs_early_bin = building_option & BuildingProgression.option_progressive_early_shipping_bin + has_shipsanity = options.shipsanity != Shipsanity.option_none + need_shipping = needs_early_bin or has_shipsanity or world_is_perfection(options) items.append(item_factory("Shipping Bin", ItemClassification.progression if need_shipping else ItemClassification.useful)) items.append(item_factory("Progressive House")) items.append(item_factory("Progressive House")) items.append(item_factory("Progressive House")) - if ModNames.tractor in world_options[options.Mods]: + if ModNames.tractor in options.mods: items.append(item_factory("Tractor Garage")) @@ -328,7 +329,7 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[I def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - stardrops_classification = get_stardrop_classification(world_options) + stardrops_classification = get_stardrop_classification(options) items.append(item_factory("Stardrop", stardrops_classification)) # The Mines level 100 items.append(item_factory("Stardrop", stardrops_classification)) # Old Master Cannoli if options.fishsanity != Fishsanity.option_none: @@ -346,19 +347,19 @@ def create_museum_items(item_factory: StardewItemFactory, options: StardewValley items.extend(item_factory(item) for item in ["Magic Rock Candy"] * 10) items.extend(item_factory(item) for item in ["Ancient Seeds"] * 5) items.extend(item_factory(item) for item in ["Traveling Merchant Metal Detector"] * 4) - items.append(item_factory("Stardrop", get_stardrop_classification(world_options))) + items.append(item_factory("Stardrop", get_stardrop_classification(options))) -def create_friendsanity_items(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item], random): - if world_options[options.Friendsanity] == options.Friendsanity.option_none: +def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item], random): + if options.friendsanity == Friendsanity.option_none: return - exclude_non_bachelors = world_options[options.Friendsanity] == options.Friendsanity.option_bachelors - exclude_locked_villagers = world_options[options.Friendsanity] == options.Friendsanity.option_starting_npcs or \ - world_options[options.Friendsanity] == options.Friendsanity.option_bachelors - include_post_marriage_hearts = world_options[options.Friendsanity] == options.Friendsanity.option_all_with_marriage - exclude_ginger_island = world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true - mods = world_options[options.Mods] - heart_size = world_options[options.FriendsanityHeartSize] + exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors + exclude_locked_villagers = options.friendsanity == Friendsanity.option_starting_npcs or \ + options.friendsanity == Friendsanity.option_bachelors + include_post_marriage_hearts = options.friendsanity == Friendsanity.option_all_with_marriage + exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true + mods = options.mods + heart_size = options.friendsanity_heart_size for villager in all_villagers: if villager.mod_name not in mods and villager.mod_name is not None: continue @@ -378,7 +379,7 @@ def create_friendsanity_items(item_factory: StardewItemFactory, world_options: S if heart % heart_size == 0 or heart == heart_cap: items.append(item_factory(f"{villager.name} <3", classification)) if not exclude_non_bachelors: - need_pet = world_options[options.Goal] == options.Goal.option_grandpa_evaluation + need_pet = options.goal == Goal.option_grandpa_evaluation for heart in range(1, 6): if heart % heart_size == 0 or heart == 5: items.append(item_factory(f"Pet <3", ItemClassification.progression_skip_balancing if need_pet else ItemClassification.useful)) @@ -408,11 +409,11 @@ def create_arcade_machine_items(item_factory: StardewItemFactory, options: Stard items.extend(item_factory(item) for item in ["Junimo Kart: Extra Life"] * 8) -def create_player_buffs(item_factory: StardewItemFactory, world_options: options.StardewOptions, items: List[Item]): - movement_buffs: int = world_options[options.NumberOfMovementBuffs] - luck_buffs: int = world_options[options.NumberOfLuckBuffs] - need_all_buffs = world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_qi - need_half_buffs = world_options[options.FestivalLocations] == options.FestivalLocations.option_easy +def create_player_buffs(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + movement_buffs: int = options.number_of_movement_buffs.value + luck_buffs: int = options.number_of_luck_buffs.value + need_all_buffs = options.special_order_locations == SpecialOrderLocations.option_board_qi + need_half_buffs = options.festival_locations == FestivalLocations.option_easy create_player_buff(item_factory, Buff.movement, movement_buffs, need_all_buffs, need_half_buffs, items) create_player_buff(item_factory, Buff.luck, luck_buffs, need_all_buffs, need_half_buffs, items) @@ -455,7 +456,7 @@ def create_festival_rewards(item_factory: StardewItemFactory, options: StardewVa return festival_rewards = [item_factory(item) for item in items_by_group[Group.FESTIVAL] if item.classification != ItemClassification.filler] - items.extend([*festival_rewards, item_factory("Stardrop", get_stardrop_classification(world_options))]) + items.extend([*festival_rewards, item_factory("Stardrop", get_stardrop_classification(options))]) def create_walnut_purchase_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -490,9 +491,9 @@ def special_order_board_item_classification(item: ItemData, need_all_recipes: bo return ItemClassification.useful -def create_special_order_qi_rewards(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - if (world_options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_board_qi or - world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true): +def create_special_order_qi_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if (options.special_order_locations != SpecialOrderLocations.option_board_qi or + options.exclude_ginger_island == ExcludeGingerIsland.option_true): return qi_gem_rewards = ["100 Qi Gems", "10 Qi Gems", "40 Qi Gems", "25 Qi Gems", "25 Qi Gems", "40 Qi Gems", "20 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems"] @@ -504,41 +505,41 @@ def create_tv_channels(item_factory: StardewItemFactory, items: List[Item]): items.extend([item_factory(item) for item in items_by_group[Group.TV_CHANNEL]]) -def create_crafting_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - has_shipsanity = world_options[options.Shipsanity] == options.Shipsanity.option_everything - has_craftsanity = world_options[options.Craftsanity] == options.Craftsanity.option_all +def create_crafting_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + has_shipsanity = options.shipsanity == Shipsanity.option_everything + has_craftsanity = options.craftsanity == Craftsanity.option_all need_qi_recipes = has_shipsanity or has_craftsanity crafting_recipes = [] if need_qi_recipes: crafting_recipes.extend([recipe for recipe in items_by_group[Group.QI_CRAFTING_RECIPE]]) if has_craftsanity: crafting_recipes.extend([recipe for recipe in items_by_group[Group.CRAFTSANITY]]) - crafting_recipes = remove_excluded_items(crafting_recipes, world_options) + crafting_recipes = remove_excluded_items(crafting_recipes, options) items.extend([item_factory(item) for item in crafting_recipes]) -def create_cooking_recipes(item_factory: StardewItemFactory, world_options: StardewOptions, items: List[Item]): - chefsanity = world_options[options.Chefsanity] - if chefsanity == options.Chefsanity.option_none: +def create_cooking_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + chefsanity = options.chefsanity + if chefsanity == Chefsanity.option_none: return chefsanity_recipes_by_name = {recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_STARTER]} # Dictionary to not make duplicates - if chefsanity & options.Chefsanity.option_queen_of_sauce: + if chefsanity & Chefsanity.option_queen_of_sauce: chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_QOS]}) - if chefsanity & options.Chefsanity.option_purchases: + if chefsanity & Chefsanity.option_purchases: chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_PURCHASE]}) - if chefsanity & options.Chefsanity.option_friendship: + if chefsanity & Chefsanity.option_friendship: chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_FRIENDSHIP]}) - if chefsanity & options.Chefsanity.option_skills: + if chefsanity & Chefsanity.option_skills: chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_SKILL]}) - filtered_chefsanity_recipes = remove_excluded_items(list(chefsanity_recipes_by_name.values()), world_options) + filtered_chefsanity_recipes = remove_excluded_items(list(chefsanity_recipes_by_name.values()), options) items.extend([item_factory(item) for item in filtered_chefsanity_recipes]) -def create_filler_festival_rewards(item_factory: StardewItemFactory, world_options: StardewOptions) -> List[Item]: - if world_options[options.FestivalLocations] == options.FestivalLocations.option_disabled: +def create_filler_festival_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions) -> List[Item]: + if options.festival_locations == FestivalLocations.option_disabled: return [] return [item_factory(item) for item in items_by_group[Group.FESTIVAL] if @@ -643,5 +644,5 @@ def get_stardrop_classification(world_options) -> ItemClassification: return ItemClassification.progression_skip_balancing if world_is_perfection(world_options) else ItemClassification.useful -def world_is_perfection(world_options) -> bool: - return world_options[options.Goal] == options.Goal.option_perfection +def world_is_perfection(options) -> bool: + return options.goal == Goal.option_perfection diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 48c41fc2fc2b..3825b9bb81f5 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -5,7 +5,7 @@ from typing import Optional, Dict, Protocol, List, FrozenSet from . import data -from .options import StardewValleyOptions +from .options import StardewValleyOptions, Craftsanity, Chefsanity, Cooksanity, Shipsanity, Monstersanity from .data.fish_data import legendary_fish, special_fish, all_fish from .data.museum_data import all_museum_items from .data.villagers_data import all_villagers @@ -184,27 +184,28 @@ def extend_help_wanted_quests(randomized_locations: List[LocationData], desired_ def extend_fishsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, random: Random): prefix = "Fishsanity: " - if options.fishsanity == Fishsanity.option_none: + fishsanity = options.fishsanity + if fishsanity == Fishsanity.option_none: return - elif options.fishsanity == Fishsanity.option_legendaries: + elif fishsanity == Fishsanity.option_legendaries: randomized_locations.extend(location_table[f"{prefix}{legendary.name}"] for legendary in legendary_fish) - elif options.fishsanity == Fishsanity.option_special: + elif fishsanity == Fishsanity.option_special: randomized_locations.extend(location_table[f"{prefix}{special.name}"] for special in special_fish) - elif options.fishsanity == Fishsanity.option_randomized: + elif fishsanity == Fishsanity.option_randomized: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if random.random() < 0.4] - randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) - elif world_options[options.Fishsanity] == options.Fishsanity.option_all: + randomized_locations.extend(filter_disabled_locations(options, fish_locations)) + elif fishsanity == Fishsanity.option_all: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish] - randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) - elif world_options[options.Fishsanity] == options.Fishsanity.option_exclude_legendaries: + randomized_locations.extend(filter_disabled_locations(options, fish_locations)) + elif fishsanity == Fishsanity.option_exclude_legendaries: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish not in legendary_fish] - randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) - elif world_options[options.Fishsanity] == options.Fishsanity.option_exclude_hard_fish: + randomized_locations.extend(filter_disabled_locations(options, fish_locations)) + elif fishsanity == Fishsanity.option_exclude_hard_fish: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish.difficulty < 80] - randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) - elif world_options[options.Fishsanity] == options.Fishsanity.option_only_easy_fish: + randomized_locations.extend(filter_disabled_locations(options, fish_locations)) + elif options.fishsanity == Fishsanity.option_only_easy_fish: fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish.difficulty < 50] - randomized_locations.extend(filter_disabled_locations(world_options, fish_locations)) + randomized_locations.extend(filter_disabled_locations(options, fish_locations)) def extend_museumsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, random: Random): @@ -316,86 +317,85 @@ def extend_elevator_locations(randomized_locations: List[LocationData], options: randomized_locations.extend(filtered_elevator_locations) -def extend_monstersanity_locations(randomized_locations: List[LocationData], world_options): - monstersanity = world_options[options.Monstersanity] - if monstersanity == options.Monstersanity.option_none: +def extend_monstersanity_locations(randomized_locations: List[LocationData], options): + monstersanity = options.monstersanity + if monstersanity == Monstersanity.option_none: return - if monstersanity == options.Monstersanity.option_one_per_monster or monstersanity == options.Monstersanity.option_split_goals: + if monstersanity == Monstersanity.option_one_per_monster or monstersanity == Monstersanity.option_split_goals: monster_locations = [location for location in locations_by_tag[LocationTags.MONSTERSANITY_MONSTER]] - filtered_monster_locations = filter_disabled_locations(world_options, monster_locations) + filtered_monster_locations = filter_disabled_locations(options, monster_locations) randomized_locations.extend(filtered_monster_locations) return goal_locations = [location for location in locations_by_tag[LocationTags.MONSTERSANITY_GOALS]] - filtered_goal_locations = filter_disabled_locations(world_options, goal_locations) + filtered_goal_locations = filter_disabled_locations(options, goal_locations) randomized_locations.extend(filtered_goal_locations) - if monstersanity != options.Monstersanity.option_progressive_goals: + if monstersanity != Monstersanity.option_progressive_goals: return progressive_goal_locations = [location for location in locations_by_tag[LocationTags.MONSTERSANITY_PROGRESSIVE_GOALS]] - filtered_progressive_goal_locations = filter_disabled_locations(world_options, progressive_goal_locations) + filtered_progressive_goal_locations = filter_disabled_locations(options, progressive_goal_locations) randomized_locations.extend(filtered_progressive_goal_locations) -def extend_shipsanity_locations(randomized_locations: List[LocationData], world_options): - shipsanity = world_options[options.Shipsanity] - if shipsanity == options.Shipsanity.option_none: +def extend_shipsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + shipsanity = options.shipsanity + if shipsanity == Shipsanity.option_none: return - if shipsanity == options.Shipsanity.option_everything: + if shipsanity == Shipsanity.option_everything: ship_locations = [location for location in locations_by_tag[LocationTags.SHIPSANITY]] - filtered_ship_locations = filter_disabled_locations(world_options, ship_locations) + filtered_ship_locations = filter_disabled_locations(options, ship_locations) randomized_locations.extend(filtered_ship_locations) return shipsanity_locations = set() - if shipsanity == options.Shipsanity.option_fish or shipsanity == options.Shipsanity.option_full_shipment_with_fish: + if shipsanity == Shipsanity.option_fish or shipsanity == Shipsanity.option_full_shipment_with_fish: shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_FISH]}) - if shipsanity == options.Shipsanity.option_crops: + if shipsanity == Shipsanity.option_crops: shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_CROP]}) - if shipsanity == options.Shipsanity.option_full_shipment or shipsanity == options.Shipsanity.option_full_shipment_with_fish: + if shipsanity == Shipsanity.option_full_shipment or shipsanity == Shipsanity.option_full_shipment_with_fish: shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]}) - filtered_shipsanity_locations = filter_disabled_locations(world_options, list(shipsanity_locations)) + filtered_shipsanity_locations = filter_disabled_locations(options, list(shipsanity_locations)) randomized_locations.extend(filtered_shipsanity_locations) -def extend_cooksanity_locations(randomized_locations: List[LocationData], world_options): - cooksanity = world_options[options.Cooksanity] - if cooksanity == options.Cooksanity.option_none: +def extend_cooksanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + cooksanity = options.cooksanity + if cooksanity == Cooksanity.option_none: return - if cooksanity == options.Cooksanity.option_queen_of_sauce: + if cooksanity == Cooksanity.option_queen_of_sauce: cooksanity_locations = {location for location in locations_by_tag[LocationTags.COOKSANITY_QOS]} else: cooksanity_locations = {location for location in locations_by_tag[LocationTags.COOKSANITY]} - filtered_cooksanity_locations = filter_disabled_locations(world_options, list(cooksanity_locations)) + filtered_cooksanity_locations = filter_disabled_locations(options, list(cooksanity_locations)) randomized_locations.extend(filtered_cooksanity_locations) -def extend_chefsanity_locations(randomized_locations: List[LocationData], world_options): - chefsanity = world_options[options.Chefsanity] - if chefsanity == options.Chefsanity.option_none: +def extend_chefsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + chefsanity = options.chefsanity + if chefsanity == Chefsanity.option_none: return chefsanity_locations_by_name = {} # Dictionary to not make duplicates - if chefsanity & options.Chefsanity.option_queen_of_sauce: + if chefsanity & Chefsanity.option_queen_of_sauce: chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_QOS]}) - if chefsanity & options.Chefsanity.option_purchases: + if chefsanity & Chefsanity.option_purchases: chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_PURCHASE]}) - if chefsanity & options.Chefsanity.option_friendship: + if chefsanity & Chefsanity.option_friendship: chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_FRIENDSHIP]}) - if chefsanity & options.Chefsanity.option_skills: + if chefsanity & Chefsanity.option_skills: chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_SKILL]}) - filtered_chefsanity_locations = filter_disabled_locations(world_options, list(chefsanity_locations_by_name.values())) + filtered_chefsanity_locations = filter_disabled_locations(options, list(chefsanity_locations_by_name.values())) randomized_locations.extend(filtered_chefsanity_locations) -def extend_craftsanity_locations(randomized_locations: List[LocationData], world_options): - craftsanity = world_options[options.Craftsanity] - if craftsanity == options.Craftsanity.option_none: +def extend_craftsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + if options.craftsanity == Craftsanity.option_none: return craftsanity_locations = [craft for craft in locations_by_tag[LocationTags.CRAFTSANITY]] - filtered_chefsanity_locations = filter_disabled_locations(world_options, craftsanity_locations) + filtered_chefsanity_locations = filter_disabled_locations(options, craftsanity_locations) randomized_locations.extend(filtered_chefsanity_locations) @@ -407,7 +407,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_mandatory_locations(randomized_locations, options) extend_backpack_locations(randomized_locations, options) - if world_options[options.ToolProgression] & options.ToolProgression.option_progressive: + if options.tool_progression & ToolProgression.option_progressive: randomized_locations.extend(locations_by_tag[LocationTags.TOOL_UPGRADE]) extend_elevator_locations(randomized_locations, options) @@ -417,7 +417,7 @@ def create_locations(location_collector: StardewLocationCollector, if location.mod_name is None or location.mod_name in options.mods: randomized_locations.append(location_table[location.name]) - if world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive: + if options.building_progression & BuildingProgression.option_progressive: for location in locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: if location.mod_name is None or location.mod_name in options.mods: randomized_locations.append(location_table[location.name]) @@ -438,18 +438,18 @@ def create_locations(location_collector: StardewLocationCollector, extend_special_order_locations(randomized_locations, options) extend_walnut_purchase_locations(randomized_locations, options) - extend_monstersanity_locations(randomized_locations, world_options) - extend_shipsanity_locations(randomized_locations, world_options) - extend_cooksanity_locations(randomized_locations, world_options) - extend_chefsanity_locations(randomized_locations, world_options) - extend_craftsanity_locations(randomized_locations, world_options) + extend_monstersanity_locations(randomized_locations, options) + extend_shipsanity_locations(randomized_locations, options) + extend_cooksanity_locations(randomized_locations, options) + extend_chefsanity_locations(randomized_locations, options) + extend_craftsanity_locations(randomized_locations, options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) -def filter_museum_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: - include_museum = world_options[options.Museumsanity] != options.Museumsanity.option_none +def filter_museum_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: + include_museum = options.museumsanity != Museumsanity.option_none return [location for location in locations if include_museum or LocationTags.REQUIRES_MUSEUM not in location.tags] @@ -458,19 +458,18 @@ def filter_ginger_island(options: StardewValleyOptions, locations: List[Location return [location for location in locations if include_island or LocationTags.GINGER_ISLAND not in location.tags] -def filter_qi_order_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: - include_qi_orders = world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_qi +def filter_qi_order_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: + include_qi_orders = options.special_order_locations == SpecialOrderLocations.option_board_qi return [location for location in locations if include_qi_orders or LocationTags.REQUIRES_QI_ORDERS not in location.tags] -def filter_modded_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: - current_mod_names = world_options[options.Mods] - return [location for location in locations if location.mod_name is None or location.mod_name in current_mod_names] +def filter_modded_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: + return [location for location in locations if location.mod_name is None or location.mod_name in options.mods] -def filter_disabled_locations(world_options: options.StardewOptions, locations: List[LocationData]) -> List[LocationData]: - locations_museum_filter = filter_museum_locations(world_options, locations) - locations_island_filter = filter_ginger_island(world_options, locations_museum_filter) - locations_qi_filter = filter_qi_order_locations(world_options, locations_island_filter) - locations_mod_filter = filter_modded_locations(world_options, locations_qi_filter) +def filter_disabled_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: + locations_museum_filter = filter_museum_locations(options, locations) + locations_island_filter = filter_ginger_island(options, locations_museum_filter) + locations_qi_filter = filter_qi_order_locations(options, locations_island_filter) + locations_mod_filter = filter_modded_locations(options, locations_qi_filter) return locations_mod_filter diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index 19d8ddfea98b..0e2cdb03a70e 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -3,6 +3,7 @@ from .region_logic import RegionLogic from .skill_logic import SkillLogic from .tool_logic import ToolLogic +from ..options import NumberOfMovementBuffs, NumberOfLuckBuffs from ..mods.logic.magic_logic import MagicLogic from ..mods.logic.skills_logic import ModSkillLogic from ..stardew_rule import StardewRule @@ -14,8 +15,8 @@ class AbilityLogic: player: int - movement_buff_option: int - luck_buff_option: int + movement_buff_option: NumberOfMovementBuffs + luck_buff_option: NumberOfLuckBuffs received: ReceivedLogic region: RegionLogic tool: ToolLogic @@ -24,7 +25,7 @@ class AbilityLogic: magic: MagicLogic mod_skill: ModSkillLogic - def __init__(self, player: int, movement_buff_option: int, luck_buff_option: int, received: ReceivedLogic, region: RegionLogic, tool: ToolLogic, + def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogic, region: RegionLogic, tool: ToolLogic, skill: SkillLogic, mine: MineLogic): self.player = player self.movement_buff_option = movement_buff_option @@ -65,4 +66,4 @@ def can_chop_perfectly(self) -> StardewRule: return region_rule & ((tool_rule & foraging_rule) | magic_rule) def has_max_buffs(self) -> StardewRule: - return self.received(Buff.movement, self.movement_buff_option) & self.received(Buff.luck, self.luck_buff_option) + return self.received(Buff.movement, self.movement_buff_option.value) & self.received(Buff.luck, self.luck_buff_option.value) diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index 0ff9615bdb4a..336bd82809a0 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,4 +1,5 @@ from .. import options +from ..options import ArcadeMachineLocations from ..stardew_rule import StardewRule, True_ from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -7,11 +8,11 @@ class ArcadeLogic: player: int - arcade_option: int + arcade_option: ArcadeMachineLocations received = ReceivedLogic region: RegionLogic - def __init__(self, player: int, arcade_option: int, received: ReceivedLogic, region: RegionLogic): + def __init__(self, player: int, arcade_option: ArcadeMachineLocations, received: ReceivedLogic, region: RegionLogic): self.player = player self.arcade_option = arcade_option self.received = received diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 83fab0f89266..b8bf3f3752ca 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,10 +1,10 @@ -from typing import Iterable, Dict +from typing import Dict from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic -from .. import options +from ..options import BuildingProgression from ..stardew_rule import StardewRule, True_, False_, Has from ..strings.artisan_good_names import ArtisanGood from ..strings.ap_names.event_names import Event @@ -17,22 +17,20 @@ class BuildingLogic: player: int - building_option: int + building_option: BuildingProgression received: ReceivedLogic has: HasLogic region: RegionLogic money: MoneyLogic building_rules: Dict[str, StardewRule] - mods_option: Iterable[str] - def __init__(self, player: int, building_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic, mods_option: Iterable[str]): + def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): self.player = player self.building_option = building_option self.received = received self.has = has self.region = region self.money = money - self.mods_option = mods_option self.building_rules = dict() def initialize_rules(self): @@ -62,7 +60,7 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): def has_building(self, building: str) -> StardewRule: carpenter_rule = self.received(Event.can_construct_buildings) - if not self.building_option & options.BuildingProgression.option_progressive: + if not self.building_option & BuildingProgression.option_progressive: return Has(building, self.building_rules) & carpenter_rule count = 1 @@ -83,7 +81,7 @@ def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level > 3: return False_() - if self.building_option & options.BuildingProgression.option_progressive: + if self.building_option & BuildingProgression.option_progressive: return self.received(f"Progressive House", upgrade_level) & self.region.can_reach(Region.carpenter) if upgrade_level == 1: diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 53eaa7af8439..b8871cec7bf0 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -8,11 +8,12 @@ from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic -from .. import options +from ..options import ExcludeGingerIsland from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe, \ all_cooking_recipes_by_name -from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource +from ..data.recipe_source import CutsceneSource, ShopTradeSource from ..locations import locations_by_tag, LocationTags +from ..options import Chefsanity from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region from ..strings.skill_names import Skill @@ -21,8 +22,8 @@ class CookingLogic: player: int - chefsanity_option: int - exclude_ginger_island: int + chefsanity_option: Chefsanity + exclude_ginger_island: ExcludeGingerIsland received: ReceivedLogic has: HasLogic region: RegionLogic @@ -34,7 +35,7 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, chefsanity_option: int, exclude_ginger_island: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player self.chefsanity_option = chefsanity_option @@ -65,21 +66,21 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: return cook_rule & recipe_rule & ingredients_rule & time_rule def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: - if self.chefsanity_option == options.Chefsanity.option_none: + if self.chefsanity_option == Chefsanity.option_none: return self.can_learn_recipe(source) if isinstance(source, StarterSource): return self.received_recipe(meal_name) - if isinstance(source, ShopTradeSource) and self.chefsanity_option & options.Chefsanity.option_purchases: + if isinstance(source, ShopTradeSource) and self.chefsanity_option & Chefsanity.option_purchases: return self.received_recipe(meal_name) - if isinstance(source, ShopSource) and self.chefsanity_option & options.Chefsanity.option_purchases: + if isinstance(source, ShopSource) and self.chefsanity_option & Chefsanity.option_purchases: return self.received_recipe(meal_name) - if isinstance(source, SkillSource) and self.chefsanity_option & options.Chefsanity.option_skills: + if isinstance(source, SkillSource) and self.chefsanity_option & Chefsanity.option_skills: return self.received_recipe(meal_name) - if isinstance(source, CutsceneSource) and self.chefsanity_option & options.Chefsanity.option_friendship: + if isinstance(source, CutsceneSource) and self.chefsanity_option & Chefsanity.option_friendship: return self.received_recipe(meal_name) - if isinstance(source, FriendshipSource) and self.chefsanity_option & options.Chefsanity.option_friendship: + if isinstance(source, FriendshipSource) and self.chefsanity_option & Chefsanity.option_friendship: return self.received_recipe(meal_name) - if isinstance(source, QueenOfSauceSource) and self.chefsanity_option & options.Chefsanity.option_queen_of_sauce: + if isinstance(source, QueenOfSauceSource) and self.chefsanity_option & Chefsanity.option_queen_of_sauce: return self.received_recipe(meal_name) return self.can_learn_recipe(source) @@ -107,7 +108,7 @@ def received_recipe(self, meal_name: str): def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " all_recipes_to_cook = [] - include_island = self.exclude_ginger_island == options.ExcludeGingerIsland.option_false + include_island = self.exclude_ginger_island == ExcludeGingerIsland.option_false for location in locations_by_tag[LocationTags.COOKSANITY]: if include_island or LocationTags.GINGER_ISLAND not in location.tags: all_recipes_to_cook.append(location.name[len(cooksanity_prefix):]) diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 15cf9af427a5..05df8a8290a3 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -10,15 +10,16 @@ from ..data.craftable_data import CraftingRecipe from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource +from ..options import Craftsanity, FestivalLocations, SpecialOrderLocations from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region class CraftingLogic: player: int - craftsanity_option: int - festivals_option: int - special_orders_option: int + craftsanity_option: Craftsanity + festivals_option: FestivalLocations + special_orders_option: SpecialOrderLocations received: ReceivedLogic has: HasLogic region: RegionLogic @@ -28,7 +29,7 @@ class CraftingLogic: skill: SkillLogic special_orders: SpecialOrderLogic - def __init__(self, player: int, craftsanity_option: int, festivals_option: int, special_orders_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, craftsanity_option: Craftsanity, festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): self.player = player self.craftsanity_option = craftsanity_option @@ -62,11 +63,11 @@ def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: return self.can_learn_recipe(recipe) else: return self.received_recipe(recipe.item) - if self.craftsanity_option == options.Craftsanity.option_none: + if self.craftsanity_option == Craftsanity.option_none: return self.can_learn_recipe(recipe) if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance(recipe.source, ShopSource): return self.received_recipe(recipe.item) - if isinstance(recipe.source, SpecialOrderSource) and self.special_orders_option != options.SpecialOrderLocations.option_disabled: + if isinstance(recipe.source, SpecialOrderSource) and self.special_orders_option != SpecialOrderLocations.option_disabled: return self.received_recipe(recipe.item) return self.can_learn_recipe(recipe) @@ -86,7 +87,7 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, FriendshipSource): return self.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) if isinstance(recipe.source, SpecialOrderSource): - if self.special_orders_option == options.SpecialOrderLocations.option_disabled: + if self.special_orders_option == SpecialOrderLocations.option_disabled: return self.special_orders.can_complete_special_order(recipe.source.special_order) return self.received_recipe(recipe.item) if isinstance(recipe.source, LogicSource): diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 5d8d36f35435..81587bcaa42c 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -34,13 +34,12 @@ from ..data.crops_data import crops_by_name from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..mods.logic.mod_logic import ModLogic -from .. import options from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops from ..data.bundle_data import BundleItem from ..data.fish_data import island_fish, legendary_fish, extended_family from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes -from ..options import StardewOptions +from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions from ..regions import vanilla_regions from ..stardew_rule import False_, Or, True_, Count, And, Has, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals @@ -88,7 +87,7 @@ @dataclass(frozen=False, repr=False) class StardewLogic: player: int - options: StardewOptions + options: StardewValleyOptions item_rules: Dict[str, StardewRule] = field(default_factory=dict) sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) @@ -107,24 +106,24 @@ def __post_init__(self): self.has = HasLogic(self.player, self.item_rules) self.region = RegionLogic(self.player) self.time = TimeLogic(self.player, self.received) - self.season = SeasonLogic(self.player, self.options[options.SeasonRandomization], self.received, self.time) - self.money = MoneyLogic(self.player, self.options[options.StartingMoney], self.received, self.has, self.region, self.time) + self.season = SeasonLogic(self.player, self.options.season_randomization, self.received, self.time) + self.money = MoneyLogic(self.player, self.options.starting_money, self.received, self.has, self.region, self.time) self.action = ActionLogic(self.player, self.received, self.has, self.region) - self.arcade = ArcadeLogic(self.player, self.options[options.ArcadeMachineLocations], self.received, self.region) + self.arcade = ArcadeLogic(self.player, self.options.arcade_machine_locations, self.received, self.region) self.artisan = ArtisanLogic(self.player, self.has, self.time) self.gifts = GiftLogic(self.player, self.has) - tool_option = self.options[options.ToolProgression] - skill_option = self.options[options.SkillProgression] - elevator_option = self.options[options.ElevatorProgression] - friendsanity_option = self.options[options.Friendsanity] - heart_size_option = self.options[options.FriendsanityHeartSize] - mods_option = self.options[options.Mods] - self.buildings = BuildingLogic(self.player, self.options[options.BuildingProgression], self.received, self.has, self.region, self.money, mods_option) - self.shipping = ShippingLogic(self.player, self.options[options.ExcludeGingerIsland], self.options[options.SpecialOrderLocations], self.has, + tool_option = self.options.tool_progression + skill_option = self.options.skill_progression + elevator_option = self.options.elevator_progression + friendsanity_option = self.options.friendsanity + heart_size_option = self.options.friendsanity_heart_size + mods_option = self.options.mods + self.buildings = BuildingLogic(self.player, self.options.building_progression, self.received, self.has, self.region, self.money) + self.shipping = ShippingLogic(self.player, self.options.exclude_ginger_island, self.options.special_order_locations, self.has, self.region, self.buildings) self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) - self.museum = MuseumLogic(self.player, self.options[options.Museumsanity], self.received, self.has, self.region, self.action) + self.museum = MuseumLogic(self.player, self.options.museumsanity, self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) self.combat = CombatLogic(self.player, self.received, self.region) self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) @@ -135,13 +134,13 @@ def __post_init__(self): self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.options[options.Chefsanity], self.options[options.ExcludeGingerIsland], self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) - self.ability = AbilityLogic(self.player, self.options[options.NumberOfMovementBuffs], self.options[options.NumberOfLuckBuffs], self.received, + self.cooking = CookingLogic(self.player, self.options.chefsanity, self.options.exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.ability = AbilityLogic(self.player, self.options.number_of_movement_buffs, self.options.number_of_luck_buffs, self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) - self.crafting = CraftingLogic(self.player, self.options[options.Craftsanity], self.options[options.FestivalLocations], - self.options[options.SpecialOrderLocations], self.received, self.has, self.region, self.time, self.money, + self.crafting = CraftingLogic(self.player, self.options.craftsanity, self.options.festival_locations, + self.options.special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, @@ -554,7 +553,7 @@ def can_complete_quest(self, quest: str) -> StardewRule: return Has(quest, self.quest_rules) def can_buy_seed(self, seed: SeedItem) -> StardewRule: - if self.options[options.Cropsanity] == options.Cropsanity.option_disabled or seed.name == Seed.qi_bean: + if self.options.cropsanity == Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() else: item_rule = self.received(seed.name) @@ -574,7 +573,7 @@ def can_buy_sapling(self, fruit: str) -> StardewRule: Fruit.peach: 6000, Fruit.pomegranate: 6000, Fruit.banana: 0, Fruit.mango: 0} received_sapling = self.received(f"{fruit} Sapling") - if self.options[options.Cropsanity] == options.Cropsanity.option_disabled: + if self.options.cropsanity == Cropsanity.option_disabled: allowed_buy_sapling = True_() else: allowed_buy_sapling = received_sapling @@ -600,8 +599,8 @@ def can_catch_fish(self, fish: FishItem) -> StardewRule: def can_catch_every_fish(self) -> StardewRule: rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] - exclude_island = self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true - exclude_extended_family = self.options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_board_qi + exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_extended_family = self.options.special_order_locations != SpecialOrderLocations.option_board_qi for fish in all_fish: if exclude_island and fish in island_fish: continue @@ -611,9 +610,9 @@ def can_catch_every_fish(self) -> StardewRule: return And(rules) def can_start_extended_family_quest(self) -> StardewRule: - if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: return False_() - if self.options[options.SpecialOrderLocations] != options.SpecialOrderLocations.option_board_qi: + if self.options.special_order_locations != SpecialOrderLocations.option_board_qi: return False_() return self.region.can_reach(Region.qi_walnut_room) & And([self.can_catch_fish(fish) for fish in legendary_fish]) @@ -712,7 +711,7 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: def can_complete_all_monster_slaying_goals(self) -> StardewRule: rules = [self.time.has_lived_max_months()] - exclude_island = self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true + exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west] for category in all_monsters_by_category: if exclude_island and all(monster.locations[0] in island_regions for monster in all_monsters_by_category[category]): @@ -722,13 +721,13 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: return And(rules) def can_win_egg_hunt(self) -> StardewRule: - number_of_movement_buffs: int = self.options[options.NumberOfMovementBuffs] - if self.options[options.FestivalLocations] == options.FestivalLocations.option_hard or number_of_movement_buffs < 2: + number_of_movement_buffs = self.options.number_of_movement_buffs + if self.options.festival_locations == FestivalLocations.option_hard or number_of_movement_buffs < 2: return True_() return self.received(Buff.movement, number_of_movement_buffs // 2) def can_succeed_luau_soup(self) -> StardewRule: - if self.options[options.FestivalLocations] != options.FestivalLocations.option_hard: + if self.options.festival_locations != FestivalLocations.option_hard: return True_() eligible_fish = [Fish.blobfish, Fish.crimsonfish, "Ice Pip", Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish, Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, "Super Cucumber"] @@ -743,7 +742,7 @@ def can_succeed_luau_soup(self) -> StardewRule: return Or(fish_rule) | Or(aged_rule) def can_succeed_grange_display(self) -> StardewRule: - if self.options[options.FestivalLocations] != options.FestivalLocations.option_hard: + if self.options.festival_locations != FestivalLocations.option_hard: return True_() animal_rule = self.has_animal(Generic.any) artisan_rule = self.artisan.can_keg(Generic.any) | self.artisan.can_preserves_jar(Generic.any) @@ -817,12 +816,12 @@ def has_any_barn_animal(self) -> StardewRule: return barn_rule def has_island_trader(self) -> StardewRule: - if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: return False_() return self.region.can_reach(Region.island_trader) def has_walnut(self, number: int) -> StardewRule: - if self.options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: return False_() if number <= 0: return True_() @@ -868,7 +867,7 @@ def has_everything(self, all_progression_items: Set[str]) -> StardewRule: return rules def has_prismatic_jelly_reward_access(self) -> StardewRule: - if self.options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_disabled: + if self.options.special_order_locations == SpecialOrderLocations.option_disabled: return self.special_order.can_complete_special_order("Prismatic Jelly") return self.received("Monster Musk Recipe") diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index a01fb2c18938..cb5f2a5f2b43 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -5,6 +5,7 @@ from .tool_logic import ToolLogic from .. import options from ..mods.logic.elevator_logic import ModElevatorLogic +from ..options import ToolProgression, SkillProgression, ElevatorProgression from ..stardew_rule import StardewRule, And, True_ from ..strings.performance_names import Performance from ..strings.region_names import Region @@ -14,9 +15,9 @@ class MineLogic: player: int - tool_option = int - skill_option = int - elevator_option = int + tool_option: ToolProgression + skill_option: SkillProgression + elevator_option: ElevatorProgression received: ReceivedLogic region: RegionLogic combat: CombatLogic @@ -24,7 +25,7 @@ class MineLogic: skill: SkillLogic mod_elevator: ModElevatorLogic - def __init__(self, player: int, tool_option: int, skill_option: int, elevator_option: int, received: ReceivedLogic, region: RegionLogic, + def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, region: RegionLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): self.player = player self.tool_option = tool_option @@ -69,7 +70,7 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) - if self.tool_option & options.ToolProgression.option_progressive: + if self.tool_option & ToolProgression.option_progressive: rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) if self.skill_option == options.SkillProgression.option_progressive: combat_tier = min(10, max(0, tier * 2)) @@ -82,7 +83,7 @@ def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) - if self.tool_option & options.ToolProgression.option_progressive: + if self.tool_option & ToolProgression.option_progressive: rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) if self.skill_option == options.SkillProgression.option_progressive: combat_tier = min(10, max(0, tier * 2)) @@ -108,7 +109,7 @@ def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule rules = [] weapon_rule = self.combat.has_great_weapon() rules.append(weapon_rule) - if self.tool_option & options.ToolProgression.option_progressive: + if self.tool_option & ToolProgression.option_progressive: rules.append(self.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) if self.skill_option == options.SkillProgression.option_progressive: skill_tier = min(10, max(0, tier * 2 + 6)) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 01aa0abe8af8..7e997877f4c6 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,10 +1,9 @@ -from typing import Iterable - from .has_logic import HasLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic -from ..stardew_rule import StardewRule, And, Or, Reach, Count, True_ +from ..options import StartingMoney +from ..stardew_rule import StardewRule, True_ from ..strings.currency_names import Currency MONEY_PER_MONTH = 15000 @@ -15,13 +14,13 @@ class MoneyLogic: player: int - starting_money_option: int + starting_money_option: StartingMoney received: ReceivedLogic has: HasLogic region: RegionLogic time: TimeLogic - def __init__(self, player: int, starting_money_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): + def __init__(self, player: int, starting_money_option: StartingMoney, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): self.player = player self.starting_money_option = starting_money_option self.received = received diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 989c60b41b48..dde104c94e99 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -4,6 +4,7 @@ from .has_logic import HasLogic from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals +from ..options import Museumsanity from ..stardew_rule import StardewRule, And, False_, Count from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -12,13 +13,13 @@ class MuseumLogic: player: int - museum_option: int + museum_option: Museumsanity received = ReceivedLogic has: HasLogic region: RegionLogic action: ActionLogic - def __init__(self, player: int, museum_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic): + def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic): self.player = player self.museum_option = museum_option self.received = received diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 409f36856814..7dcbaa07f5e4 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -8,6 +8,7 @@ from .tool_logic import ToolLogic from .. import options from ..data.villagers_data import Villager +from ..options import Friendsanity, FriendsanityHeartSize from ..stardew_rule import StardewRule, True_ from ..strings.region_names import Region from ..strings.villager_names import NPC @@ -15,14 +16,14 @@ class PetLogic: player: int - friendsanity_option: int - heart_size_option: int + friendsanity_option: Friendsanity + heart_size_option: FriendsanityHeartSize received: ReceivedLogic region: RegionLogic time: TimeLogic tool: ToolLogic - def __init__(self, player: int, friendsanity_option: int, heart_size_option: int, received_logic: ReceivedLogic, region: RegionLogic, + def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, region: RegionLogic, time: TimeLogic, tool: ToolLogic): self.player = player self.friendsanity_option = friendsanity_option @@ -35,7 +36,7 @@ def __init__(self, player: int, friendsanity_option: int, heart_size_option: int def has_hearts(self, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() - if self.friendsanity_option == options.Friendsanity.option_none or self.friendsanity_option == options.Friendsanity.option_bachelors: + if self.friendsanity_option == Friendsanity.option_none or self.friendsanity_option == Friendsanity.option_bachelors: return self.can_befriend_pet(hearts) return self.received_hearts(NPC.pet, hearts) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index f8e4688bf75b..400b91fd54ca 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -11,6 +11,7 @@ from .time_logic import TimeLogic from .. import options from ..data.villagers_data import all_villagers_by_name, Villager +from ..options import Friendsanity, FriendsanityHeartSize, Mods from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic from ..strings.gift_names import Gift @@ -19,8 +20,8 @@ class RelationshipLogic: player: int - friendsanity_option: int - heart_size_option: int + friendsanity_option: Friendsanity + heart_size_option: FriendsanityHeartSize received: ReceivedLogic has: HasLogic region: RegionLogic @@ -28,10 +29,10 @@ class RelationshipLogic: season: SeasonLogic gifts: GiftLogic buildings: BuildingLogic - mods_option: Iterable[str] + mods_option: Mods - def __init__(self, player: int, friendsanity_option: int, heart_size_option: int, received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, - time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Iterable[str]): + def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, + time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option @@ -68,7 +69,7 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule: def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() - if self.friendsanity_option == options.Friendsanity.option_none: + if self.friendsanity_option == Friendsanity.option_none: return self.can_earn_relationship(npc, hearts) if npc not in all_villagers_by_name: if npc == Generic.any or npc == Generic.bachelor: @@ -98,11 +99,11 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if not self.npc_is_in_current_slot(npc): return True_() villager = all_villagers_by_name[npc] - if self.friendsanity_option == options.Friendsanity.option_bachelors and not villager.bachelor: + if self.friendsanity_option == Friendsanity.option_bachelors and not villager.bachelor: return self.can_earn_relationship(npc, hearts) - if self.friendsanity_option == options.Friendsanity.option_starting_npcs and not villager.available: + if self.friendsanity_option == Friendsanity.option_starting_npcs and not villager.available: return self.can_earn_relationship(npc, hearts) - is_capped_at_8 = villager.bachelor and self.friendsanity_option != options.Friendsanity.option_all_with_marriage + is_capped_at_8 = villager.bachelor and self.friendsanity_option != Friendsanity.option_all_with_marriage if is_capped_at_8 and hearts > 8: return self.received_hearts(villager, 8) & self.can_earn_relationship(npc, hearts) return self.received_hearts(villager, hearts) @@ -143,7 +144,7 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: previous_heart = hearts - self.heart_size_option previous_heart_rule = self.has_hearts(npc, previous_heart) - # if npc == NPC.wizard and ModNames.magic in self.options[options.Mods]: + # if npc == NPC.wizard and ModNames.magic in self.options.mods: # earn_rule = self.can_meet(npc) & self.time.has_lived_months(hearts) if npc in all_villagers_by_name: if not self.npc_is_in_current_slot(npc): diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 0a4d91422f3a..40229b9ef71a 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -2,7 +2,7 @@ from .received_logic import ReceivedLogic from .time_logic import TimeLogic -from .. import options +from ..options import SeasonRandomization from ..stardew_rule import StardewRule, True_, And, Or from ..strings.generic_names import Generic from ..strings.season_names import Season @@ -10,11 +10,11 @@ class SeasonLogic: player: int - season_option: int + season_option: SeasonRandomization received: ReceivedLogic time: TimeLogic - def __init__(self, player: int, season_option: int, received_logic: ReceivedLogic, time: TimeLogic): + def __init__(self, player: int, season_option: SeasonRandomization, received_logic: ReceivedLogic, time: TimeLogic): self.player = player self.season_option = season_option self.received = received_logic @@ -30,9 +30,9 @@ def has(self, season: str) -> StardewRule: if season in self.has_season_rules: return self.has_season_rules[season] seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] - if self.season_option == options.SeasonRandomization.option_progressive: + if self.season_option == SeasonRandomization.option_progressive: self.has_season_rules[season] = self.received(Season.progressive, seasons_order.index(season)) - elif self.season_option == options.SeasonRandomization.option_disabled: + elif self.season_option == SeasonRandomization.option_disabled: if season == Season.spring: self.has_season_rules[season] = True_() else: diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 0efc6283f93d..39f0fd6d3b2a 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -2,8 +2,9 @@ from .building_logic import BuildingLogic from .has_logic import HasLogic from .region_logic import RegionLogic -from .. import options +from ..options import ExcludeGingerIsland from ..locations import LocationTags, locations_by_tag +from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, And from ..strings.building_names import Building from ..strings.region_names import Region @@ -11,13 +12,13 @@ class ShippingLogic: player: int - exclude_ginger_island: int - special_orders_option: int + exclude_ginger_island: ExcludeGingerIsland + special_orders_option: SpecialOrderLocations has: HasLogic region: RegionLogic buildings: BuildingLogic - def __init__(self, player: int, exclude_ginger_island: int, special_orders_option: int, has: HasLogic, region: RegionLogic, buildings: BuildingLogic): + def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations, has: HasLogic, region: RegionLogic, buildings: BuildingLogic): self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_orders_option = special_orders_option @@ -37,8 +38,8 @@ def can_ship(self, item: str = "") -> StardewRule: def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " all_items_to_ship = [] - include_island = self.exclude_ginger_island == options.ExcludeGingerIsland.option_false - include_qi = self.special_orders_option == options.SpecialOrderLocations.option_board_qi + include_island = self.exclude_ginger_island == ExcludeGingerIsland.option_false + include_qi = self.special_orders_option == SpecialOrderLocations.option_board_qi for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 705578d9e816..db56de5a57de 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -12,6 +12,7 @@ from ..data import all_crops from ..mods.logic.magic_logic import MagicLogic from ..mods.logic.mod_skills_levels import get_mod_skill_levels +from ..options import SkillProgression, Mods from ..stardew_rule import StardewRule, True_, Or from worlds.stardew_valley.strings.craftable_names import Craftable, Fishing from ..strings.generic_names import Generic @@ -26,7 +27,7 @@ class SkillLogic: player: int - skill_option: int + skill_option: SkillProgression received: ReceivedLogic has: HasLogic region: RegionLogic @@ -36,9 +37,9 @@ class SkillLogic: combat: CombatLogic crop: CropLogic magic: MagicLogic - mods: Iterable[str] + mods: Mods - def __init__(self, player: int, skill_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): self.player = player self.skill_option = skill_option @@ -51,7 +52,7 @@ def __init__(self, player: int, skill_option: int, received: ReceivedLogic, has: self.combat = combat self.crop = crop - def set_mod_logic(self, magic: MagicLogic, mods: Iterable[str]): + def set_mod_logic(self, magic: MagicLogic, mods: Mods): self.magic = magic self.mods = mods diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index e03362caf091..979a625f04c1 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -5,6 +5,7 @@ from .season_logic import SeasonLogic from .. import options from ..mods.logic.magic_logic import MagicLogic +from ..options import ToolProgression from ..stardew_rule import StardewRule, True_ from ..strings.region_names import Region from ..strings.skill_names import ModSkill @@ -29,7 +30,7 @@ class ToolLogic: player: int - tool_option = int + tool_option = ToolProgression received: ReceivedLogic has: HasLogic region: RegionLogic @@ -37,7 +38,7 @@ class ToolLogic: money: MoneyLogic magic: MagicLogic - def __init__(self, player: int, tool_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, money: MoneyLogic): self.player = player self.tool_option = tool_option @@ -54,13 +55,13 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule if material == ToolMaterial.basic or tool == Tool.scythe: return True_() - if self.tool_option & options.ToolProgression.option_progressive: + if self.tool_option & ToolProgression.option_progressive: return self.received(f"Progressive {tool}", tool_materials[material]) return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) def has_fishing_rod(self, level: int) -> StardewRule: - if self.tool_option & options.ToolProgression.option_progressive: + if self.tool_option & ToolProgression.option_progressive: return self.received(f"Progressive {Tool.fishing_rod}", level) if level <= 1: diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 41ce810eb269..2e151538c1a8 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -2,6 +2,7 @@ from ...logic.has_logic import HasLogic from ...logic.money_logic import MoneyLogic +from ...options import Mods from ...strings.artisan_good_names import ArtisanGood from ...strings.building_names import ModBuilding from ..mod_data import ModNames @@ -13,9 +14,9 @@ class ModBuildingLogic: player: int has: HasLogic money: MoneyLogic - mods_option: Iterable[str] + mods_option: Mods - def __init__(self, player: int, has: HasLogic, money: MoneyLogic, mods_option: Iterable[str]): + def __init__(self, player: int, has: HasLogic, money: MoneyLogic, mods_option: Mods): self.player = player self.has = has self.money = money diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index 617776554d86..264c28069b3c 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -4,19 +4,19 @@ from ...logic.received_logic import ReceivedLogic from ...logic.skill_logic import SkillLogic from ...logic.tool_logic import ToolLogic +from ...options import SkillProgression, ElevatorProgression from ...strings.craftable_names import Bomb from ...strings.performance_names import Performance from ...strings.skill_names import Skill from ...strings.tool_names import Tool, ToolMaterial from ...strings.ap_names.transport_names import ModTransportation from ...stardew_rule import StardewRule, True_, And -from ... import options class DeepWoodsLogic: player: int - skill_option: int - elevator_option: int + skill_option: SkillProgression + elevator_option: ElevatorProgression received: ReceivedLogic has: HasLogic combat: CombatLogic @@ -24,7 +24,7 @@ class DeepWoodsLogic: skill: SkillLogic cooking: CookingLogic - def __init__(self, player: int, skill_option: int, elevator_option: int, received: ReceivedLogic, has: HasLogic, combat: CombatLogic, tool: ToolLogic, + def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, has: HasLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, cooking: CookingLogic): self.player = player self.skill_option = skill_option @@ -46,13 +46,13 @@ def can_reach_woods_depth(self, depth: int) -> StardewRule: if depth > 50: rules.append(self.combat.can_fight_at_level(Performance.great) & self.cooking.can_cook() & self.received(ModTransportation.woods_obelisk)) - if self.skill_option == options.SkillProgression.option_progressive: + if self.skill_option == SkillProgression.option_progressive: combat_tier = min(10, max(0, tier + 5)) rules.append(self.skill.has_level(Skill.combat, combat_tier)) return And(rules) def has_woods_rune_to_depth(self, floor: int) -> StardewRule: - if self.elevator_option == options.ElevatorProgression.option_vanilla: + if self.elevator_option == ElevatorProgression.option_vanilla: return True_() return self.received("Progressive Woods Obelisk Sigils", int(floor / 10)) diff --git a/worlds/stardew_valley/mods/logic/elevator_logic.py b/worlds/stardew_valley/mods/logic/elevator_logic.py index e9d3730be21f..b1ab38d30057 100644 --- a/worlds/stardew_valley/mods/logic/elevator_logic.py +++ b/worlds/stardew_valley/mods/logic/elevator_logic.py @@ -1,6 +1,5 @@ -from typing import Iterable - from ...logic.received_logic import ReceivedLogic +from ...options import ElevatorProgression, Mods from ...stardew_rule import StardewRule, True_ from ...mods.mod_data import ModNames from ... import options @@ -8,11 +7,11 @@ class ModElevatorLogic: player: int - elevator_option: int - mods: Iterable[str] + elevator_option: ElevatorProgression + mods: Mods received: ReceivedLogic - def __init__(self, player: int, elevator_option: int, mods: Iterable[str], received: ReceivedLogic): + def __init__(self, player: int, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic): self.player = player self.elevator_option = elevator_option self.mods = mods diff --git a/worlds/stardew_valley/mods/logic/magic_logic.py b/worlds/stardew_valley/mods/logic/magic_logic.py index e9f517baa016..7b95ac29ebde 100644 --- a/worlds/stardew_valley/mods/logic/magic_logic.py +++ b/worlds/stardew_valley/mods/logic/magic_logic.py @@ -2,6 +2,7 @@ from ...logic.received_logic import ReceivedLogic from ...logic.region_logic import RegionLogic +from ...options import Mods from ...strings.region_names import MagicRegion from ...mods.mod_data import ModNames from ...strings.spells import MagicSpell @@ -11,11 +12,11 @@ class MagicLogic: player: int - mods: Iterable[str] + mods: Mods received: ReceivedLogic region: RegionLogic - def __init__(self, player: int, mods: Iterable[str], received: ReceivedLogic, region: RegionLogic): + def __init__(self, player: int, mods: Mods, received: ReceivedLogic, region: RegionLogic): self.player = player self.mods = mods self.received = received diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index a5218eded1e5..9ecbf43394f6 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -23,6 +23,7 @@ from ...logic.skill_logic import SkillLogic from ...logic.tool_logic import ToolLogic from ...logic.wallet_logic import WalletLogic +from ...options import SkillProgression, ElevatorProgression, Mods class ModLogic: @@ -34,7 +35,7 @@ class ModLogic: deepwoods: DeepWoodsLogic skill: ModSkillLogic - def __init__(self, player: int, skill_option: int, elevator_option: int, mods: Iterable[str], received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic): self.magic = MagicLogic(player, mods, received, region) diff --git a/worlds/stardew_valley/mods/logic/mod_skills_levels.py b/worlds/stardew_valley/mods/logic/mod_skills_levels.py index 4ad99f8d4787..c1b2c305ec17 100644 --- a/worlds/stardew_valley/mods/logic/mod_skills_levels.py +++ b/worlds/stardew_valley/mods/logic/mod_skills_levels.py @@ -1,8 +1,9 @@ from typing import List, Iterable from ...mods.mod_data import ModNames +from ...options import Mods -def get_mod_skill_levels(mods: Iterable[str]) -> List[str]: +def get_mod_skill_levels(mods: Mods) -> List[str]: skills_items = [] if ModNames.luck_skill in mods: skills_items.append("Luck Level") diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 8493e5211d8c..b01618cddffe 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -1,9 +1,10 @@ -from typing import Iterable, Dict +from typing import Dict from ...logic.has_logic import HasLogic from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic +from ...options import Mods from ...strings.quest_names import ModQuest from ..mod_data import ModNames from ...strings.food_names import Meal, Beverage @@ -15,13 +16,13 @@ class QuestLogic: - mods: Iterable[str] + mods: Mods has: HasLogic region: RegionLogic season: SeasonLogic relationship: RelationshipLogic - def __init__(self, mods: Iterable[str], has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic): + def __init__(self, mods: Mods, has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic): self.mods = mods self.has = has self.region = region diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 8b8852f00e60..758ffa862033 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -1,4 +1,3 @@ -from typing import Iterable from .magic_logic import MagicLogic from ... import options from ...logic.action_logic import ActionLogic @@ -10,6 +9,7 @@ from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.tool_logic import ToolLogic +from ...options import SkillProgression, Mods from ...strings.building_names import Building from ...strings.geode_names import Geode from ...strings.region_names import Region @@ -24,7 +24,7 @@ class ModSkillLogic: player: int - skill_option: int + skill_option: SkillProgression received: ReceivedLogic has: HasLogic region: RegionLogic @@ -35,11 +35,11 @@ class ModSkillLogic: fishing: FishingLogic cooking: CookingLogic magic: MagicLogic - mods_option: Iterable[str] + mods_option: Mods - def __init__(self, player: int, skill_option: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - magic: MagicLogic, mods_option: Iterable[str]): + magic: MagicLogic, mods_option: Mods): self.player = player self.skill_option = skill_option self.received = received diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index a02c52c24e56..a99d5ab90a3a 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -4,6 +4,7 @@ from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.wallet_logic import WalletLogic +from ...options import Mods from ...strings.craftable_names import Consumable, Edible from ...strings.food_names import Meal from ...strings.material_names import Material @@ -20,9 +21,9 @@ class ModSpecialOrderLogic: region: RegionLogic relationship: RelationshipLogic wallet: WalletLogic - mods_option: Iterable[str] + mods_option: Mods - def __init__(self, player: int, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, wallet: WalletLogic, mods_option: Iterable[str]): + def __init__(self, player: int, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, wallet: WalletLogic, mods_option: Mods): self.player = player self.has = has self.region = region diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 2db5027e7b92..81e6b5ffd43e 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -670,11 +670,11 @@ class StardewValleyOptions(PerGameCommonOptions): help_wanted_locations: HelpWantedLocations fishsanity: Fishsanity museumsanity: Museumsanity - Monstersanity, - Shipsanity, - Cooksanity, - Chefsanity, - Craftsanity, + monstersanity: Monstersanity + shipsanity: Shipsanity + cooksanity: Cooksanity + chefsanity: Chefsanity + craftsanity: Craftsanity friendsanity: Friendsanity friendsanity_heart_size: FriendsanityHeartSize movement_buff_number: NumberOfMovementBuffs diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 8e2b0a851334..45c00f92a1ff 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -1,30 +1,31 @@ import itertools -from typing import Dict, List +from typing import List from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules -from . import options, locations -from .bundles import Bundle +from worlds.stardew_valley.strings.craftable_names import Bomb +from . import locations +from .options import StardewValleyOptions from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name +from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals, \ + all_museum_artifacts, Artifact from .data.recipe_data import all_cooking_recipes_by_name +from .locations import LocationTags from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices -from .stardew_rule import And -from .strings.building_names import Building -from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance -from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals,\ - all_museum_artifacts, Artifact -from .strings.region_names import Region from .mods.mod_data import ModNames -from .locations import LocationTags -from .options import StardewOptions +from .options import ToolProgression, BuildingProgression, ExcludeGingerIsland, SpecialOrderLocations, Museumsanity, BackpackProgression, Shipsanity, \ + Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression +from .stardew_rule import And from .strings.ap_names.transport_names import Transportation from .strings.artisan_good_names import ArtisanGood +from .strings.building_names import Building from .strings.calendar_names import Weekday -from worlds.stardew_valley.strings.craftable_names import Bomb +from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance from .strings.material_names import Material from .strings.metal_names import MetalBar +from .strings.region_names import Region from .strings.season_names import Season from .strings.skill_names import ModSkill, Skill from .strings.tool_names import Tool, ToolMaterial @@ -33,45 +34,50 @@ from .strings.wallet_item_names import Wallet -def set_rules(multi_world: MultiWorld, player: int, world_options: StardewOptions, logic: StardewLogic, - current_bundles: Dict[str, Bundle]): - all_location_names = list(location.name for location in multi_world.get_locations(player)) +def set_rules(world): + multiworld = world.multiworld + world_options = world.options + player = world.player + logic = world.logic + current_bundles = world.modified_bundles + + all_location_names = list(location.name for location in multiworld.get_locations(player)) # 22.756 - 23.789 - set_entrance_rules(logic, multi_world, player, world_options) + set_entrance_rules(logic, multiworld, player, world_options) # 34.761 - 35.568 - set_ginger_island_rules(logic, multi_world, player, world_options) + set_ginger_island_rules(logic, multiworld, player, world_options) # 36.281 - 38.453 - set_tool_rules(logic, multi_world, player, world_options) + set_tool_rules(logic, multiworld, player, world_options) # 36.980 - 37.228 - set_skills_rules(logic, multi_world, player, world_options) - set_bundle_rules(current_bundles, logic, multi_world, player) - set_building_rules(logic, multi_world, player, world_options) - set_cropsanity_rules(all_location_names, logic, multi_world, player, world_options) - set_story_quests_rules(all_location_names, logic, multi_world, player, world_options) + set_skills_rules(logic, multiworld, player, world_options) + set_bundle_rules(current_bundles, logic, multiworld, player) + set_building_rules(logic, multiworld, player, world_options) + set_cropsanity_rules(all_location_names, logic, multiworld, player, world_options) + set_story_quests_rules(all_location_names, logic, multiworld, player, world_options) # 1min09 - 1min14 - set_special_order_rules(all_location_names, logic, multi_world, player, world_options) - set_help_wanted_quests_rules(logic, multi_world, player, world_options) - set_fishsanity_rules(all_location_names, logic, multi_world, player) - set_museumsanity_rules(all_location_names, logic, multi_world, player, world_options) + set_special_order_rules(all_location_names, logic, multiworld, player, world_options) + set_help_wanted_quests_rules(logic, multiworld, player, world_options) + set_fishsanity_rules(all_location_names, logic, multiworld, player) + set_museumsanity_rules(all_location_names, logic, multiworld, player, world_options) # 1min34 - 1min46 - set_friendsanity_rules(all_location_names, logic, multi_world, player) - set_backpack_rules(logic, multi_world, player, world_options) - set_festival_rules(all_location_names, logic, multi_world, player) - set_monstersanity_rules(all_location_names, logic, multi_world, player, world_options) - set_shipsanity_rules(all_location_names, logic, multi_world, player, world_options) - set_cooksanity_rules(all_location_names, logic, multi_world, player, world_options) - set_chefsanity_rules(all_location_names, logic, multi_world, player, world_options) - set_craftsanity_rules(all_location_names, logic, multi_world, player, world_options) - set_isolated_locations_rules(logic, multi_world, player) - set_traveling_merchant_rules(logic, multi_world, player) - set_arcade_machine_rules(logic, multi_world, player, world_options) - - set_deepwoods_rules(logic, multi_world, player, world_options) - set_magic_spell_rules(logic, multi_world, player, world_options) + set_friendsanity_rules(all_location_names, logic, multiworld, player) + set_backpack_rules(logic, multiworld, player, world_options) + set_festival_rules(all_location_names, logic, multiworld, player) + set_monstersanity_rules(all_location_names, logic, multiworld, player, world_options) + set_shipsanity_rules(all_location_names, logic, multiworld, player, world_options) + set_cooksanity_rules(all_location_names, logic, multiworld, player, world_options) + set_chefsanity_rules(all_location_names, logic, multiworld, player, world_options) + set_craftsanity_rules(all_location_names, logic, multiworld, player, world_options) + set_isolated_locations_rules(logic, multiworld, player) + set_traveling_merchant_rules(logic, multiworld, player) + set_arcade_machine_rules(logic, multiworld, player, world_options) + + set_deepwoods_rules(logic, multiworld, player, world_options) + set_magic_spell_rules(logic, multiworld, player, world_options) # 1min52 - 1min53 # These times are for TestOptions # 1min36 - 1min38 # After the combat not duplicating a bunch of stuff # 1min28 - 1min30 # with the caching of combat rules @@ -93,8 +99,8 @@ def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): logic.relationship.can_reproduce(2).simplify()) -def set_tool_rules(logic: StardewLogic, multi_world, player, world_options): - if not world_options[options.ToolProgression] & options.ToolProgression.option_progressive: +def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + if not world_options.tool_progression & ToolProgression.option_progressive: return MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), @@ -111,92 +117,92 @@ def set_tool_rules(logic: StardewLogic, multi_world, player, world_options): MultiWorldRules.set_rule(tool_upgrade_location, logic.has_tool(tool, previous).simplify()) -def set_building_rules(logic: StardewLogic, multi_world, player, world_options): - if not world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive: +def set_building_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + if not world_options.building_progression & BuildingProgression.option_progressive: return for building in locations.locations_by_tag[LocationTags.BUILDING_BLUEPRINT]: - if building.mod_name is not None and building.mod_name not in world_options[options.Mods]: + if building.mod_name is not None and building.mod_name not in world_options.mods: continue - MultiWorldRules.set_rule(multi_world.get_location(building.name, player), + MultiWorldRules.set_rule(multiworld.get_location(building.name, player), logic.buildings.building_rules[building.name.replace(" Blueprint", "")].simplify()) -def set_bundle_rules(current_bundles, logic: StardewLogic, multi_world, player): +def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): for bundle in current_bundles.values(): - location = multi_world.get_location(bundle.get_name_with_bundle(), player) + location = multiworld.get_location(bundle.get_name_with_bundle(), player) rules = logic.can_complete_bundle(bundle.requirements, bundle.number_required) simplified_rules = rules.simplify() MultiWorldRules.set_rule(location, simplified_rules) - MultiWorldRules.add_rule(multi_world.get_location("Complete Crafts Room", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), And(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Complete Pantry", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), And(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Complete Fish Tank", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), And(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Complete Boiler Room", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), And(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Complete Bulletin Board", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), And(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Complete Vault", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), And(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]).simplify()) -def set_skills_rules(logic: StardewLogic, multi_world, player, world_options): - mods = world_options[options.Mods] - if world_options[options.SkillProgression] == options.SkillProgression.option_vanilla: +def set_skills_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + mods = world_options.mods + if world_options.skill_progression == SkillProgression.option_vanilla: return for i in range(1, 11): - set_vanilla_skill_rule_for_level(logic, multi_world, player, i) - set_modded_skill_rule_for_level(logic, multi_world, player, mods, i) + set_vanilla_skill_rule_for_level(logic, multiworld, player, i) + set_modded_skill_rule_for_level(logic, multiworld, player, mods, i) -def set_vanilla_skill_rule_for_level(logic: StardewLogic, multi_world, player, level: int): - set_vanilla_skill_rule(logic, multi_world, player, Skill.farming, level) - set_vanilla_skill_rule(logic, multi_world, player, Skill.fishing, level) - set_vanilla_skill_rule(logic, multi_world, player, Skill.foraging, level) - set_vanilla_skill_rule(logic, multi_world, player, Skill.mining, level) - set_vanilla_skill_rule(logic, multi_world, player, Skill.combat, level) +def set_vanilla_skill_rule_for_level(logic: StardewLogic, multiworld, player, level: int): + set_vanilla_skill_rule(logic, multiworld, player, Skill.farming, level) + set_vanilla_skill_rule(logic, multiworld, player, Skill.fishing, level) + set_vanilla_skill_rule(logic, multiworld, player, Skill.foraging, level) + set_vanilla_skill_rule(logic, multiworld, player, Skill.mining, level) + set_vanilla_skill_rule(logic, multiworld, player, Skill.combat, level) -def set_modded_skill_rule_for_level(logic: StardewLogic, multi_world, player, mods, level: int): +def set_modded_skill_rule_for_level(logic: StardewLogic, multiworld, player, mods, level: int): if ModNames.luck_skill in mods: - set_modded_skill_rule(logic, multi_world, player, ModSkill.luck, level) + set_modded_skill_rule(logic, multiworld, player, ModSkill.luck, level) if ModNames.magic in mods: - set_modded_skill_rule(logic, multi_world, player, ModSkill.magic, level) + set_modded_skill_rule(logic, multiworld, player, ModSkill.magic, level) if ModNames.binning_skill in mods: - set_modded_skill_rule(logic, multi_world, player, ModSkill.binning, level) + set_modded_skill_rule(logic, multiworld, player, ModSkill.binning, level) if ModNames.cooking_skill in mods: - set_modded_skill_rule(logic, multi_world, player, ModSkill.cooking, level) + set_modded_skill_rule(logic, multiworld, player, ModSkill.cooking, level) if ModNames.socializing_skill in mods: - set_modded_skill_rule(logic, multi_world, player, ModSkill.socializing, level) + set_modded_skill_rule(logic, multiworld, player, ModSkill.socializing, level) if ModNames.archaeology in mods: - set_modded_skill_rule(logic, multi_world, player, ModSkill.archaeology, level) + set_modded_skill_rule(logic, multiworld, player, ModSkill.archaeology, level) -def get_skill_level_location(multi_world, player, skill: str, level: int): +def get_skill_level_location(multiworld, player, skill: str, level: int): location_name = f"Level {level} {skill}" - return multi_world.get_location(location_name, player) + return multiworld.get_location(location_name, player) -def set_vanilla_skill_rule(logic: StardewLogic, multi_world, player, skill: str, level: int): +def set_vanilla_skill_rule(logic: StardewLogic, multiworld, player, skill: str, level: int): rule = logic.skill.can_earn_level(skill, level).simplify() - MultiWorldRules.set_rule(get_skill_level_location(multi_world, player, skill, level), rule.simplify()) + MultiWorldRules.set_rule(get_skill_level_location(multiworld, player, skill, level), rule.simplify()) -def set_modded_skill_rule(logic: StardewLogic, multi_world, player, skill: str, level: int): +def set_modded_skill_rule(logic: StardewLogic, multiworld, player, skill: str, level: int): rule = logic.mod.skill.can_earn_mod_skill_level(skill, level).simplify() - MultiWorldRules.set_rule(get_skill_level_location(multi_world, player, skill, level), rule.simplify()) + MultiWorldRules.set_rule(get_skill_level_location(multiworld, player, skill, level), rule.simplify()) -def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: StardewOptions): +def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): set_mines_floor_entrance_rules(logic, multiworld, player) set_skull_cavern_floor_entrance_rules(logic, multiworld, player) set_blacksmith_entrance_rules(logic, multiworld, player) @@ -204,52 +210,52 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: set_traveling_merchant_day_rules(logic, multiworld, player) dangerous_mine_rule = logic.mine.has_mine_elevator_to_floor(120) & logic.region.can_reach(Region.qi_walnut_room) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_to_dangerous_mines_20, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_20, player), dangerous_mine_rule.simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_to_dangerous_mines_60, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_60, player), dangerous_mine_rule.simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_to_dangerous_mines_100, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_100, player), dangerous_mine_rule.simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_tide_pools, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), logic.received("Beach Bridge") | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_quarry, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), logic.received("Bridge Repair") | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_secret_woods, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.forest_to_sewer, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), logic.wallet.has_rusty_key().simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.town_to_sewer, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), logic.wallet.has_rusty_key().simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_abandoned_jojamart, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_abandoned_jojamart, player), logic.has_abandoned_jojamart().simplify()) movie_theater_rule = logic.has_movie_theater().simplify() - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_movie_theater, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_movie_theater, player), movie_theater_rule) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.purchase_movie_ticket, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.purchase_movie_ticket, player), movie_theater_rule) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.take_bus_to_desert, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.take_bus_to_desert, player), logic.received("Bus Repair").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_skull_cavern, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_skull_cavern, player), logic.received(Wallet.skull_key).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_dangerous_skull_cavern, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_dangerous_skull_cavern, player), (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room)).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_mines_dwarf, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.buy_from_traveling_merchant, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), logic.has_traveling_merchant()) - set_farm_buildings_entrance_rules(logic, multi_world, player) + set_farm_buildings_entrance_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_adventurer_guild, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player), logic.received("Adventurer's Guild")) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_railroad, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), logic.time.has_lived_months(2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_witch_warp_cave, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_witch_hut, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_mutant_bug_lair, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), ((logic.wallet.has_rusty_key() & logic.region.can_reach(Region.railroad) & logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()).simplify())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), @@ -263,28 +269,28 @@ def set_entrance_rules(logic: StardewLogic, multi_world, player, world_options: MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce).simplify()) -def set_farm_buildings_entrance_rules(logic, multi_world, player): - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_coop, player), logic.buildings.has_building(Building.coop)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_barn, player), logic.buildings.has_building(Building.barn)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_shed, player), logic.buildings.has_building(Building.shed)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_slime_hutch, player), logic.buildings.has_building(Building.slime_hutch)) +def set_farm_buildings_entrance_rules(logic, multiworld, player): + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_coop, player), logic.buildings.has_building(Building.coop)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_barn, player), logic.buildings.has_building(Building.barn)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_shed, player), logic.buildings.has_building(Building.shed)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_slime_hutch, player), logic.buildings.has_building(Building.slime_hutch)) -def set_bedroom_entrance_rules(logic, multi_world, player, world_options): - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) - if ModNames.alec in world_options[options.Mods]: - MultiWorldRules.set_rule(multi_world.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) +def set_bedroom_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) + if ModNames.alec in world_options.mods: + MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) def set_mines_floor_entrance_rules(logic, multiworld, player): @@ -345,59 +351,59 @@ def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_optio if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return - set_boat_repair_rules(logic, multi_world, player) - set_island_parrot_rules(logic, multi_world, player) - MultiWorldRules.add_rule(multi_world.get_location("Open Professor Snail Cave", player), + set_boat_repair_rules(logic, multiworld, player) + set_island_parrot_rules(logic, multiworld, player) + MultiWorldRules.add_rule(multiworld.get_location("Open Professor Snail Cave", player), logic.has(Bomb.cherry_bomb).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Complete Island Field Office", player), + MultiWorldRules.add_rule(multiworld.get_location("Complete Island Field Office", player), logic.can_complete_field_office().simplify()) -def set_boat_repair_rules(logic: StardewLogic, multi_world, player): - MultiWorldRules.add_rule(multi_world.get_location("Repair Boat Hull", player), +def set_boat_repair_rules(logic: StardewLogic, multiworld, player): + MultiWorldRules.add_rule(multiworld.get_location("Repair Boat Hull", player), logic.has(Material.hardwood).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Repair Boat Anchor", player), + MultiWorldRules.add_rule(multiworld.get_location("Repair Boat Anchor", player), logic.has(MetalBar.iridium).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Repair Ticket Machine", player), + MultiWorldRules.add_rule(multiworld.get_location("Repair Ticket Machine", player), logic.has(ArtisanGood.battery_pack).simplify()) -def set_island_entrances_rules(logic: StardewLogic, multi_world, player): +def set_island_entrances_rules(logic: StardewLogic, multiworld, player): boat_repaired = logic.received(Transportation.boat_repair).simplify() - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.fish_shop_to_boat_tunnel, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fish_shop_to_boat_tunnel, player), boat_repaired) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.boat_to_ginger_island, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.boat_to_ginger_island, player), boat_repaired) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_south_to_west, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_west, player), logic.received("Island West Turtle").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_south_to_north, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_north, player), logic.received("Island North Turtle").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_west_to_islandfarmhouse, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_islandfarmhouse, player), logic.received("Island Farmhouse").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_west_to_gourmand_cave, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_gourmand_cave, player), logic.received("Island Farmhouse").simplify()) dig_site_rule = logic.received("Dig Site Bridge").simplify() MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_dig_site, player), dig_site_rule) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), logic.received("Open Professor Snail Cave").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_island_trader, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_island_trader, player), logic.received("Island Trader").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_south_to_southeast, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_southeast, player), logic.received("Island Resort").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.use_island_resort, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_resort, player), logic.received("Island Resort").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_west_to_qi_walnut_room, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_qi_walnut_room, player), logic.received("Qi Walnut Room").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_north_to_volcano, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_volcano, player), (logic.tool.can_water(0) | logic.received("Volcano Bridge") | logic.mod.magic.can_blink()).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.volcano_to_secret_beach, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.volcano_to_secret_beach, player), logic.tool.can_water(2).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.climb_to_volcano_5, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.talk_to_volcano_dwarf, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), logic.wallet.can_speak_dwarf()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.climb_to_volcano_10, player), + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_docks_to_dig_site, @@ -414,75 +420,75 @@ def set_island_entrances_rules(logic: StardewLogic, multi_world, player): MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), parrot_express_rule) -def set_island_parrot_rules(logic: StardewLogic, multi_world, player): +def set_island_parrot_rules(logic: StardewLogic, multiworld, player): has_walnut = logic.has_walnut(1).simplify() has_5_walnut = logic.has_walnut(5).simplify() has_10_walnut = logic.has_walnut(10).simplify() has_20_walnut = logic.has_walnut(20).simplify() - MultiWorldRules.add_rule(multi_world.get_location("Leo's Parrot", player), + MultiWorldRules.add_rule(multiworld.get_location("Leo's Parrot", player), has_walnut) - MultiWorldRules.add_rule(multi_world.get_location("Island West Turtle", player), + MultiWorldRules.add_rule(multiworld.get_location("Island West Turtle", player), has_10_walnut & logic.received("Island North Turtle")) - MultiWorldRules.add_rule(multi_world.get_location("Island Farmhouse", player), + MultiWorldRules.add_rule(multiworld.get_location("Island Farmhouse", player), has_20_walnut) - MultiWorldRules.add_rule(multi_world.get_location("Island Mailbox", player), + MultiWorldRules.add_rule(multiworld.get_location("Island Mailbox", player), has_5_walnut & logic.received("Island Farmhouse")) - MultiWorldRules.add_rule(multi_world.get_location(Transportation.farm_obelisk, player), + MultiWorldRules.add_rule(multiworld.get_location(Transportation.farm_obelisk, player), has_20_walnut & logic.received("Island Mailbox")) - MultiWorldRules.add_rule(multi_world.get_location("Dig Site Bridge", player), + MultiWorldRules.add_rule(multiworld.get_location("Dig Site Bridge", player), has_10_walnut & logic.received("Island West Turtle")) - MultiWorldRules.add_rule(multi_world.get_location("Island Trader", player), + MultiWorldRules.add_rule(multiworld.get_location("Island Trader", player), has_10_walnut & logic.received("Island Farmhouse")) - MultiWorldRules.add_rule(multi_world.get_location("Volcano Bridge", player), + MultiWorldRules.add_rule(multiworld.get_location("Volcano Bridge", player), has_5_walnut & logic.received("Island West Turtle") & logic.region.can_reach(Region.volcano_floor_10)) - MultiWorldRules.add_rule(multi_world.get_location("Volcano Exit Shortcut", player), + MultiWorldRules.add_rule(multiworld.get_location("Volcano Exit Shortcut", player), has_5_walnut & logic.received("Island West Turtle")) - MultiWorldRules.add_rule(multi_world.get_location("Island Resort", player), + MultiWorldRules.add_rule(multiworld.get_location("Island Resort", player), has_20_walnut & logic.received("Island Farmhouse")) - MultiWorldRules.add_rule(multi_world.get_location(Transportation.parrot_express, player), + MultiWorldRules.add_rule(multiworld.get_location(Transportation.parrot_express, player), has_10_walnut) -def set_cropsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options: StardewOptions): - if world_options[options.Cropsanity] == options.Cropsanity.option_disabled: +def set_cropsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + if world_options.cropsanity == Cropsanity.option_disabled: return harvest_prefix = "Harvest " harvest_prefix_length = len(harvest_prefix) for harvest_location in locations.locations_by_tag[LocationTags.CROPSANITY]: - if harvest_location.name in all_location_names and (harvest_location.mod_name is None or harvest_location.mod_name in world_options[options.Mods]): + if harvest_location.name in all_location_names and (harvest_location.mod_name is None or harvest_location.mod_name in world_options.mods): crop_name = harvest_location.name[harvest_prefix_length:] - MultiWorldRules.set_rule(multi_world.get_location(harvest_location.name, player), + MultiWorldRules.set_rule(multiworld.get_location(harvest_location.name, player), logic.has(crop_name).simplify()) -def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options: StardewOptions): +def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): for quest in locations.locations_by_tag[LocationTags.QUEST]: - if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options[options.Mods]): - MultiWorldRules.set_rule(multi_world.get_location(quest.name, player), + if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options.mods): + MultiWorldRules.set_rule(multiworld.get_location(quest.name, player), logic.quest_rules[quest.name].simplify()) -def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, - world_options: StardewOptions): - if world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_disabled: +def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, + world_options: StardewValleyOptions): + if world_options.special_order_locations == SpecialOrderLocations.option_disabled: return board_rule = logic.received("Special Order Board") & logic.time.has_lived_months(4) for board_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD]: if board_order.name in all_location_names: order_rule = board_rule & logic.special_order.special_order_rules[board_order.name] - MultiWorldRules.set_rule(multi_world.get_location(board_order.name, player), order_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(board_order.name, player), order_rule.simplify()) - if world_options[options.ExcludeGingerIsland] == options.ExcludeGingerIsland.option_true: + if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return - if world_options[options.SpecialOrderLocations] == options.SpecialOrderLocations.option_board_only: + if world_options.special_order_locations == SpecialOrderLocations.option_board_only: return qi_rule = logic.region.can_reach(Region.qi_walnut_room) & logic.time.has_lived_months(8) for qi_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_QI]: if qi_order.name in all_location_names: order_rule = qi_rule & logic.special_order.special_order_rules[qi_order.name] - MultiWorldRules.set_rule(multi_world.get_location(qi_order.name, player), order_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(qi_order.name, player), order_rule.simplify()) help_wanted_prefix = "Help Wanted:" @@ -492,8 +498,8 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, slay_monsters = "Slay Monsters" -def set_help_wanted_quests_rules(logic: StardewLogic, multi_world, player, world_options): - help_wanted_number = world_options[options.HelpWantedLocations] +def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + help_wanted_number = world_options.help_wanted_locations.value for i in range(0, help_wanted_number): set_number = i // 7 month_rule = logic.time.has_lived_months(set_number).simplify() @@ -501,23 +507,23 @@ def set_help_wanted_quests_rules(logic: StardewLogic, multi_world, player, world quest_number_in_set = i % 7 if quest_number_in_set < 4: quest_number = set_number * 4 + quest_number_in_set + 1 - set_help_wanted_delivery_rule(multi_world, player, month_rule, quest_number) + set_help_wanted_delivery_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 4: set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 5: set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_number) elif quest_number_in_set == 6: - set_help_wanted_gathering_rule(multi_world, player, month_rule, quest_number) + set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number) -def set_help_wanted_delivery_rule(multi_world, player, month_rule, quest_number): +def set_help_wanted_delivery_rule(multiworld, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {item_delivery} {quest_number}" - MultiWorldRules.set_rule(multi_world.get_location(location_name, player), month_rule) + MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) -def set_help_wanted_gathering_rule(multi_world, player, month_rule, quest_number): +def set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {gathering} {quest_number}" - MultiWorldRules.set_rule(multi_world.get_location(location_name, player), month_rule) + MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) def set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number): @@ -530,26 +536,26 @@ def set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_num MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule.simplify()) -def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world: MultiWorld, player: int): +def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): fish_prefix = "Fishsanity: " for fish_location in locations.locations_by_tag[LocationTags.FISHSANITY]: if fish_location.name in all_location_names: fish_name = fish_location.name[len(fish_prefix):] - MultiWorldRules.set_rule(multi_world.get_location(fish_location.name, player), + MultiWorldRules.set_rule(multiworld.get_location(fish_location.name, player), logic.has(fish_name).simplify()) -def set_museumsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world: MultiWorld, player: int, - world_options: StardewOptions): +def set_museumsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int, + world_options: StardewValleyOptions): museum_prefix = "Museumsanity: " - if world_options[options.Museumsanity] == options.Museumsanity.option_milestones: + if world_options.museumsanity == Museumsanity.option_milestones: for museum_milestone in locations.locations_by_tag[LocationTags.MUSEUM_MILESTONES]: - set_museum_milestone_rule(logic, multi_world, museum_milestone, museum_prefix, player) - elif world_options[options.Museumsanity] != options.Museumsanity.option_none: - set_museum_individual_donations_rules(all_location_names, logic, multi_world, museum_prefix, player) + set_museum_milestone_rule(logic, multiworld, museum_milestone, museum_prefix, player) + elif world_options.museumsanity != Museumsanity.option_none: + set_museum_individual_donations_rules(all_location_names, logic, multiworld, museum_prefix, player) -def set_museum_individual_donations_rules(all_location_names, logic: StardewLogic, multi_world, museum_prefix, player): +def set_museum_individual_donations_rules(all_location_names, logic: StardewLogic, multiworld, museum_prefix, player): all_donations = sorted(locations.locations_by_tag[LocationTags.MUSEUM_DONATIONS], key=lambda x: all_museum_items_by_name[x.name[len(museum_prefix):]].difficulty, reverse=True) counter = 0 @@ -564,7 +570,7 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi counter += 1 -def set_museum_milestone_rule(logic: StardewLogic, multi_world: MultiWorld, museum_milestone, museum_prefix: str, +def set_museum_milestone_rule(logic: StardewLogic, multiworld: MultiWorld, museum_milestone, museum_prefix: str, player: int): milestone_name = museum_milestone.name[len(museum_prefix):] donations_suffix = " Donations" @@ -590,7 +596,7 @@ def set_museum_milestone_rule(logic: StardewLogic, multi_world: MultiWorld, muse rule = logic.museum.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) if rule is None: return - MultiWorldRules.set_rule(multi_world.get_location(museum_milestone.name, player), rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(museum_milestone.name, player), rule.simplify()) def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, accepted_items, donation_func): @@ -601,80 +607,80 @@ def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, acce return rule -def set_backpack_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options): - if world_options[options.BackpackProgression] != options.BackpackProgression.option_vanilla: - MultiWorldRules.set_rule(multi_world.get_location("Large Pack", player), +def set_backpack_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if world_options.backpack_progression != BackpackProgression.option_vanilla: + MultiWorldRules.set_rule(multiworld.get_location("Large Pack", player), logic.money.can_spend(2000).simplify()) - MultiWorldRules.set_rule(multi_world.get_location("Deluxe Pack", player), + MultiWorldRules.set_rule(multiworld.get_location("Deluxe Pack", player), (logic.money.can_spend(10000) & logic.received("Progressive Backpack")).simplify()) - if ModNames.big_backpack in world_options[options.Mods]: - MultiWorldRules.set_rule(multi_world.get_location("Premium Pack", player), + if ModNames.big_backpack in world_options.mods: + MultiWorldRules.set_rule(multiworld.get_location("Premium Pack", player), (logic.money.can_spend(150000) & logic.received("Progressive Backpack", 2)).simplify()) -def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player): +def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): festival_locations = [] festival_locations.extend(locations.locations_by_tag[LocationTags.FESTIVAL]) festival_locations.extend(locations.locations_by_tag[LocationTags.FESTIVAL_HARD]) for festival in festival_locations: if festival.name in all_location_names: - MultiWorldRules.set_rule(multi_world.get_location(festival.name, player), + MultiWorldRules.set_rule(multiworld.get_location(festival.name, player), logic.festival_rules[festival.name].simplify()) monster_eradication_prefix = "Monster Eradication: " -def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): - monstersanity_option = world_options[options.Monstersanity] - if monstersanity_option == options.Monstersanity.option_none: +def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + monstersanity_option = world_options.monstersanity + if monstersanity_option == Monstersanity.option_none: return - if monstersanity_option == options.Monstersanity.option_one_per_monster or monstersanity_option == options.Monstersanity.option_split_goals: - set_monstersanity_monster_rules(all_location_names, logic, multi_world, player, monstersanity_option) + if monstersanity_option == Monstersanity.option_one_per_monster or monstersanity_option == Monstersanity.option_split_goals: + set_monstersanity_monster_rules(all_location_names, logic, multiworld, player, monstersanity_option) return - if monstersanity_option == options.Monstersanity.option_progressive_goals: - set_monstersanity_progressive_category_rules(all_location_names, logic, multi_world, player) + if monstersanity_option == Monstersanity.option_progressive_goals: + set_monstersanity_progressive_category_rules(all_location_names, logic, multiworld, player) return - set_monstersanity_category_rules(all_location_names, logic, multi_world, player, monstersanity_option) + set_monstersanity_category_rules(all_location_names, logic, multiworld, player, monstersanity_option) -def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monstersanity_option): +def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monstersanity_option): for monster_name in all_monsters_by_name: location_name = f"{monster_eradication_prefix}{monster_name}" if location_name not in all_location_names: continue - location = multi_world.get_location(location_name, player) - if monstersanity_option == options.Monstersanity.option_split_goals: + location = multiworld.get_location(location_name, player) + if monstersanity_option == Monstersanity.option_split_goals: rule = logic.monster.can_kill_max(all_monsters_by_name[monster_name]) else: rule = logic.monster.can_kill(all_monsters_by_name[monster_name]) MultiWorldRules.set_rule(location, rule.simplify()) -def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player): +def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): for monster_category in all_monsters_by_category: - set_monstersanity_progressive_single_category_rules(all_location_names, logic, multi_world, player, monster_category) + set_monstersanity_progressive_single_category_rules(all_location_names, logic, multiworld, player, monster_category) -def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monster_category: str): +def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monster_category: str): location_names = [name for name in all_location_names if name.startswith(monster_eradication_prefix) and name.endswith(monster_category)] if not location_names: return location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) for i in range(5): location_name = location_names[i] - set_monstersanity_progressive_category_rule(all_location_names, logic, multi_world, player, monster_category, location_name, i) + set_monstersanity_progressive_category_rule(all_location_names, logic, multiworld, player, monster_category, location_name, i) -def set_monstersanity_progressive_category_rule(all_location_names: List[str], logic: StardewLogic, multi_world, player, +def set_monstersanity_progressive_category_rule(all_location_names: List[str], logic: StardewLogic, multiworld, player, monster_category: str, location_name: str, goal_index): if location_name not in all_location_names: return - location = multi_world.get_location(location_name, player) + location = multiworld.get_location(location_name, player) if goal_index < 3: rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category], goal_index + 1) else: @@ -690,22 +696,22 @@ def get_monster_eradication_number(location_name, monster_category) -> int: return 1000 -def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, monstersanity_option): +def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monstersanity_option): for monster_category in all_monsters_by_category: location_name = f"{monster_eradication_prefix}{monster_category}" if location_name not in all_location_names: continue - location = multi_world.get_location(location_name, player) - if monstersanity_option == options.Monstersanity.option_one_per_category: + location = multiworld.get_location(location_name, player) + if monstersanity_option == Monstersanity.option_one_per_category: rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category]) else: rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], 8) MultiWorldRules.set_rule(location, rule.simplify()) -def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): - shipsanity_option = world_options[options.Shipsanity] - if shipsanity_option == options.Shipsanity.option_none: +def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + shipsanity_option = world_options.shipsanity + if shipsanity_option == Shipsanity.option_none: return shipsanity_prefix = "Shipsanity: " @@ -713,12 +719,12 @@ def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, mul if location.name not in all_location_names: continue item_to_ship = location.name[len(shipsanity_prefix):] - MultiWorldRules.set_rule(multi_world.get_location(location.name, player), logic.shipping.can_ship(item_to_ship)) + MultiWorldRules.set_rule(multiworld.get_location(location.name, player), logic.shipping.can_ship(item_to_ship)) -def set_cooksanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): - cooksanity_option = world_options[options.Cooksanity] - if cooksanity_option == options.Cooksanity.option_none: +def set_cooksanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + cooksanity_option = world_options.cooksanity + if cooksanity_option == Cooksanity.option_none: return cooksanity_prefix = "Cook " @@ -728,12 +734,12 @@ def set_cooksanity_rules(all_location_names: List[str], logic: StardewLogic, mul recipe_name = location.name[len(cooksanity_prefix):] recipe = all_cooking_recipes_by_name[recipe_name] cook_rule = logic.cooking.can_cook(recipe) - MultiWorldRules.set_rule(multi_world.get_location(location.name, player), cook_rule) + MultiWorldRules.set_rule(multiworld.get_location(location.name, player), cook_rule) -def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): - chefsanity_option = world_options[options.Chefsanity] - if chefsanity_option == options.Chefsanity.option_none: +def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + chefsanity_option = world_options.chefsanity + if chefsanity_option == Chefsanity.option_none: return chefsanity_prefix = "Learn Recipe " @@ -743,12 +749,12 @@ def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, mul recipe_name = location.name[len(chefsanity_prefix):] recipe = all_cooking_recipes_by_name[recipe_name] learn_rule = logic.cooking.can_learn_recipe(recipe.source) - MultiWorldRules.set_rule(multi_world.get_location(location.name, player), learn_rule) + MultiWorldRules.set_rule(multiworld.get_location(location.name, player), learn_rule) -def set_craftsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world, player, world_options): - craftsanity_option = world_options[options.Craftsanity] - if craftsanity_option == options.Craftsanity.option_none: +def set_craftsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + craftsanity_option = world_options.craftsanity + if craftsanity_option == Craftsanity.option_none: return craft_prefix = "Craft " @@ -764,41 +770,41 @@ def set_craftsanity_rules(all_location_names: List[str], logic: StardewLogic, mu recipe_name = location.name[len(craft_prefix):] recipe = all_crafting_recipes_by_name[recipe_name] craft_rule = logic.crafting.can_craft(recipe) - MultiWorldRules.set_rule(multi_world.get_location(location.name, player), craft_rule) + MultiWorldRules.set_rule(multiworld.get_location(location.name, player), craft_rule) -def set_traveling_merchant_day_rules(logic: StardewLogic, multi_world: MultiWorld, player: int): +def set_traveling_merchant_day_rules(logic: StardewLogic, multiworld: MultiWorld, player: int): for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" entrance_name = f"Buy from Traveling Merchant {day}" MultiWorldRules.set_rule(multiworld.get_entrance(entrance_name, player), logic.received(item_for_day)) -def set_arcade_machine_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options): - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.play_junimo_kart, player), +def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_junimo_kart, player), logic.received(Wallet.skull_key).simplify()) - if world_options[options.ArcadeMachineLocations] != options.ArcadeMachineLocations.option_full_shuffling: + if world_options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: return - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.play_junimo_kart, player), + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_junimo_kart, player), logic.has("Junimo Kart Small Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_junimo_kart_2, player), + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_junimo_kart_2, player), logic.has("Junimo Kart Medium Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_junimo_kart_3, player), + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_junimo_kart_3, player), logic.has("Junimo Kart Big Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Junimo Kart: Sunset Speedway (Victory)", player), + MultiWorldRules.add_rule(multiworld.get_location("Junimo Kart: Sunset Speedway (Victory)", player), logic.has("Junimo Kart Max Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.play_journey_of_the_prairie_king, player), + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_journey_of_the_prairie_king, player), logic.has("JotPK Small Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_jotpk_world_2, player), + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_jotpk_world_2, player), logic.has("JotPK Medium Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_entrance(Entrance.reach_jotpk_world_3, player), + MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_jotpk_world_3, player), logic.has("JotPK Big Buff").simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Journey of the Prairie King Victory", player), + MultiWorldRules.add_rule(multiworld.get_location("Journey of the Prairie King Victory", player), logic.has("JotPK Max Buff").simplify()) -def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multi_world: MultiWorld, player: int): +def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): friend_prefix = "Friendsanity: " friend_suffix = " <3" for friend_location in locations.locations_by_tag[LocationTags.FRIENDSANITY]: @@ -809,25 +815,25 @@ def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, m split_index = friend_location_trimmed.rindex(" ") friend_name = friend_location_trimmed[:split_index] num_hearts = int(friend_location_trimmed[split_index + 1:]) - MultiWorldRules.set_rule(multi_world.get_location(friend_location.name, player), + MultiWorldRules.set_rule(multiworld.get_location(friend_location.name, player), logic.relationship.can_earn_relationship(friend_name, num_hearts).simplify()) -def set_deepwoods_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options: StardewOptions): - if ModNames.deepwoods in world_options[options.Mods]: - MultiWorldRules.add_rule(multi_world.get_location("Breaking Up Deep Woods Gingerbread House", player), +def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if ModNames.deepwoods in world_options.mods: + MultiWorldRules.add_rule(multiworld.get_location("Breaking Up Deep Woods Gingerbread House", player), logic.tool.has_tool(Tool.axe, "Gold") & logic.mod.deepwoods.can_reach_woods_depth(50).simplify()) - MultiWorldRules.add_rule(multi_world.get_location("Chop Down a Deep Woods Iridium Tree", player), + MultiWorldRules.add_rule(multiworld.get_location("Chop Down a Deep Woods Iridium Tree", player), logic.tool.has_tool(Tool.axe, "Iridium").simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), + MultiWorldRules.set_rule(multiworld.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), logic.received("Woods Obelisk").simplify()) for depth in range(10, 100 + 10, 10): - MultiWorldRules.set_rule(multi_world.get_entrance(move_to_woods_depth(depth), player), + MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), logic.mod.deepwoods.can_chop_to_depth(depth).simplify()) -def set_magic_spell_rules(logic: StardewLogic, multi_world: MultiWorld, player: int, world_options: StardewOptions): - if ModNames.magic not in world_options[options.Mods]: +def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if ModNames.magic not in world_options.mods: return MultiWorldRules.set_rule(multiworld.get_entrance(MagicEntrance.store_to_altar, player), diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 0e0ccc730db8..5116cd47fb6a 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -7,6 +7,8 @@ from ..items import items_by_group, Group, item_table from ..locations import LocationTags from ..mods.mod_data import ModNames +from ..options import Friendsanity, SpecialOrderLocations, Shipsanity, Chefsanity, SeasonRandomization, Craftsanity, ExcludeGingerIsland, ToolProgression, \ + FriendsanityHeartSize def get_real_locations(tester: typing.Union[SVTestBase, SVTestCase], multiworld: MultiWorld): @@ -19,12 +21,12 @@ def get_real_location_names(tester: typing.Union[SVTestBase, SVTestCase], multiw class TestBaseItemGeneration(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, - options.Shipsanity.internal_name: options.Shipsanity.option_everything, - options.Chefsanity.internal_name: options.Chefsanity.option_all, - options.Craftsanity.internal_name: options.Craftsanity.option_all, + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + SeasonRandomization.internal_name: SeasonRandomization.option_progressive, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, + Shipsanity.internal_name: Shipsanity.option_everything, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, } def test_all_progression_items_are_added_to_the_pool(self): @@ -69,12 +71,12 @@ def test_does_not_create_exactly_two_items(self): class TestNoGingerIslandItemGeneration(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, - options.Shipsanity.internal_name: options.Shipsanity.option_everything, - options.Chefsanity.internal_name: options.Chefsanity.option_all, - options.Craftsanity.internal_name: options.Craftsanity.option_all, + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + SeasonRandomization.internal_name: SeasonRandomization.option_progressive, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + Shipsanity.internal_name: Shipsanity.option_everything, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, } def test_all_progression_items_except_island_are_added_to_the_pool(self): @@ -216,7 +218,7 @@ def test_when_generate_world_then_many_rings_shoes_in_the_pool(self): class TestProgressiveElevator(SVTestBase): options = { options.ElevatorProgression.internal_name: options.ElevatorProgression.option_progressive, - options.ToolProgression.internal_name: options.ToolProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive, options.SkillProgression.internal_name: options.SkillProgression.option_progressive, } @@ -336,7 +338,7 @@ def test_allsanity_with_mods_has_at_least_locations(self): class TestFriendsanityNone(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_none, + Friendsanity.internal_name: Friendsanity.option_none, } @property @@ -361,8 +363,8 @@ def check_no_friendsanity_locations(self): class TestFriendsanityBachelors(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_bachelors, - options.FriendsanityHeartSize.internal_name: 1, + Friendsanity.internal_name: Friendsanity.option_bachelors, + FriendsanityHeartSize.internal_name: 1, } bachelors = {"Harvey", "Elliott", "Sam", "Alex", "Shane", "Sebastian", "Emily", "Haley", "Leah", "Abigail", "Penny", "Maru"} @@ -396,8 +398,8 @@ def check_only_bachelors_locations(self): class TestFriendsanityStartingNpcs(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_starting_npcs, - options.FriendsanityHeartSize.internal_name: 1, + Friendsanity.internal_name: Friendsanity.option_starting_npcs, + FriendsanityHeartSize.internal_name: 1, } excluded_npcs = {"Leo", "Krobus", "Dwarf", "Sandy", "Kent"} @@ -436,8 +438,8 @@ def check_only_starting_npcs_locations(self): class TestFriendsanityAllNpcs(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all, - options.FriendsanityHeartSize.internal_name: 4, + Friendsanity.internal_name: Friendsanity.option_all, + FriendsanityHeartSize.internal_name: 4, } def test_friendsanity_all_npcs(self): @@ -489,9 +491,9 @@ def check_locations_are_valid(self): class TestFriendsanityAllNpcsExcludingGingerIsland(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all, - options.FriendsanityHeartSize.internal_name: 4, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + Friendsanity.internal_name: Friendsanity.option_all, + FriendsanityHeartSize.internal_name: 4, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true } def test_friendsanity_all_npcs_exclude_island(self): @@ -530,8 +532,8 @@ def check_locations(self): class TestFriendsanityHeartSize3(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 3, + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + FriendsanityHeartSize.internal_name: 3, } def test_friendsanity_all_npcs_with_marriage(self): @@ -583,8 +585,8 @@ def check_locations_are_valid(self): class TestFriendsanityHeartSize5(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 5, + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + FriendsanityHeartSize.internal_name: 5, } def test_friendsanity_all_npcs_with_marriage(self): @@ -636,7 +638,7 @@ def check_locations_are_valid(self): class TestShipsanityNone(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_none + Shipsanity.internal_name: Shipsanity.option_none } def test_no_shipsanity_locations(self): @@ -649,8 +651,8 @@ def test_no_shipsanity_locations(self): class TestShipsanityCrops(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_crops, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + Shipsanity.internal_name: Shipsanity.option_crops, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi } def test_only_crop_shipsanity_locations(self): @@ -672,8 +674,8 @@ def test_include_island_crop_shipsanity_locations(self): class TestShipsanityCropsExcludeIsland(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_crops, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + Shipsanity.internal_name: Shipsanity.option_crops, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true } def test_only_crop_shipsanity_locations(self): @@ -695,8 +697,8 @@ def test_only_mainland_crop_shipsanity_locations(self): class TestShipsanityCropsNoQiCropWithoutSpecialOrders(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_crops, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_only + Shipsanity.internal_name: Shipsanity.option_crops, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_only } def test_only_crop_shipsanity_locations(self): @@ -718,8 +720,8 @@ def test_island_crops_without_qi_fruit_shipsanity_locations(self): class TestShipsanityFish(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_fish, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + Shipsanity.internal_name: Shipsanity.option_fish, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi } def test_only_fish_shipsanity_locations(self): @@ -742,8 +744,8 @@ def test_include_island_fish_shipsanity_locations(self): class TestShipsanityFishExcludeIsland(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_fish, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + Shipsanity.internal_name: Shipsanity.option_fish, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true } def test_only_fish_shipsanity_locations(self): @@ -766,8 +768,8 @@ def test_exclude_island_fish_shipsanity_locations(self): class TestShipsanityFishExcludeQiOrders(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_fish, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_only + Shipsanity.internal_name: Shipsanity.option_fish, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_only } def test_only_fish_shipsanity_locations(self): @@ -790,8 +792,8 @@ def test_include_island_fish_no_extended_family_shipsanity_locations(self): class TestShipsanityFullShipment(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + Shipsanity.internal_name: Shipsanity.option_full_shipment, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi } def test_only_full_shipment_shipsanity_locations(self): @@ -817,8 +819,8 @@ def test_include_island_items_shipsanity_locations(self): class TestShipsanityFullShipmentExcludeIsland(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + Shipsanity.internal_name: Shipsanity.option_full_shipment, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true } def test_only_full_shipment_shipsanity_locations(self): @@ -844,8 +846,8 @@ def test_exclude_island_items_shipsanity_locations(self): class TestShipsanityFullShipmentExcludeQiBoard(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_disabled + Shipsanity.internal_name: Shipsanity.option_full_shipment, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled } def test_only_full_shipment_shipsanity_locations(self): @@ -871,8 +873,8 @@ def test_exclude_qi_board_items_shipsanity_locations(self): class TestShipsanityFullShipmentWithFish(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi + Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi } def test_only_full_shipment_and_fish_shipsanity_locations(self): @@ -906,8 +908,8 @@ def test_include_island_items_shipsanity_locations(self): class TestShipsanityFullShipmentWithFishExcludeIsland(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true + Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true } def test_only_full_shipment_and_fish_shipsanity_locations(self): @@ -941,8 +943,8 @@ def test_exclude_island_items_shipsanity_locations(self): class TestShipsanityFullShipmentWithFishExcludeQiBoard(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_only + Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_only } def test_only_full_shipment_and_fish_shipsanity_locations(self): diff --git a/worlds/stardew_valley/test/TestOptionFlags.py b/worlds/stardew_valley/test/TestOptionFlags.py index f311156fe17e..b6a2210904e1 100644 --- a/worlds/stardew_valley/test/TestOptionFlags.py +++ b/worlds/stardew_valley/test/TestOptionFlags.py @@ -1,15 +1,17 @@ from . import SVTestBase -from .. import options +from .checks.option_checks import get_stardew_world +from .. import BuildingProgression +from ..options import ToolProgression class TestBitFlagsVanilla(SVTestBase): - options = {options.ToolProgression.internal_name: options.ToolProgression.option_vanilla, - options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla} + options = {ToolProgression.internal_name: ToolProgression.option_vanilla, + BuildingProgression.internal_name: BuildingProgression.option_vanilla} def test_options_are_not_detected_as_progressive(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + world_options = get_stardew_world(self.multiworld).options + tool_progressive = world_options.tool_progression & ToolProgression.option_progressive + building_progressive = world_options.building_progression & BuildingProgression.option_progressive self.assertFalse(tool_progressive) self.assertFalse(building_progressive) @@ -20,13 +22,13 @@ def test_tools_and_buildings_not_in_pool(self): class TestBitFlagsVanillaCheap(SVTestBase): - options = {options.ToolProgression.internal_name: options.ToolProgression.option_vanilla_cheap, - options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla_cheap} + options = {ToolProgression.internal_name: ToolProgression.option_vanilla_cheap, + BuildingProgression.internal_name: BuildingProgression.option_vanilla_cheap} def test_options_are_not_detected_as_progressive(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + world_options = get_stardew_world(self.multiworld).options + tool_progressive = world_options.tool_progression & ToolProgression.option_progressive + building_progressive = world_options.building_progression & BuildingProgression.option_progressive self.assertFalse(tool_progressive) self.assertFalse(building_progressive) @@ -37,13 +39,13 @@ def test_tools_and_buildings_not_in_pool(self): class TestBitFlagsVanillaVeryCheap(SVTestBase): - options = {options.ToolProgression.internal_name: options.ToolProgression.option_vanilla_very_cheap, - options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla_very_cheap} + options = {ToolProgression.internal_name: ToolProgression.option_vanilla_very_cheap, + BuildingProgression.internal_name: BuildingProgression.option_vanilla_very_cheap} def test_options_are_not_detected_as_progressive(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + world_options = get_stardew_world(self.multiworld).options + tool_progressive = world_options.tool_progression & ToolProgression.option_progressive + building_progressive = world_options.building_progression & BuildingProgression.option_progressive self.assertFalse(tool_progressive) self.assertFalse(building_progressive) @@ -54,13 +56,13 @@ def test_tools_and_buildings_not_in_pool(self): class TestBitFlagsProgressive(SVTestBase): - options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive, - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive} + options = {ToolProgression.internal_name: ToolProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive} def test_options_are_detected_as_progressive(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + world_options = get_stardew_world(self.multiworld).options + tool_progressive = world_options.tool_progression & ToolProgression.option_progressive + building_progressive = world_options.building_progression & BuildingProgression.option_progressive self.assertTrue(tool_progressive) self.assertTrue(building_progressive) @@ -71,13 +73,13 @@ def test_tools_and_buildings_in_pool(self): class TestBitFlagsProgressiveCheap(SVTestBase): - options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive_cheap, - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_cheap} + options = {ToolProgression.internal_name: ToolProgression.option_progressive_cheap, + BuildingProgression.internal_name: BuildingProgression.option_progressive_cheap} def test_options_are_detected_as_progressive(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + world_options = get_stardew_world(self.multiworld).options + tool_progressive = world_options.tool_progression & ToolProgression.option_progressive + building_progressive = world_options.building_progression & BuildingProgression.option_progressive self.assertTrue(tool_progressive) self.assertTrue(building_progressive) @@ -88,13 +90,13 @@ def test_tools_and_buildings_in_pool(self): class TestBitFlagsProgressiveVeryCheap(SVTestBase): - options = {options.ToolProgression.internal_name: options.ToolProgression.option_progressive_very_cheap, - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_very_cheap} + options = {ToolProgression.internal_name: ToolProgression.option_progressive_very_cheap, + BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap} def test_options_are_detected_as_progressive(self): - world_options = self.multiworld.worlds[self.player].options - tool_progressive = world_options[options.ToolProgression] & options.ToolProgression.option_progressive - building_progressive = world_options[options.BuildingProgression] & options.BuildingProgression.option_progressive + world_options = get_stardew_world(self.multiworld).options + tool_progressive = world_options.tool_progression & ToolProgression.option_progressive + building_progressive = world_options.building_progression & BuildingProgression.option_progressive self.assertTrue(tool_progressive) self.assertTrue(building_progressive) diff --git a/worlds/stardew_valley/test/TestRegions.py b/worlds/stardew_valley/test/TestRegions.py index 7ebbcece5c2c..71794cf9a119 100644 --- a/worlds/stardew_valley/test/TestRegions.py +++ b/worlds/stardew_valley/test/TestRegions.py @@ -39,7 +39,7 @@ def test_entrance_randomization(self): with self.subTest(flag=flag, msg=f"Seed: {seed}"): rand = random.Random(seed) world_options = {EntranceRandomization.internal_name: option, - ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false} + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false} multiworld = setup_solo_multiworld(world_options) regions_by_name = {region.name: region for region in vanilla_regions} @@ -65,7 +65,7 @@ def test_entrance_randomization_without_island(self): seed = random.randrange(sys.maxsize) rand = random.Random(seed) world_options = {EntranceRandomization.internal_name: option, - ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true} + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true} multiworld = setup_solo_multiworld(world_options) regions_by_name = {region.name: region for region in vanilla_regions} diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index d1495d852b93..ded1f37e2e60 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -4,79 +4,73 @@ from .. import options from ..data.craftable_data import all_crafting_recipes_by_name from ..locations import locations_by_tag, LocationTags, location_table -from ..strings.animal_names import Animal -from ..strings.animal_product_names import AnimalProduct -from ..strings.artisan_good_names import ArtisanGood -from ..strings.crop_names import Vegetable +from ..options import ToolProgression, BuildingProgression, ExcludeGingerIsland, Chefsanity, Craftsanity, Shipsanity, SeasonRandomization, Friendsanity, \ + FriendsanityHeartSize from ..strings.entrance_names import Entrance -from ..strings.food_names import Meal -from ..strings.ingredient_names import Ingredient -from ..strings.machine_names import Machine from ..strings.region_names import Region -from ..strings.season_names import Season -from ..strings.seed_names import Seed class TestProgressiveToolsLogic(SVTestBase): options = { - options.ToolProgression.internal_name: options.ToolProgression.option_progressive, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized, + ToolProgression.internal_name: ToolProgression.option_progressive, + SeasonRandomization.internal_name: SeasonRandomization.option_randomized, } - def setUp(self): - super().setUp() + def test_sturgeon(self): self.multiworld.state.prog_items = {1: Counter()} - def test_sturgeon(self): - self.assertFalse(self.world.logic.has("Sturgeon")(self.multiworld.state)) + sturgeon_rule = self.world.logic.has("Sturgeon") + self.assertFalse(sturgeon_rule(self.multiworld.state)) summer = self.world.create_item("Summer") - self.multiworld.state.collect(summer, event=True) - self.assertFalse(self.world.logic.has("Sturgeon")(self.multiworld.state)) + self.multiworld.state.collect(summer, event=False) + self.assertFalse(sturgeon_rule(self.multiworld.state)) fishing_rod = self.world.create_item("Progressive Fishing Rod") - self.multiworld.state.collect(fishing_rod, event=True) - self.multiworld.state.collect(fishing_rod, event=True) - self.assertFalse(self.world.logic.has("Sturgeon")(self.multiworld.state)) + self.multiworld.state.collect(fishing_rod, event=False) + self.multiworld.state.collect(fishing_rod, event=False) + self.assertFalse(sturgeon_rule(self.multiworld.state)) fishing_level = self.world.create_item("Fishing Level") - self.multiworld.state.collect(fishing_level, event=True) - self.assertFalse(self.world.logic.has("Sturgeon")(self.multiworld.state)) + self.multiworld.state.collect(fishing_level, event=False) + self.assertFalse(sturgeon_rule(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) - self.assertTrue(self.world.logic.has("Sturgeon")(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.assertTrue(sturgeon_rule(self.multiworld.state)) self.remove(summer) - self.assertFalse(self.world.logic.has("Sturgeon")(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state)) winter = self.world.create_item("Winter") - self.multiworld.state.collect(winter, event=True) - self.assertTrue(self.world.logic.has("Sturgeon")(self.multiworld.state)) + self.multiworld.state.collect(winter, event=False) + self.assertTrue(sturgeon_rule(self.multiworld.state)) self.remove(fishing_rod) - self.assertFalse(self.world.logic.has("Sturgeon")(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state)) def test_old_master_cannoli(self): - self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=True) - self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=True) - self.multiworld.state.collect(self.world.create_item("Summer"), event=True) + self.multiworld.state.prog_items = 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.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) fall = self.world.create_item("Fall") - self.multiworld.state.collect(fall, event=True) + self.multiworld.state.collect(fall, event=False) self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) tuesday = self.world.create_item("Traveling Merchant: Tuesday") - self.multiworld.state.collect(tuesday, event=True) + self.multiworld.state.collect(tuesday, event=False) self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) rare_seed = self.world.create_item("Rare Seed") - self.multiworld.state.collect(rare_seed, event=True) + self.multiworld.state.collect(rare_seed, event=False) self.assertTrue(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) self.remove(fall) @@ -84,11 +78,11 @@ def test_old_master_cannoli(self): self.remove(tuesday) green_house = self.world.create_item("Greenhouse") - self.multiworld.state.collect(green_house, event=True) + self.multiworld.state.collect(green_house, event=False) self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) friday = self.world.create_item("Traveling Merchant: Friday") - self.multiworld.state.collect(friday, event=True) + 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) @@ -106,7 +100,7 @@ def test_vault_2500g_bundle(self): class TestBuildingLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive_early_shipping_bin + BuildingProgression.internal_name: BuildingProgression.option_progressive_early_shipping_bin } def test_coop_blueprint(self): @@ -265,7 +259,7 @@ def test_prairie_king(self): class TestWeaponsLogic(SVTestBase): options = { - options.ToolProgression.internal_name: options.ToolProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive, options.SkillProgression.internal_name: options.SkillProgression.option_progressive, } @@ -356,11 +350,11 @@ def test_has_rules(self): class TestRecipeLearnLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_enabled, options.Cooksanity.internal_name: options.Cooksanity.option_all, - options.Chefsanity.internal_name: options.Chefsanity.option_none, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + Chefsanity.internal_name: Chefsanity.option_none, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } def test_can_learn_qos_recipe(self): @@ -381,11 +375,11 @@ def test_can_learn_qos_recipe(self): class TestRecipeReceiveLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, options.Cooksanity.internal_name: options.Cooksanity.option_all, - options.Chefsanity.internal_name: options.Chefsanity.option_all, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + Chefsanity.internal_name: Chefsanity.option_all, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } def test_can_learn_qos_recipe(self): @@ -436,10 +430,10 @@ def test_get_chefsanity_check_recipe(self): class TestCraftsanityLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, - options.Craftsanity.internal_name: options.Craftsanity.option_all, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + Craftsanity.internal_name: Craftsanity.option_all, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } def test_can_craft_recipe(self): @@ -483,11 +477,11 @@ def test_can_craft_festival_recipe(self): class TestCraftsanityWithFestivalsLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, options.FestivalLocations.internal_name: options.FestivalLocations.option_easy, - options.Craftsanity.internal_name: options.Craftsanity.option_all, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + Craftsanity.internal_name: Craftsanity.option_all, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } def test_can_craft_festival_recipe(self): @@ -506,12 +500,12 @@ def test_can_craft_festival_recipe(self): class TestNoCraftsanityLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, + SeasonRandomization.internal_name: SeasonRandomization.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, - options.Craftsanity.internal_name: options.Craftsanity.option_none, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + Craftsanity.internal_name: Craftsanity.option_none, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } def test_can_craft_recipe(self): @@ -532,11 +526,11 @@ def test_can_craft_festival_recipe(self): class TestNoCraftsanityWithFestivalsLogic(SVTestBase): options = { - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, options.FestivalLocations.internal_name: options.FestivalLocations.option_easy, - options.Craftsanity.internal_name: options.Craftsanity.option_none, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, + Craftsanity.internal_name: Craftsanity.option_none, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } def test_can_craft_festival_recipe(self): @@ -625,9 +619,9 @@ def collect_all_except(multiworld, item_to_not_collect: str): class TestFriendsanityDatingRules(SVTestBase): options = { - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized_not_winter, - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 3 + 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): @@ -638,9 +632,9 @@ def test_earning_dating_heart_requires_dating(self): self.multiworld.state.collect(self.world.create_item("Beach Bridge"), event=False) self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False) self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False) - self.multiworld.state.collect(self.world.create_item("Galaxy Hammer"), 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): @@ -672,20 +666,19 @@ def assert_can_reach_heart_up_to(self, npc: str, max_reachable: int, step: int): if i % step != 0 and i != 14: continue location = f"{prefix}{npc} {i}{suffix}" - can_reach = self.world.logic.can_reach_location(location)(self.multiworld.state) + 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.can_reach_location(location)(self.multiworld.state) + 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 = { - options.Shipsanity.internal_name: options.Shipsanity.option_none + Shipsanity.internal_name: Shipsanity.option_none } def test_no_shipsanity_locations(self): @@ -697,7 +690,7 @@ def test_no_shipsanity_locations(self): class TestShipsanityCrops(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_crops + Shipsanity.internal_name: Shipsanity.option_crops } def test_only_crop_shipsanity_locations(self): @@ -708,7 +701,7 @@ def test_only_crop_shipsanity_locations(self): class TestShipsanityFish(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_fish + Shipsanity.internal_name: Shipsanity.option_fish } def test_only_fish_shipsanity_locations(self): @@ -719,7 +712,7 @@ def test_only_fish_shipsanity_locations(self): class TestShipsanityFullShipment(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment + Shipsanity.internal_name: Shipsanity.option_full_shipment } def test_only_full_shipment_shipsanity_locations(self): @@ -731,7 +724,7 @@ def test_only_full_shipment_shipsanity_locations(self): class TestShipsanityFullShipmentWithFish(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_full_shipment_with_fish + Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish } def test_only_full_shipment_and_fish_shipsanity_locations(self): @@ -743,8 +736,8 @@ def test_only_full_shipment_and_fish_shipsanity_locations(self): class TestShipsanityEverything(SVTestBase): options = { - options.Shipsanity.internal_name: options.Shipsanity.option_everything, - options.BuildingProgression.internal_name: options.BuildingProgression.option_progressive + Shipsanity.internal_name: Shipsanity.option_everything, + BuildingProgression.internal_name: BuildingProgression.option_progressive } def test_all_shipsanity_locations_require_shipping_bin(self): @@ -762,62 +755,3 @@ def test_all_shipsanity_locations_require_shipping_bin(self): self.assertTrue(can_reach_shipsanity_location) self.remove(bin_item) - -class TestFriendsanityDatingRules(SVTestBase): - options = { - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized_not_winter, - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.FriendsanityHeartSize.internal_name: 3 - } - - def test_earning_dating_heart_requires_dating(self): - month_name = "Month End" - for i in range(12): - month_item = self.world.create_item(month_name) - self.multiworld.state.collect(month_item, event=True) - self.multiworld.state.collect(self.world.create_item("Beach Bridge"), event=False) - self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False) - self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), 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") - diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 43e5c7d4a9ef..366c37dca58a 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -12,39 +12,40 @@ from worlds.AutoWorld import call_all from ..options import Cropsanity, SkillProgression, SpecialOrderLocations, Friendsanity, NumberOfLuckBuffs, SeasonRandomization, ToolProgression, \ ElevatorProgression, Museumsanity, BackpackProgression, BuildingProgression, ArcadeMachineLocations, HelpWantedLocations, Fishsanity, NumberOfMovementBuffs, \ - BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods + BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods, Monstersanity, Shipsanity, \ + Cooksanity, Chefsanity, Craftsanity def get_minsanity_options(): minsanity = { - options.Goal.internal_name: options.Goal.option_bottom_of_the_mines, - options.BundleRandomization.internal_name: options.BundleRandomization.option_vanilla, - options.BundlePrice.internal_name: options.BundlePrice.option_very_cheap, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_disabled, - options.Cropsanity.internal_name: options.Cropsanity.option_disabled, - options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla, - options.ToolProgression.internal_name: options.ToolProgression.option_vanilla, - options.SkillProgression.internal_name: options.SkillProgression.option_vanilla, - options.BuildingProgression.internal_name: options.BuildingProgression.option_vanilla, - options.FestivalLocations.internal_name: options.FestivalLocations.option_disabled, - options.ElevatorProgression.internal_name: options.ElevatorProgression.option_vanilla, - options.ArcadeMachineLocations.internal_name: options.ArcadeMachineLocations.option_disabled, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_disabled, - options.HelpWantedLocations.internal_name: 0, - options.Fishsanity.internal_name: options.Fishsanity.option_none, - options.Museumsanity.internal_name: options.Museumsanity.option_none, - options.Monstersanity.internal_name: options.Monstersanity.option_none, - options.Shipsanity.internal_name: options.Shipsanity.option_none, - options.Cooksanity.internal_name: options.Cooksanity.option_none, - options.Chefsanity.internal_name: options.Chefsanity.option_none, - options.Craftsanity.internal_name: options.Craftsanity.option_none, - options.Friendsanity.internal_name: options.Friendsanity.option_none, - options.FriendsanityHeartSize.internal_name: 8, - options.NumberOfMovementBuffs.internal_name: 0, - options.NumberOfLuckBuffs.internal_name: 0, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, - options.TrapItems.internal_name: options.TrapItems.option_no_traps, - options.Mods.internal_name: (), + Goal.internal_name: Goal.option_bottom_of_the_mines, + BundleRandomization.internal_name: BundleRandomization.option_vanilla, + BundlePrice.internal_name: BundlePrice.option_very_cheap, + SeasonRandomization.internal_name: SeasonRandomization.option_disabled, + Cropsanity.internal_name: Cropsanity.option_disabled, + BackpackProgression.internal_name: BackpackProgression.option_vanilla, + ToolProgression.internal_name: ToolProgression.option_vanilla, + SkillProgression.internal_name: SkillProgression.option_vanilla, + BuildingProgression.internal_name: BuildingProgression.option_vanilla, + FestivalLocations.internal_name: FestivalLocations.option_disabled, + ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, + ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, + HelpWantedLocations.internal_name: 0, + Fishsanity.internal_name: Fishsanity.option_none, + Museumsanity.internal_name: Museumsanity.option_none, + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_none, + Craftsanity.internal_name: Craftsanity.option_none, + Friendsanity.internal_name: Friendsanity.option_none, + FriendsanityHeartSize.internal_name: 8, + NumberOfMovementBuffs.internal_name: 0, + NumberOfLuckBuffs.internal_name: 0, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + TrapItems.internal_name: TrapItems.option_no_traps, + Mods.internal_name: (), } return minsanity @@ -81,6 +82,8 @@ def world_setup(self, *args, **kwargs): @property def run_default_tests(self) -> bool: + if self.skip_long_tests: + return False # world_setup is overridden, so it'd always run default tests when importing SVTestBase is_not_stardew_test = type(self) is not SVTestBase should_run_default_tests = is_not_stardew_test and super().run_default_tests @@ -112,9 +115,9 @@ def minimal_locations_maximal_items(): FriendsanityHeartSize.internal_name: 8, NumberOfMovementBuffs.internal_name: 12, NumberOfLuckBuffs.internal_name: 12, - options.ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - options.TrapItems.internal_name: TrapItems.option_nightmare, - options.Mods.internal_name: (), + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + TrapItems.internal_name: TrapItems.option_nightmare, + Mods.internal_name: (), } return min_max_options diff --git a/worlds/stardew_valley/test/checks/goal_checks.py b/worlds/stardew_valley/test/checks/goal_checks.py index d0f06a6caafa..314904e9cd81 100644 --- a/worlds/stardew_valley/test/checks/goal_checks.py +++ b/worlds/stardew_valley/test/checks/goal_checks.py @@ -33,7 +33,7 @@ def is_not_perfection(multiworld: MultiWorld) -> bool: def assert_ginger_island_is_included(tester: SVTestBase, multiworld: MultiWorld): - tester.assertEqual(get_stardew_options(multiworld).exclude_ginger_island, options.ExcludeGingerIsland.option_false) + tester.assertEqual(get_stardew_options(multiworld).exclude_ginger_island, ExcludeGingerIsland.option_false) def assert_walnut_hunter_world_is_valid(tester: SVTestBase, multiworld: MultiWorld): diff --git a/worlds/stardew_valley/test/checks/option_checks.py b/worlds/stardew_valley/test/checks/option_checks.py index 358be9f1bea0..ec17337c71fa 100644 --- a/worlds/stardew_valley/test/checks/option_checks.py +++ b/worlds/stardew_valley/test/checks/option_checks.py @@ -52,7 +52,7 @@ def assert_cannot_reach_island(tester: SVTestBase, multiworld: MultiWorld): def assert_can_reach_island_if_should(tester: SVTestBase, multiworld: MultiWorld): stardew_options = get_stardew_options(multiworld) - include_island = stardew_options.exclude_ginger_island.value == options.ExcludeGingerIsland.option_false + include_island = stardew_options.exclude_ginger_island.value == ExcludeGingerIsland.option_false if include_island: assert_can_reach_island(tester, multiworld) else: diff --git a/worlds/stardew_valley/test/mods/TestBiggerBackpack.py b/worlds/stardew_valley/test/mods/TestBiggerBackpack.py index bc81f21963d8..4b35b0471e1b 100644 --- a/worlds/stardew_valley/test/mods/TestBiggerBackpack.py +++ b/worlds/stardew_valley/test/mods/TestBiggerBackpack.py @@ -1,11 +1,11 @@ from .. import SVTestBase -from ... import options from ...mods.mod_data import ModNames +from ...options import Mods, BackpackProgression class TestBiggerBackpackVanilla(SVTestBase): - options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_vanilla, - options.Mods.internal_name: ModNames.big_backpack} + options = {BackpackProgression.internal_name: BackpackProgression.option_vanilla, + Mods.internal_name: ModNames.big_backpack} def test_no_backpack(self): with self.subTest(check="no items"): @@ -20,8 +20,8 @@ def test_no_backpack(self): class TestBiggerBackpackProgressive(SVTestBase): - options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_progressive, - options.Mods.internal_name: ModNames.big_backpack} + options = {BackpackProgression.internal_name: BackpackProgression.option_progressive, + Mods.internal_name: ModNames.big_backpack} def test_backpack(self): with self.subTest(check="has items"): @@ -36,8 +36,8 @@ def test_backpack(self): class TestBiggerBackpackEarlyProgressive(TestBiggerBackpackProgressive): - options = {options.BackpackProgression.internal_name: options.BackpackProgression.option_early_progressive, - options.Mods.internal_name: ModNames.big_backpack} + options = {BackpackProgression.internal_name: BackpackProgression.option_early_progressive, + Mods.internal_name: ModNames.big_backpack} def test_backpack(self): super().test_backpack() diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index f2fd112354d3..8a57fd3e93b4 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -11,7 +11,8 @@ from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions from ...items import item_table, items_by_group from ...locations import location_table -from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems +from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems, Chefsanity, \ + Shipsanity, Craftsanity def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld): @@ -49,13 +50,13 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi class TestBaseItemGeneration(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, - options.SpecialOrderLocations.internal_name: options.SpecialOrderLocations.option_board_qi, - options.Shipsanity.internal_name: options.Shipsanity.option_everything, - options.Chefsanity.internal_name: options.Chefsanity.option_all, - options.Craftsanity.internal_name: options.Craftsanity.option_all, - options.Mods.internal_name: mod_list + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + SeasonRandomization.internal_name: SeasonRandomization.option_progressive, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, + Shipsanity.internal_name: Shipsanity.option_everything, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, + Mods.internal_name: all_mods } def test_all_progression_items_are_added_to_the_pool(self): @@ -75,13 +76,13 @@ def test_all_progression_items_are_added_to_the_pool(self): class TestNoGingerIslandModItemGeneration(SVTestBase): options = { - options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage, - options.SeasonRandomization.internal_name: options.SeasonRandomization.option_progressive, - options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true, - options.Shipsanity.internal_name: options.Shipsanity.option_everything, - options.Chefsanity.internal_name: options.Chefsanity.option_all, - options.Craftsanity.internal_name: options.Craftsanity.option_all, - options.Mods.internal_name: mod_list + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + SeasonRandomization.internal_name: SeasonRandomization.option_progressive, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + Shipsanity.internal_name: Shipsanity.option_everything, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, + Mods.internal_name: all_mods } def test_all_progression_items_except_island_are_added_to_the_pool(self): From cfe4c3426a0c34455b2318275ec1598ffc8c9732 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 11 Oct 2023 13:44:58 -0400 Subject: [PATCH 086/482] - Mod fixes --- worlds/stardew_valley/mods/logic/elevator_logic.py | 3 +-- worlds/stardew_valley/mods/logic/magic_logic.py | 2 -- worlds/stardew_valley/mods/logic/skills_logic.py | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/elevator_logic.py b/worlds/stardew_valley/mods/logic/elevator_logic.py index b1ab38d30057..8c4fc448b412 100644 --- a/worlds/stardew_valley/mods/logic/elevator_logic.py +++ b/worlds/stardew_valley/mods/logic/elevator_logic.py @@ -2,7 +2,6 @@ from ...options import ElevatorProgression, Mods from ...stardew_rule import StardewRule, True_ from ...mods.mod_data import ModNames -from ... import options class ModElevatorLogic: @@ -18,6 +17,6 @@ def __init__(self, player: int, elevator_option: ElevatorProgression, mods: Mods self.received = received def has_skull_cavern_elevator_to_floor(self, floor: int) -> StardewRule: - if self.elevator_option != options.ElevatorProgression.option_vanilla and ModNames.skull_cavern_elevator in self.mods: + if self.elevator_option != ElevatorProgression.option_vanilla and ModNames.skull_cavern_elevator in self.mods: return self.received("Progressive Skull Cavern Elevator", floor // 25) return True_() diff --git a/worlds/stardew_valley/mods/logic/magic_logic.py b/worlds/stardew_valley/mods/logic/magic_logic.py index 7b95ac29ebde..255e1337cff0 100644 --- a/worlds/stardew_valley/mods/logic/magic_logic.py +++ b/worlds/stardew_valley/mods/logic/magic_logic.py @@ -1,5 +1,3 @@ -from typing import Iterable - from ...logic.received_logic import ReceivedLogic from ...logic.region_logic import RegionLogic from ...options import Mods diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 758ffa862033..ff973c31fe83 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -1,5 +1,4 @@ from .magic_logic import MagicLogic -from ... import options from ...logic.action_logic import ActionLogic from ...logic.building_logic import BuildingLogic from ...logic.cooking_logic import CookingLogic @@ -58,7 +57,7 @@ def has_mod_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() - if self.skill_option == options.SkillProgression.option_progressive: + if self.skill_option == SkillProgression.option_progressive: return self.received(f"{skill} Level", level) return self.can_earn_mod_skill_level(skill, level) From a8a93d686bfc087fe024821137839c571348be32 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 4 Aug 2023 19:21:59 -0400 Subject: [PATCH 087/482] - Added Monstersanity locations --- worlds/stardew_valley/options.py | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 81e6b5ffd43e..c52e40edd884 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -490,6 +490,60 @@ class FriendsanityHeartSize(Range): # step = 1 +class Monstersanity(Choice): + """Locations for slaying monsters? + None: There are no checks for slaying monsters + One per category: Every category visible at the adventure guild gives one check + One per Monster: Every unique monster gives one check + Monster Eradication Goals: The Monster Eradication Goals each contain one check + Short Monster Eradication Goals: The Monster Eradication Goals each contain one check, but are reduced by 60% + Very Short Monster Eradication Goals: The Monster Eradication Goals each contain one check, but are reduced by 90% + Progressive Eradication Goals: The Monster Eradication Goals each contain 5 checks, each 20% of the way + Split Eradication Goals: The Monster Eradication Goals are split by monsters, each monster has one check + """ + internal_name = "monstersanity" + display_name = "Monstersanity" + default = 1 + option_none = 0 + option_one_per_category = 1 + option_one_per_monster = 2 + option_goals = 3 + option_short_goals = 4 + option_very_short_goals = 5 + option_progressive_goals = 6 + option_split_goals = 7 + + +class Shipsanity(Choice): + """Locations for shipping items? + None: There are no checks for shipping items + Crops: Every crop being shipped is a check + Quality Crops: Every crop being shipped is a check, but only granted if it is gold-quality + Fish: Every fish being shipped is a check except legendaries + Quality Fish: Every fish being shipped is a check except legendaries, but only granted if it is gold-quality + Full Shipment: Every item in the Collections page is a check + Quality Full Shipment: Every item in the Collections page is a check, but only granted if it is gold-quality when applicable + Full Shipment With Fish: Every item in the Collections page and every fish is a check + Quality Full Shipment With Fish: Every item in the Collections page and every fish is a check, but only granted if it is gold-quality when applicable + Everything: Every item in the game that can be shipped is a check + Quality Everything: Every item in the game that can be shipped is a check, but only granted if it is gold-quality when applicable + """ + internal_name = "shipsanity" + display_name = "Shipsanity" + default = 0 + option_none = 0 + option_crops = 1 + option_quality_crops = 2 + option_fish = 3 + option_quality_fish = 4 + option_full_shipment = 5 + option_quality_full_shipment = 6 + option_full_shipment_with_fish = 7 + option_quality_full_shipment_with_fish = 8 + option_everything = 9 + option_quality_everything = 10 + + class NumberOfMovementBuffs(Range): """Number of movement speed buffs to the player that exist as items in the pool. Each movement speed buff is a +25% multiplier that stacks additively""" From 7bb2fa1ccad22e0bf77e36e958b91a222ed01c76 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 9 Aug 2023 11:02:32 -0400 Subject: [PATCH 088/482] - Changed many items from progression to useful - Fix rules issue with volcano exit shortcut and island south - Disabled simplifying the rules as it apparently improves performance --- worlds/stardew_valley/data/items.csv | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 528a15b58889..1bde7d6512cf 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -79,7 +79,7 @@ id,name,classification,groups,mod_name 93,Shipping Bin,progression,BUILDING, 94,Beach Bridge,progression,, 95,Adventurer's Guild,progression,, -96,Club Card,progression,, +96,Club Card,useful,, 97,Magnifying Glass,progression,, 98,Bear's Knowledge,useful,, 99,Iridium Snake Milk,useful,, @@ -226,13 +226,13 @@ id,name,classification,groups,mod_name 241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +244,10 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", 251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", From b11e1870d7cab8e363779e967b97fa8b91a6ce3a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 24 Aug 2023 11:58:53 -0400 Subject: [PATCH 089/482] - Missing Bundle and changes for recursive region access update --- worlds/stardew_valley/logic/logic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 81587bcaa42c..bd78ebbcebb5 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -886,3 +886,9 @@ def has_movie_theater(self) -> StardewRule: def can_use_obelisk(self, obelisk: str) -> StardewRule: return self.region.can_reach(Region.wizard_tower) & self.region.can_reach(Region.farm) & self.received(obelisk) + def has_abandoned_jojamart(self) -> StardewRule: + return self.received(CommunityUpgrade.movie_theater, 1) + + def has_movie_theater(self) -> StardewRule: + return self.received(CommunityUpgrade.movie_theater, 2) + From 2de0188c3013e2f9db2d976254d177b11d3d6e70 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 26 Aug 2023 12:19:02 -0400 Subject: [PATCH 090/482] - Added minsanity options --- worlds/stardew_valley/logic/logic.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index bd78ebbcebb5..ffc397381b58 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -892,3 +892,6 @@ def has_abandoned_jojamart(self) -> StardewRule: def has_movie_theater(self) -> StardewRule: return self.received(CommunityUpgrade.movie_theater, 2) + def can_use_obelisk(self, obelisk: str) -> StardewRule: + return self.region.can_reach(Region.wizard_tower) & self.region.can_reach(Region.farm) & self.received(obelisk) + From 65d4f536463e12f49b56d0c9451123582d2a5656 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:05:33 -0500 Subject: [PATCH 091/482] - Some fixes --- worlds/stardew_valley/data/items.csv | 14 +++++++------- worlds/stardew_valley/logic/logic.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 1bde7d6512cf..70abdc6f75b5 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -226,13 +226,13 @@ id,name,classification,groups,mod_name 241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", 243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,useful,"GINGER_ISLAND,SPECIAL_ORDER_QI", +244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", 251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index ffc397381b58..15cc7670a855 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -135,7 +135,7 @@ def __post_init__(self): self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) self.cooking = CookingLogic(self.player, self.options.chefsanity, self.options.exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) - self.ability = AbilityLogic(self.player, self.options.number_of_movement_buffs, self.options.number_of_luck_buffs, self.received, + self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) @@ -721,7 +721,7 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: return And(rules) def can_win_egg_hunt(self) -> StardewRule: - number_of_movement_buffs = self.options.number_of_movement_buffs + number_of_movement_buffs = self.options.luck_buff_number if self.options.festival_locations == FestivalLocations.option_hard or number_of_movement_buffs < 2: return True_() return self.received(Buff.movement, number_of_movement_buffs // 2) From baefff91e5b61b2283470fbf9afba59aff31d5c6 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 23 Oct 2023 21:46:44 -0500 Subject: [PATCH 092/482] Create bundle Logic --- worlds/stardew_valley/logic/bundle_logic.py | 46 +++++++++++++++++++++ worlds/stardew_valley/logic/crop_logic.py | 31 +++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 worlds/stardew_valley/logic/bundle_logic.py diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py new file mode 100644 index 000000000000..0ed79fee0256 --- /dev/null +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -0,0 +1,46 @@ +from typing import List + +from ..data.bundle_data import BundleItem +from .crop_logic import CropLogic +from ..logic.has_logic import HasLogic +from ..logic.money_logic import MoneyLogic +from ..logic.region_logic import RegionLogic +from ..stardew_rule import StardewRule +from ..strings.region_names import Region + + +class BundleLogic: + player: int + crop: CropLogic + has: HasLogic + money: MoneyLogic + region: RegionLogic + crop: CropLogic + + def __init__(self, player: int, crop: CropLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + self.player = player + self.crop = crop + self.has = has + self.region = region + self.money = money + + def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: + item_rules = [] + highest_quality_yet = 0 + can_speak_junimo = self.region.can_reach(Region.wizard_tower) + for bundle_item in bundle_requirements: + if bundle_item.item.item_id == -1: + return can_speak_junimo & self.money.can_spend(bundle_item.amount) + else: + item_rules.append(bundle_item.item.name) + if bundle_item.quality > highest_quality_yet: + highest_quality_yet = bundle_item.quality + return can_speak_junimo & self.has(item_rules, number_required) & self.crop.can_grow_gold_quality(highest_quality_yet) + + def can_complete_community_center(self) -> StardewRule: + return (self.region.can_reach_location("Complete Crafts Room") & + self.region.can_reach_location("Complete Pantry") & + self.region.can_reach_location("Complete Fish Tank") & + self.region.can_reach_location("Complete Bulletin Board") & + self.region.can_reach_location("Complete Vault") & + self.region.can_reach_location("Complete Boiler Room")) diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 02f510732865..5ed2d7356464 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -3,9 +3,11 @@ from .has_logic import HasLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic +from .skill_logic import SkillLogic from .tool_logic import ToolLogic from ..data import CropItem -from ..stardew_rule import StardewRule +from ..stardew_rule import StardewRule, True_ +from ..strings.fertilizer_names import Fertilizer from ..strings.region_names import Region from ..strings.tool_names import Tool @@ -15,13 +17,15 @@ class CropLogic: has: HasLogic region: RegionLogic season: SeasonLogic + skill: SkillLogic tool: ToolLogic - def __init__(self, player: int, has: HasLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic): + def __init__(self, player: int, has: HasLogic, region: RegionLogic, season: SeasonLogic, skill: SkillLogic, tool: ToolLogic): self.player = player self.has = has self.region = region self.season = season + self.skill = skill self.tool = tool def can_grow(self, crop: CropItem) -> StardewRule: @@ -43,3 +47,26 @@ def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> Stardew def has_island_farm(self) -> StardewRule: return self.region.can_reach(Region.island_south) + def has_fertilizer(self, tier: int) -> StardewRule: + if tier <= 0: + return True_() + if tier == 1: + return self.has(Fertilizer.basic) + if tier == 2: + return self.has(Fertilizer.quality) + if tier >= 3: + return self.has(Fertilizer.deluxe) + + def can_grow_gold_quality(self, quality: int) -> StardewRule: + if quality <= 0: + return True_() + if quality == 1: + return self.skill.has_farming_level(5) | (self.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( + self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) + if quality == 2: + return self.skill.has_farming_level(10) | (self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( + self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( + self.has_fertilizer(3) & self.skill.has_farming_level(2)) + if quality >= 3: + return self.has_fertilizer(3) & self.skill.has_farming_level(4) + From 535dd470009dbf4a659ff438b5af5eca4096673a Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 23 Oct 2023 21:47:10 -0500 Subject: [PATCH 093/482] Initial SVE Items and Locations --- worlds/stardew_valley/data/items.csv | 29 ++++ worlds/stardew_valley/data/locations.csv | 205 +++++++++++++++++++++++ 2 files changed, 234 insertions(+) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 70abdc6f75b5..59f22a1dcd93 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -753,5 +753,34 @@ id,name,classification,groups,mod_name 10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC 10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley +10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded +10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded +10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded +10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded +10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded +10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded +10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded +10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded +10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded +10502,Diamond Wand,progression,"WEAPON,GINGER_ISLAND",Stardew Valley Expanded +10503,Iridium Bomb,progression,,Stardew Valley Expanded +10504,Krobus' Protection,useful,,Stardew Valley Expanded +10505,Kittyfish Spell,progression,,Stardew Valley Expanded +10506,Nexus: Adventurer's Guild Runes,progression,,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,,Stardew Valley Expanded +10508,Nexus: Aurora Vineyard Runes,progression,,Stardew Valley Expanded +10509,Nexus: Sprite Spring Runes,progression,,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,,Stardew Valley Expanded +10511,Lance's Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded +10512,Super Starfruit,useful,,Stardew Valley Expanded +10513,Tempered Galaxy Sword,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded +10514,Tempered Galaxy Dagger,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded +10515,Tempered Galaxy Hammer,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 6d237f98b4cc..83b46613289c 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2239,6 +2239,170 @@ id,region,name,tags,mod_name 6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley 6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley 6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded +6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded +6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded +6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded +6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded +6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded +6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded +6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded +6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded +6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded +6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded +6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded +6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded +6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded +6153,Highlands,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Highlands,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Highlands,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Highlands,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Highlands,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Highlands,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Highlands,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Highlands,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Highlands,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Highlands,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Highlands,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6167,Jenkins Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6168,Jenkins Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6169,Jenkins Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6170,Jenkins Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6171,Jenkins Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6172,Jenkins Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6173,Jenkins Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6174,Jenkins Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6175,Jenkins Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6176,Jenkins Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6177,Jenkins Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6178,Jenkins Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6179,Jenkins Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6180,Jenkins Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6181,Forest,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded +6182,Forest,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded +6183,Forest,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded +6184,Forest,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded +6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6199,Jenkins Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded +6200,Jenkins Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded +6201,Jenkins Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded +6202,Jenkins Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded +6203,Jenkins Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded +6204,Jenkins Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded +6205,Jenkins Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded +6206,Jenkins Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded +6207,Jenkins Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded +6208,Jenkins Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded +6209,Jenkins Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded +6210,Jenkins Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded +6211,Jenkins Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded +6212,Jenkins Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded +6213,Forest,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded +6214,Forest,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded +6215,Forest,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded +6216,Forest,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded +6217,Forest,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded +6218,Forest,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded +6219,Forest,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded +6220,Forest,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded +6221,Forest,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded +6222,Forest,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded +6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded +6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded +6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded +6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded +6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded +6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded +6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded +6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded +6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded +6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded +6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded +6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded +6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded +6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded +6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded +6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded +6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded +6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded +6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded +6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded +6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded +6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded +6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded +6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded +6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded +6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded +6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded +6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded +6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded +6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded +6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded +6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded +6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded +6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded +6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded +6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded +6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded +6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded +6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded +6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded +6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6273,Blue Moon Vineyard,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded +6274,Blue Moon Vineyard,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded +6275,Blue Moon Vineyard,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded +6276,Blue Moon Vineyard,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded +6277,Blue Moon Vineyard,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded +6278,Blue Moon Vineyard,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded +6279,Blue Moon Vineyard,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded +6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded +6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded +6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Railroad,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Railroad,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Railroad,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Railroad,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Railroad,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Railroad,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Railroad,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Railroad,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Railroad,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Railroad,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded +6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded +6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded +6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded +6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded +6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded +6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded +6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded +6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded +6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded 7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack 7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod 7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods @@ -2272,3 +2436,44 @@ id,region,name,tags,mod_name 7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC 7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC 7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC +7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded +7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded +7509,Farm,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded +7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded +7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded +7512,Sewers,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded +7601,Bear Shop,Bear: Baked Berry Oatmeal Recipe,MANDATORY,Stardew Valley Expanded +7602,Bear Shop,Bear: Flower Cookie Recipe,MANDATORY,Stardew Valley Expanded +7603,Purple Junimo Shop,Purple Junimo: Super Starfruit,MANDATORY,Stardew Valley Expanded +7604,Alesia Shop,Alesia: Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7605,Issac Shop,Issac: Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7606,Issac Shop,Issac: Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7607,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7608,Volcano – Floor 10,Volcano Caldera Prismatic Shard,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7501,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7502,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded +7503,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded +7504,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded +7505,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7506,Highlands,Fishsanity: Daggerfish,FISHSANITY,Stardew Valley Expanded +7507,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded +7508,Highlands,Fishsanity: Gemfish,FISHSANITY,Stardew Valley Expanded +8001,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded +8002,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded +8003,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded +8004,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +8005,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded +8006,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded +8007,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded +8008,Sewers,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +8009,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +8010,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +8011,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +8012,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded +8013,Beach,Fishsanity: Starfish,FISHSANITY,Stardew Valley Expanded +8014,Fable Reef,Fishsanity: Torpedo Trout,FISHSANITY,Stardew Valley Expanded +8015,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded +8016,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded +8017,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded +8018,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded +8019,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded From f150748c35115699ae6a08eec515c492d016d357 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 23 Oct 2023 21:47:50 -0500 Subject: [PATCH 094/482] Add initial SVE regions --- worlds/stardew_valley/mods/mod_data.py | 3 +- worlds/stardew_valley/mods/mod_regions.py | 110 +++++++++++++++++- .../stardew_valley/strings/entrance_names.py | 55 +++++++++ worlds/stardew_valley/strings/region_names.py | 40 +++++++ 4 files changed, 205 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index 30fe96c9d906..25f5cb60071d 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -21,6 +21,7 @@ class ModNames: ayeisha = "Ayeisha - The Postal Worker (Custom NPC)" riley = "Custom NPC - Riley" skull_cavern_elevator = "Skull Cavern Elevator" + sve = "Stardew Valley Expanded" all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, @@ -28,4 +29,4 @@ class ModNames: ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator}) + ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve}) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index b05bc9538dba..805dbd4a5da6 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -1,7 +1,7 @@ from ..strings.entrance_names import DeepWoodsEntrance, EugeneEntrance, \ - JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance + JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, \ - AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion + AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion from ..region_classes import RegionData, ConnectionData, RandomizationFlag, ModRegionData from .mod_data import ModNames @@ -131,6 +131,111 @@ flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA) ] +stardew_valley_expanded_regions = [ + RegionData(Region.backwoods, [SVEEntrance.backwoods_to_grove]), + RegionData(Region.bus_stop, [SVEEntrance.bus_stop_to_shed]), + RegionData(SVERegion.grandpas_shed, [SVEEntrance.grandpa_shed_to_interior, SVEEntrance.grandpa_shed_to_town]), + RegionData(SVERegion.grandpas_shed_interior, [SVEEntrance.to_grandpa_upstairs]), + RegionData(SVERegion.grandpas_shed_upstairs), + RegionData(Region.forest, + [SVEEntrance.forest_to_fairhaven, SVEEntrance.forest_to_west, SVEEntrance.forest_to_junimo, + SVEEntrance.forest_to_bmv, SVEEntrance.forest_to_marnie_shed]), + RegionData(SVERegion.marnies_shed), + RegionData(SVERegion.fairhaven_farm), + RegionData(Region.town, [SVEEntrance.town_to_bmv, SVEEntrance.town_to_jenkins, + SVEEntrance.town_to_bridge, SVEEntrance.town_to_plot]), + RegionData(SVERegion.blue_moon_vineyard, [SVEEntrance.bmv_to_sophia, SVEEntrance.bmv_to_beach]), + RegionData(SVERegion.sophias_house), + RegionData(SVERegion.jenkins_residence, [SVEEntrance.jenkins_to_cellar]), + RegionData(SVERegion.jenkins_cellar), + RegionData(SVERegion.unclaimed_plot, [SVEEntrance.plot_to_bridge]), + RegionData(SVERegion.shearwater), + RegionData(Region.mountain, [SVEEntrance.mountain_to_guild_summit]), + RegionData(SVERegion.guild_summit, [SVEEntrance.guild_to_interior, SVEEntrance.guild_to_mines, + SVEEntrance.summit_to_boat]), + RegionData(SVERegion.marlon_boat, [SVEEntrance.boat_to_highlands]), + RegionData(Region.railroad, [SVEEntrance.to_susan_house, SVEEntrance.enter_summit]), + RegionData(Region.wizard_basement, [SVEEntrance.wizard_to_fable_reef]), + RegionData(SVERegion.fable_reef, [SVEEntrance.fable_reef_to_guild]), + RegionData(SVERegion.first_slash_guild), + RegionData(SVERegion.highlands, [SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave]), + RegionData(SVERegion.highlands_cavern, [SVEEntrance.to_dwarf_prison]), + RegionData(SVERegion.dwarf_prison), + RegionData(SVERegion.lances_house, [SVEEntrance.lance_ladder_to_highlands]), + RegionData(SVERegion.forest_west, [SVEEntrance.forest_west_to_spring, SVEEntrance.west_to_aurora, + SVEEntrance.use_bear_shop]), + RegionData(SVERegion.aurora_vineyard, [SVEEntrance.to_aurora_basement]), + RegionData(SVERegion.aurora_vineyard_basement), + RegionData(Region.secret_woods, [SVEEntrance.secret_woods_to_west]), + RegionData(SVERegion.bear_shop), + RegionData(SVERegion.sprite_spring), + RegionData(SVERegion.junimo_woods, [SVEEntrance.use_purple_junimo]), + RegionData(SVERegion.purple_junimo_shop), + RegionData(SVERegion.enchanted_grove, [SVEEntrance.grove_to_outpost, SVEEntrance.grove_to_wizard, + SVEEntrance.grove_to_farm, SVEEntrance.grove_to_guild, SVEEntrance.grove_to_junimo, + SVEEntrance.grove_to_spring, SVEEntrance.grove_to_aurora]), + RegionData(SVERegion.galmoran_outpost, [SVEEntrance.outpost_to_badlands_entrance, SVEEntrance.use_alesia_shop, + SVEEntrance.use_issac_shop, SVEEntrance.to_outpost_roof]), + RegionData(SVERegion.outpost_roof), + RegionData(SVERegion.badlands_entrance, [SVEEntrance.badlands_entrance_to_badlands]), + RegionData(SVERegion.crimson_badlands, [SVEEntrance.badlands_to_cave]), + RegionData(SVERegion.badlands_cave), + RegionData(SVERegion.alesia_shop), + RegionData(SVERegion.issac_shop), + RegionData(SVERegion.summit), + RegionData(SVERegion.susans_house), + +] + +mandatory_sve_connections = [ + ConnectionData(SVEEntrance.town_to_jenkins, SVERegion.jenkins_residence), + ConnectionData(SVEEntrance.jenkins_to_cellar, SVERegion.jenkins_cellar), + ConnectionData(SVEEntrance.forest_to_bmv, SVERegion.blue_moon_vineyard), + ConnectionData(SVEEntrance.bmv_to_beach, Region.beach), + ConnectionData(SVEEntrance.town_to_plot, SVERegion.unclaimed_plot), + ConnectionData(SVEEntrance.town_to_bmv, SVERegion.blue_moon_vineyard), + ConnectionData(SVEEntrance.town_to_bridge, SVERegion.shearwater), + ConnectionData(SVEEntrance.plot_to_bridge, SVERegion.shearwater), + ConnectionData(SVEEntrance.bus_stop_to_shed, SVERegion.grandpas_shed), + ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior), + ConnectionData(SVEEntrance.to_grandpa_upstairs, SVERegion.grandpas_shed_upstairs), + ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), + ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house), + ConnectionData(SVEEntrance.boat_to_highlands, SVERegion.highlands), + ConnectionData(SVEEntrance.guild_to_interior, SVERegion.guild_summit), + ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove), + ConnectionData(SVEEntrance.grove_to_outpost, SVERegion.galmoran_outpost), + ConnectionData(SVEEntrance.grove_to_wizard, Region.wizard_basement), + ConnectionData(SVEEntrance.grove_to_aurora, SVERegion.aurora_vineyard_basement), + ConnectionData(SVEEntrance.to_aurora_basement, SVERegion.aurora_vineyard_basement), + ConnectionData(SVEEntrance.grove_to_farm, Region.farm), + ConnectionData(SVEEntrance.grove_to_guild, Region.adventurer_guild), + ConnectionData(SVEEntrance.grove_to_junimo, SVERegion.junimo_woods), + ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), + ConnectionData(SVEEntrance.grove_to_spring, SVERegion.sprite_spring), + ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef), + ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance), + ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands), + ConnectionData(SVEEntrance.guild_to_mines, Region.mines), + ConnectionData(SVEEntrance.forest_to_west, SVERegion.forest_west), + ConnectionData(SVEEntrance.secret_woods_to_west, SVERegion.forest_west), + ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard), + ConnectionData(SVEEntrance.forest_to_junimo, SVERegion.junimo_woods), + ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed), + ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring), + ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house), + ConnectionData(SVEEntrance.enter_summit, SVERegion.summit), + ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm), + ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house), + ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands), + ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern), + ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), + ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), + ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop), + ConnectionData(SVEEntrance.use_issac_shop, SVERegion.issac_shop), + ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison), +] + ModDataList = { ModNames.deepwoods: ModRegionData(ModNames.deepwoods, deep_woods_regions, deep_woods_entrances), ModNames.eugene: ModRegionData(ModNames.eugene, eugene_regions, eugene_entrances), @@ -141,4 +246,5 @@ ModNames.magic: ModRegionData(ModNames.magic, magic_regions, magic_entrances), ModNames.ayeisha: ModRegionData(ModNames.ayeisha, ayeisha_regions, ayeisha_entrances), ModNames.riley: ModRegionData(ModNames.riley, riley_regions, riley_entrances), + ModNames.sve: ModRegionData(ModNames.sve, stardew_valley_expanded_regions, mandatory_sve_connections), } diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 0dbcc066766c..1bf2ec203460 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -257,3 +257,58 @@ class AyeishaEntrance: class RileyEntrance: town_to_riley = "Town to Riley's House" + +class SVEEntrance: + backwoods_to_grove = "Backwoods to Enchanted Grove" + grove_to_outpost = "Enchanted Grove to Galmoran Outpost" + grove_to_wizard = "Enchanted Grove to Wizard's Tower" + grove_to_aurora = "Enchanted Grove to Aurora Vineyard Basement" + grove_to_farm = "Enchanted Grove to Farm" + grove_to_guild = "Enchanted Grove to Adventurer's Guild Summit" + grove_to_junimo = "Enchanted Grove to Junimo Woods" + grove_to_spring = "Enchanted Grove to Sprite Springs" + wizard_to_fable_reef = "Wizard's Basement to Fable Reef" + bus_stop_to_shed = "Bus Stop to Grandpa's Shed" + grandpa_shed_to_interior = "Grandpa's Shed to Grandpa's Shed Interior" + grandpa_shed_to_town = "Grandpa's Shed to Town" + to_grandpa_upstairs = "Grandpa's Shed to Grandpa's Shed Upstairs" + forest_to_fairhaven = "Forest to Fairhaven Farm" + forest_to_west = "Forest to Forest West" + forest_to_junimo = "Forest to Junimo Woods" + use_purple_junimo = "Talk to Purple Junimo" + forest_to_bmv = "Forest to Blue Moon Vineyard" + forest_to_marnie_shed = "Forest to Marnie's Shed" + town_to_bmv = "Town to Blue Moon Vineyard" + town_to_jenkins = "Town to Jenkins' Residence" + town_to_bridge = "Town to Shearwater Bridge" + town_to_plot = "Town to Unclaimed Plot" + bmv_to_sophia = "Blue Moon Vineyard to Sophia's House" + bmv_to_beach = "Blue Moon Vineyard to Beach" + jenkins_to_cellar = "Jenkins' House to Jenkins' Cellar" + plot_to_bridge = "Unclaimed Plot to Shearwater Bridge" + mountain_to_guild_summit = "Mountain to Adventurer's Guild Summit" + guild_to_interior = "Adventurer's Guild Summit to Adventurer's Guild" + guild_to_mines = "Adventurer's Guild Summit to The Mines" + summit_to_boat = "Adventurer's Guild Summit to Marlon's Boat" + boat_to_highlands = "Marlon's Boat to Highlands" + to_aurora_basement = "Aurora Vineyard to Aurora Vineyard Basement" + outpost_to_badlands_entrance = "Galmoran Outpost to Badlands Entrance" + use_alesia_shop = "Talk to Alesia" + use_issac_shop = "Talk to Issac" + badlands_entrance_to_badlands = "Badlands Entrance to Crimson Badlands" + badlands_to_cave = "Crimson Badlands to Badlands Cave" + to_susan_house = "Railroad to Susan's House" + enter_summit = "Railroad to Summit" + fable_reef_to_guild = "Fable Reef to First Slash Guild" + highlands_to_lance = "Highlands to Lance's House Main" + highlands_to_cave = "Highlands to Highlands Cave" + to_dwarf_prison = "Highlands Cave to Dwarf Prison" + lance_ladder_to_highlands = "Lance's House Ladder to Highlands" + forest_west_to_spring = "Forest West to Sprite Springs" + west_to_aurora = "Forest West to Aurora Vineyard" + use_bear_shop = "Talk to Bear Shop" + secret_woods_to_west = "Secret Woods to Forest West" + to_outpost_roof = "Galmoran Outpost to Galmoran Outpost Roof" + + + diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 4550f2d7764c..1bbeeedd98b4 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -216,3 +216,43 @@ class AyeishaRegion: class RileyRegion: riley_house = "Riley's House" + + +class SVERegion: + grandpas_shed = "Grandpa's Shed" + grandpas_shed_interior = "Grandpa's Shed Interior" + grandpas_shed_upstairs = "Grandpa's Shed Upstairs" + marnies_shed = "Marnie's Shed" + fairhaven_farm = "Fairhaven Farm" + blue_moon_vineyard = "Blue Moon Vineyard" + sophias_house = "Sophia's House" + jenkins_residence = "Jenkins' Residence" + jenkins_cellar = "Jenkins' Cellar" + unclaimed_plot = "Unclaimed Plot" + shearwater = "Shearwater Bridge" + guild_summit = "Adventurer's Guild Summit" + fable_reef = "Fable Reef" + first_slash_guild = "First Slash Guild" + highlands = "Highlands" + highlands_cavern = "Highlands Cavern" + dwarf_prison = "Drawf Prison" + lances_house = "Lance's House" + forest_west = "Forest West" + aurora_vineyard = "Aurora Vineyard" + aurora_vineyard_basement = "Aurora Vineyard Basement" + bear_shop = "Bear Shop" + sprite_spring = "Sprite Spring" + junimo_woods = "Junimo Woods" + purple_junimo_shop = "Purple Junimo Shop" + enchanted_grove = "Enchanted Grove" + galmoran_outpost = "Galmoran Outpost" + badlands_entrance = "Badlands Entrance" + crimson_badlands = "Crimson Badlands" + alesia_shop = "Alesia Shop" + issac_shop = "Issac Shop" + summit = "Summit" + susans_house = "Susan's House" + marlon_boat = "Marlon's Boat" + badlands_cave = "Badlands Cave" + outpost_roof = "Galmoran Outpost Roof" + From 576af3942c5c82ef7627f3a90eac5fb5d6f9f4ac Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 23 Oct 2023 21:48:22 -0500 Subject: [PATCH 095/482] Add SVE fish and villagers --- worlds/stardew_valley/data/fish_data.py | 43 ++++++++- worlds/stardew_valley/data/villagers_data.py | 91 +++++++++++++++++++ worlds/stardew_valley/strings/fish_names.py | 30 ++++++ .../stardew_valley/strings/villager_names.py | 3 +- 4 files changed, 163 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 5146297c456b..23c889738d96 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -3,8 +3,9 @@ from . import season_data as season from .game_item import GameItem -from ..strings.fish_names import Fish -from ..strings.region_names import Region +from ..strings.fish_names import Fish, SVEFish +from ..strings.region_names import Region, SVERegion +from ..mods.mod_data import ModNames @dataclass(frozen=True) @@ -14,7 +15,7 @@ class FishItem(GameItem): difficulty: int legendary: bool extended_family: bool - mod_name: Optional[str] + mod_name: Optional[str] = None def __repr__(self): return f"{self.name} [{self.item_id}] (Locations: {self.locations} |" \ @@ -42,6 +43,13 @@ def __repr__(self): ginger_island_river = (Region.island_west,) pirate_cove = (Region.pirate_cove,) +crimson_badlands = (SVERegion.crimson_badlands,) +shearwater = (SVERegion.shearwater,) +highlands = (SVERegion.highlands,) +sprite_spring = (SVERegion.sprite_spring,) +fable_reef = (SVERegion.fable_reef,) +vineyard = (SVERegion.vineyard,) + all_fish: List[FishItem] = [] @@ -121,6 +129,35 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un legend_ii = create_fish(Fish.legend_ii, 163, mountain_lake, season.spring, 110, True, True) radioactive_carp = create_fish(Fish.radioactive_carp, 682, sewers, season.all_seasons, 80, True, True) +baby_lunaloo = create_fish(SVEFish.baby_lunaloo, 3006, ginger_island_ocean, season.all_seasons, 15, ModNames.sve) +bonefish = create_fish(SVEFish.bonefish, 3013, crimson_badlands, season.all_seasons, 70, ModNames.sve) +bull_trout = create_fish(SVEFish.bull_trout, 3014, forest_river, season.not_spring, 45, ModNames.sve) +butterfish = create_fish(SVEFish.butterfish, 3015, shearwater, season.not_winter, 75, ModNames.sve) +clownfish = create_fish(SVEFish.clownfish, 3016, ginger_island_ocean, season.all_seasons, 45, ModNames.sve) +daggerfish = create_fish(SVEFish.daggerfish, 3017, highlands, season.all_seasons, 50, ModNames.sve) +frog = create_fish(SVEFish.frog, 3023, mountain_lake, (season.spring, season.summer), 70, ModNames.sve) +gemfish = create_fish(SVEFish.gemfish, 3027, highlands, season.all_seasons, 100, ModNames.sve) +goldenfish = create_fish(SVEFish.goldenfish, 3031, sprite_spring, season.all_seasons, 60, ModNames.sve) +grass_carp = create_fish(SVEFish.grass_carp, 3034, secret_woods, (season.spring, season.summer), 85, ModNames.sve) +king_salmon = create_fish(SVEFish.king_salmon, 3044, forest_river, (season.spring, season.summer), 80, ModNames.sve) +kittyfish = create_fish(SVEFish.kittyfish, 3045, shearwater, (season.fall, season.winter), 85, ModNames.sve) +lunaloo = create_fish(SVEFish.lunaloo, 3049, ginger_island_ocean, season.all_seasons, 70, ModNames.sve) +meteor_carp = create_fish(SVEFish.meteor_carp, 3051, sprite_spring, season.all_seasons, 80, ModNames.sve) +minnow = create_fish(SVEFish.minnow, 3052, town_river, season.all_seasons, 1, ModNames.sve) +puppyfish = create_fish(SVEFish.puppyfish, 3061, shearwater, season.not_winter, 85, ModNames.sve) +radioactive_bass = create_fish(SVEFish.radioactive_bass, 3062, sewers, season.all_seasons, 90, ModNames.sve) +seahorse = create_fish(SVEFish.seahorse, 3068, ginger_island_ocean, season.all_seasons, 25, ModNames.sve) +shiny_lunaloo = create_fish(SVEFish.shiny_lunaloo, 3070, ginger_island_ocean, season.all_seasons, 110, ModNames.sve) +snatcher_worm = create_fish(SVEFish.snatcher_worm, 3075, mutant_bug_lair, season.all_seasons, 75, ModNames.sve) +starfish = create_fish(SVEFish.starfish, 3079, ginger_island_ocean, season.all_seasons, 75, ModNames.sve) +torpedo_trout = create_fish(SVEFish.torpedo_trout, 3084, fable_reef, season.all_seasons, 70, ModNames.sve) +undeadfish = create_fish(SVEFish.undeadfish, 3085, crimson_badlands, season.all_seasons, 80, ModNames.sve) +void_eel = create_fish(SVEFish.void_eel, 3087, witch_swamp, season.all_seasons, 100, ModNames.sve) +water_grub = create_fish(SVEFish.water_grub, 3094, mutant_bug_lair, season.all_seasons, 60, ModNames.sve) +sea_sponge = create_fish(SVEFish.sea_sponge, 3067, ginger_island_ocean, season.all_seasons, 40, ModNames.sve) +dulse_seaweed = create_fish(SVEFish.dulse_seaweed, 3020, vineyard, season.all_seasons, 50, ModNames.sve) + + clam = create_fish("Clam", 372, ocean, season.all_seasons, -1) cockle = create_fish("Cockle", 718, ocean, season.all_seasons, -1) crab = create_fish("Crab", 717, ocean, season.all_seasons, -1) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index c357e35ce849..623c1d0b2273 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -43,6 +43,16 @@ def __repr__(self): secret_woods = (Region.secret_woods,) wizard_tower = (Region.wizard_tower,) +# Stardew Valley Expanded Locations +adventurer = (SVRegion.adventurer_guild,) +highlands = (SVERegion.highlands,) +bluemoon = (SVERegion.blue_moon_vineyard,) +aurora = (SVERegion.aurora_vineyard,) +museum = (SVRegion.museum,) +jojamart = (SVRegion.jojamart,) +railroad = (SVRegion.railroad,) +junimo = (SVERegion.junimo_woods,) + golden_pumpkin = ("Golden Pumpkin",) # magic_rock_candy = ("Magic Rock Candy",) pearl = ("Pearl",) @@ -273,6 +283,70 @@ def __repr__(self): juna_loves = ancient_doll + elvish_jewelry + dinosaur_egg + strange_doll + joja_cola + hashbrowns + pancakes + \ pink_cake + jelly + ghost_crystal + prehistoric_scapula + cherry +glazed_butterfish = ("Glazed Butterfish",) +aged_blue_moon_wine = ("Aged Blue Moon Wine",) +blue_moon_wine = ("Blue Moon Wine",) +daggerfish = ("Daggerfish",) +gemfish = ("Gemfish",) +green_mushroom = ("Green Mushroom",) +monster_mushroom = ("Monster Mushroom",) +swirl_stone = ("Swirl Stone",) +torpedo_trout = ("Torpedo Trout",) +void_shard = ("Void Shard",) +ornate_treasure_chest = ("Ornate Treasure Chest",) +frog_legs = ("Frog Legs",) +void_delight = ("Void Delight",) +void_pebble = ("Void Pebble",) +void_salmon_sushi = ("Void Salmon Sushi",) +puppyfish = ("Puppyfish",) +butterfish = ("Butterfish",) +king_salmon = ("King Salmon",) +frog = ("Frog",) +kittyfish = ("Kittyfish",) +big_bark_burger = ("Big Bark Burger",) +starfruit = ("Starfruit",) +bruschetta = ("Brushetta",) +apricot = ("Apricot",) +ocean_stone = ("Ocean Stone",) +galaxy_soul = ("Galaxy Soul",) +fairy_stone = ("Fairy Stone",) +lunarite = ("Lunarite",) +bean_hotpot = ("Bean Hotpot",) +petrified_slime = ("Petrified Slime",) +ornamental_fan = ("Ornamental Fan",) +ancient_sword = ("Ancient Sword",) +star_shards = ("Star Shards",) +life_elixir = ("Life Elixir",) +juice = ("Juice",) +lobster_bisque = ("Lobster Bisque",) +chowder = ("Chowder",) +goat_milk = ("Goat Milk",) +maple_syrup = ("Maple Syrup",) +cookie = ("Cookie",) +blueberry_tart = ("Blueberry Tart",) + +claire_loves = green_tea + sunflower + energy_tonic + bruschetta + apricot + ocean_stone + glazed_butterfish +lance_loves = aged_blue_moon_wine + daggerfish + galaxy_soul + gemfish + golden_pumpkin + \ + green_mushroom + monster_mushroom + swirl_stone + torpedo_trout + tropical_curry + void_shard + \ + ornate_treasure_chest +olivia_loves = wine + chocolate_cake + pink_cake + golden_mask + golden_relic + \ + blue_moon_wine + aged_blue_moon_wine +sophia_loves = fairy_rose + fairy_stone + puppyfish +victor_loves = spaghetti + battery_pack + duck_feather + lunarite + \ + aged_blue_moon_wine + blue_moon_wine + butterfish +andy_loves = pearl + beer + mead + pale_ale + farmers_lunch + glazed_butterfish + butterfish + \ + king_salmon + blackberry_cobbler +gunther_loves = bean_hotpot + petrified_slime + salmon_dinner + elvish_jewelry + ornamental_fan + \ + dinosaur_egg + rare_disc + ancient_sword + dwarvish_helm + dwarf_gadget + golden_mask + golden_relic + \ + star_shards +marlon_loves = roots_platter + life_elixir + aged_blue_moon_wine + void_delight +martin_loves = juice + ice_cream + big_bark_burger +morgan_loves = iridium_bar + void_egg + void_mayonnaise + frog + kittyfish +morris_loves = lobster_bisque + chowder + truffle_oil + star_shards + aged_blue_moon_wine +scarlett_loves = goat_cheese + duck_feather + goat_milk + cherry + maple_syrup + honey + \ + chocolate_cake + pink_cake + jade + glazed_yams # actually large milk but meh +susan_loves = pancakes + chocolate_cake + pink_cake + ice_cream + cookie + pumpkin_pie + rhubarb_pie + \ + blueberry_tart + blackberry_cobbler + cranberry_candy + red_plate all_villagers: List[Villager] = [] @@ -332,6 +406,23 @@ def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: st yoba = villager(ModNPC.yoba, False, secret_woods, Season.spring, universal_loves + yoba_loves, False, ModNames.yoba) riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley) +# SVE Villagers +claire = villager("Claire", True, town + jojamart, "Fall", universal_loves + claire_loves, True, "Stardew Valley Expanded") +lance = villager("Lance", True, adventurer + highlands + island, "Spring", lance_loves, False, "Stardew Valley Expanded") +mommy = villager("Olivia", True, town, "Spring", universal_loves_no_rabbit_foot + olivia_loves, True, "Stardew Valley Expanded") +sophia = villager("Sophia", True, bluemoon, "Winter", universal_loves_no_rabbit_foot + sophia_loves, True, "Stardew Valley Expanded") +victor = villager("Victor", True, town, "Summer", universal_loves + victor_loves, True, "Stardew Valley Expanded") +andy = villager("Andy", False, forest, "Spring", universal_loves + andy_loves, True, "Stardew Valley Expanded") +apples = villager("Apples", False, aurora + junimo, "Spring", starfruit, False, "Stardew Valley Expanded") +gunther = villager("Gunther", False, museum, "Winter", universal_loves + gunther_loves, True, "Stardew Valley Expanded") +martin = villager("Martin", False, town + jojamart, "Summer", universal_loves + martin_loves, True, "Stardew Valley Expanded") +marlon = villager("Marlon", False, adventurer, "Winter", universal_loves + marlon_loves, False, "Stardew Valley Expanded") +morgan = villager("Morgan", False, forest, "Fall", universal_loves_no_rabbit_foot + morgan_loves, False, "Stardew Valley Expanded") +scarlett = villager("Scarlett", False, bluemoon, "Summer", universal_loves + scarlett_loves, False, "Stardew Valley Expanded") +susan = villager("Susan", False, railroad, "Fall", universal_loves + susan_loves, False, "Stardew Valley Expanded") +morris = villager("Morris", False, jojamart, "Spring", universal_loves + morris_loves, True, "Stardew Valley Expanded") + + all_villagers_by_name: Dict[str, Villager] = {villager.name: villager for villager in all_villagers} all_villagers_by_mod: Dict[str, List[Villager]] = {} all_villagers_by_mod_by_name: Dict[str, Dict[str, Villager]] = {} diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 511745265be0..24fed4c98b94 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -73,5 +73,35 @@ class WaterChest: treasure = "Treasure Chest" +class SVEFish: + baby_lunaloo = "Baby Lunaloo" + bonefish = "Bonefish" + bull_trout = "Bull Trout" + butterfish = "Butterfish" + clownfish = "Clownfish" + daggerfish = "Daggerfish" + frog = "Frog" + gemfish = "Gemfish" + goldenfish = "Goldenfish" + grass_carp = "Grass Carp" + king_salmon = "King Salmon" + kittyfish = "Kittyfish" + lunaloo = "Lunaloo" + meteor_carp = "Meteor Carp" + minnow = "Minnow" + puppyfish = "Puppyfish" + radioactive_bass = "Radioactive Bass" + seahorse = "Seahorse" + shiny_lunaloo = "Shiny Lunaloo" + snatcher_worm = "Snatcher Worm" + starfish = "Starfish" + torpedo_trout = "Torpedo Trout" + undeadfish = "Undeadfish" + void_eel = "Void Eel" + water_grub = "Water Grub" + sea_sponge = "Sea Sponge" + dulse_seaweed = "Dulse Seaweed" + + diff --git a/worlds/stardew_valley/strings/villager_names.py b/worlds/stardew_valley/strings/villager_names.py index 5bf13ea8dd7e..2ff616d3dfd5 100644 --- a/worlds/stardew_valley/strings/villager_names.py +++ b/worlds/stardew_valley/strings/villager_names.py @@ -46,4 +46,5 @@ class ModNPC: riley = "Riley" shiko = "Shiko" wellwick = "Wellwick" - yoba = "Yoba" \ No newline at end of file + yoba = "Yoba" + lance = "Lance" \ No newline at end of file From 2c36aeda239f8f8477eb60cb07c024c5b7a635b7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 23 Oct 2023 21:49:00 -0500 Subject: [PATCH 096/482] Initial SVE logic port --- worlds/stardew_valley/items.py | 10 ++++ worlds/stardew_valley/logic/logic.py | 44 -------------- .../stardew_valley/mods/logic/quests_logic.py | 35 ++++++++++- worlds/stardew_valley/mods/logic/sve_logic.py | 58 +++++++++++++++++++ .../strings/monster_drop_names.py | 7 +++ worlds/stardew_valley/strings/quest_names.py | 9 ++- 6 files changed, 115 insertions(+), 48 deletions(-) create mode 100644 worlds/stardew_valley/mods/logic/sve_logic.py diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index be0c1f74fea9..51166e177787 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -78,6 +78,7 @@ class Group(enum.Enum): CRAFTSANITY = enum.auto() # Mods MAGIC_SPELL = enum.auto() + TEMPERED_GALAXY_WEAPONS = enum.auto() @dataclass(frozen=True) @@ -194,6 +195,8 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items.append(item_factory("Dark Talisman")) create_tv_channels(item_factory, items) create_special_quest_rewards(item_factory, items) + if ModNames.sve in options.mods: + create_special_quest_rewards_sve(item_factory, items) create_stardrops(item_factory, options, items) create_museum_items(item_factory, options, items) create_arcade_machine_items(item_factory, options, items) @@ -327,6 +330,13 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[I items.append(item_factory("Iridium Snake Milk")) items.append(item_factory("Fairy Dust Recipe")) +def create_special_quest_rewards_sve(item_factory: StardewItemFactory, items: List[Item]): + items.append(item_factory("Marlon's Boat Paddle")) + items.append(item_factory("Iridium Bomb")) + items.append(item_factory("Krobus' Protection")) + items.append(item_factory("Kittyfish Spell")) + create_nexus_warps(item_factory, items) + items.append(item_factory("Lance's Fable Reef Portal")) def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): stardrops_classification = get_stardrop_classification(options) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 15cc7670a855..b170446cb202 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -626,42 +626,6 @@ def has_traveling_merchant(self, tier: int = 1): traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] return self.received(traveling_merchant_days, tier) - def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: - item_rules = [] - highest_quality_yet = 0 - can_speak_junimo = self.region.can_reach(Region.wizard_tower) - for bundle_item in bundle_requirements: - if bundle_item.item.item_id == -1: - return can_speak_junimo & self.money.can_spend(bundle_item.amount) - else: - item_rules.append(bundle_item.item.name) - if bundle_item.quality > highest_quality_yet: - highest_quality_yet = bundle_item.quality - return can_speak_junimo & self.has(item_rules, number_required) & self.can_grow_gold_quality(highest_quality_yet) - - def can_grow_gold_quality(self, quality: int) -> StardewRule: - if quality <= 0: - return True_() - if quality == 1: - return self.skill.has_farming_level(5) | (self.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( - self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) - if quality == 2: - return self.skill.has_farming_level(10) | (self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( - self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( - self.has_fertilizer(3) & self.skill.has_farming_level(2)) - if quality >= 3: - return self.has_fertilizer(3) & self.skill.has_farming_level(4) - - def has_fertilizer(self, tier: int) -> StardewRule: - if tier <= 0: - return True_() - if tier == 1: - return self.has(Fertilizer.basic) - if tier == 2: - return self.has(Fertilizer.quality) - if tier >= 3: - return self.has(Fertilizer.deluxe) - def can_complete_field_office(self) -> StardewRule: field_office = self.region.can_reach(Region.field_office) professor_snail = self.received("Open Professor Snail Cave") @@ -675,14 +639,6 @@ def can_complete_field_office(self) -> StardewRule: snake_vertebrae = self.has(Fossil.snake_vertebrae) return field_office & professor_snail & tools & leg_and_snake_skull & ribs_and_spine & skull & tail & frog & bat & snake_vertebrae - def can_complete_community_center(self) -> StardewRule: - return (self.region.can_reach_location("Complete Crafts Room") & - self.region.can_reach_location("Complete Pantry") & - self.region.can_reach_location("Complete Fish Tank") & - self.region.can_reach_location("Complete Bulletin Board") & - self.region.can_reach_location("Complete Vault") & - self.region.can_reach_location("Complete Boiler Room")) - def can_finish_grandpa_evaluation(self) -> StardewRule: # https://stardewvalleywiki.com/Grandpa rules_worth_a_point = [self.money.can_have_earned_total(50000), # 50 000g diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index b01618cddffe..0c7091e8ad1a 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -1,33 +1,48 @@ from typing import Dict +from ...logic.bundle_logic import BundleLogic from ...logic.has_logic import HasLogic from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic +from ...logic.received_logic import ReceivedLogic +from ...logic.time_logic import TimeLogic from ...options import Mods from ...strings.quest_names import ModQuest from ..mod_data import ModNames +from ...strings.artisan_good_names import ArtisanGood +from ...strings.crop_names import Fruit from ...strings.food_names import Meal, Beverage -from ...strings.monster_drop_names import Loot +from ...strings.monster_drop_names import Loot, ModLoot from ...strings.villager_names import ModNPC from ...strings.season_names import Season -from ...strings.region_names import Region +from ...strings.region_names import Region, SVERegion +from ...strings.material_names import Material +from ...strings.metal_names import Ore, MetalBar +from ...strings.wallet_item_names import Wallet from ...stardew_rule import StardewRule class QuestLogic: mods: Mods + bundle: BundleLogic has: HasLogic region: RegionLogic season: SeasonLogic relationship: RelationshipLogic + received: ReceivedLogic + time: TimeLogic - def __init__(self, mods: Mods, has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic): + def __init__(self, bundle: BundleLogic, mods: Mods, has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, + received: ReceivedLogic, time: TimeLogic): + self.bundle = bundle self.mods = mods self.has = has self.region = region self.season = season self.relationship = relationship + self.received = received + self.time = time def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = {} @@ -48,4 +63,18 @@ def get_modded_quest_rules(self) -> Dict[str, StardewRule]: ModQuest.AyeishaRing: self.season.has(Season.winter) & self.region.can_reach(Region.forest) }) + if ModNames.sve in self.mods: + quests.update({ + ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has([Ore.iridium, Material.coal]) & + self.region.can_reach(Region.blacksmith) & self.region.can_reach(Region.railroad), + ModQuest.GrandpasShed: self.has([Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone]) & + self.region.can_reach(SVERegion.grandpas_shed_interior), + ModQuest.MarlonsBoat: self.has([Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat]) & + self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), + ModQuest.AuroraVineyard: self.bundle.can_complete_community_center() & self.has(Fruit.starfruit) & + self.region.can_reach(SVERegion.aurora_vineyard) & self.time.has_year_two(), + ModQuest.MonsterCrops: self.has([ModLoot.monster_mushroom, ModLoot.slime_berry, ModLoot.monster_fruit, ModLoot.void_root]), + ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(ModQuest.VoidSoul), + }) + return quests diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py new file mode 100644 index 000000000000..79739c92778a --- /dev/null +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -0,0 +1,58 @@ +if self.has_mod("Stardew Valley Expanded"): + self.item_rules.update({ + "Aged Blue Moon Wine": self.can_reach_region(SVERegion.sophias_house) & self.can_spend_money(28000), + "Big Bark Burger": self.can_cook() & self.has(["Puppyfish", "Bread", "Oil"]) & + self.has_relationship("Gus", 5) & self.can_spend_money(5500) & + self.can_reach_region(SVRegion.saloon), + "Blue Moon Wine": self.can_reach_region(SVERegion.sophias_house) & self.can_spend_money(3000), + "Fungus Seed": self.can_reach_region(SVERegion.highlands_cavern) & self.has_good_weapon(), + "Glazed Butterfish": self.can_cook() & self.has(["Butterfish", "Wheat", "Oil"]) & + self.has_relationship("Gus", 10) & self.can_spend_money(4000), + "Green Mushroom": self.can_reach_region(SVERegion.highlands) & self.has_tool("Axe", "Iron"), + "Monster Fruit": self.has_season("Summer") & self.has("Stalk Seed"), + "Monster Mushroom": self.has_season("Fall") & self.has("Fungus Seed"), + "Ornate Treasure Chest": self.can_reach_region(SVERegion.highlands) & self.has_galaxy_weapon() & + self.can_cook() & self.has_tool("Axe", "Iron"), + "Slime Berry": self.has_season("Spring") & self.has("Slime Seed"), + "Slime Seed": self.can_reach_region(SVERegion.highlands) & self.has_good_weapon(), + "Stalk Seed": self.can_reach_region(SVERegion.highlands) & self.has_good_weapon(), + "Swirl Stone": self.can_reach_region(SVERegion.crimson_badlands) & self.has_great_weapon(), + "Void Delight": self.has("Void Eel") & self.has("Void Essence") & self.has("Solar Essence"), + "Void Pebble": self.can_reach_region(SVERegion.crimson_badlands) & self.has_galaxy_weapon(), + "Void Root": self.has_season("Winter") & self.has("Void Seed"), + "Void Salmon Sushi": self.has("Void Salmon") & self.has("Void Mayonnaise") & self.has("Seaweed"), + "Void Seed": self.can_reach_region(SVERegion.highlands_cavern) & self.has_good_weapon(), + "Void Soul": self.can_reach_region(SVERegion.crimson_badlands) & self.has_good_weapon() & + self.can_cook(), + }) + +self.sve_location_rules.update({ + "Bear: Baked Berry Oatmeal Recipe": self.can_complete_quest("Strange Note") & self.can_spend_money(12500), + "Bear: Flower Cookie Recipe": self.can_complete_quest("Strange Note") & self.can_spend_money(8750), + "Purple Junimo: Super Starfruit": self.can_earn_relationship("Apples", 10) & + self.can_reach_region( + SVERegion.purple_junimo_shop) & self.can_spend_money(80000), + "Alesia: Tempered Galaxy Dagger": self.can_reach_region(SVERegion.alesia_shop) & self.has_galaxy_weapon() & + self.can_spend_money(350000) & self.has_lived_months(3), + "Issac: Tempered Galaxy Sword": self.can_reach_region(SVERegion.issac_shop) & self.has_galaxy_weapon() & + self.can_spend_money(600000), + "Issac: Tempered Galaxy Hammer": self.can_reach_region(SVERegion.issac_shop) & self.has_galaxy_weapon() & + self.can_spend_money(400000), + "Lance's Diamond Wand": self.can_complete_quest("Monster Crops") & self.can_reach_region( + SVERegion.lances_house), + "Volcano Caldera Prismatic Shard": self.can_reach_region(SVRegion.ginger_island) & self.has_good_weapon(), +}) + +if "Stardew Valley Expanded" in self.options[options.Mods]: + self.quest_rules.update({ + "The Railroad Boulder": self.received("Skull Key") & self.has(["Furnace", "Iridium Ore", "Coal"]) & + self.can_reach_region("Clint's Blacksmith"), + "Grandpa's Shed": self.has(["Hardwood", "Iron Bar", "Battery Pack", "Stone"]) & + self.can_reach_region(SVERegion.grandpas_shed_interior), + "Marlon's Boat": self.has(["Void Essence", "Solar Essence", "Slime", "Bat Wing", "Bug Meat"]) & + self.can_meet("Lance") & self.can_reach_region(SVERegion.guild_summit), + "Aurora Vineyard": self.can_complete_community_center() & self.has("Starfruit") & + self.can_reach_region(SVERegion.aurora_vineyard) & self.has_year_two(), + "Monster Crops": self.has(["Monster Mushroom", "Slime Berry", "Monster Fruit", "Void Root"]), + "Void Soul": self.can_reach_region(SVRegion.sewers) & self.has("Void Soul"), + }) diff --git a/worlds/stardew_valley/strings/monster_drop_names.py b/worlds/stardew_valley/strings/monster_drop_names.py index 1b9f42429d07..51ed84a245be 100644 --- a/worlds/stardew_valley/strings/monster_drop_names.py +++ b/worlds/stardew_valley/strings/monster_drop_names.py @@ -4,3 +4,10 @@ class Loot: bat_wing = "Bat Wing" solar_essence = "Solar Essence" void_essence = "Void Essence" + + +class ModLoot: + monster_mushroom = "Monster Mushroom" + slime_berry = "Slime Berry" + monster_fruit = "Monster Fruit" + void_root = "Void Root" diff --git a/worlds/stardew_valley/strings/quest_names.py b/worlds/stardew_valley/strings/quest_names.py index 86fc406a0a6d..9431389d51cd 100644 --- a/worlds/stardew_valley/strings/quest_names.py +++ b/worlds/stardew_valley/strings/quest_names.py @@ -50,9 +50,16 @@ class Quest: goblin_problem = "Goblin Problem" magic_ink = "Magic Ink" + class ModQuest: MrGinger = "Mr.Ginger's request" AyeishaEnvelope = "Missing Envelope" AyeishaRing = "Lost Emerald Ring" JunaCola = "Juna's Drink Request" - JunaSpaghetti = "Juna's BFF Request" \ No newline at end of file + JunaSpaghetti = "Juna's BFF Request" + RailroadBoulder = "The Railroad Boulder" + GrandpasShed = "Grandpa's Shed" + MarlonsBoat = "Marlon's Boat" + AuroraVineyard = "Aurora Vineyard" + MonsterCrops = "Monster Crops" + VoidSoul = "Void Soul" \ No newline at end of file From 94a80191952fd1458d7e6b0d067e882c956fafdb Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 30 Oct 2023 02:17:02 -0500 Subject: [PATCH 097/482] Second Pass of SVE Logic Porting --- worlds/stardew_valley/__init__.py | 4 +- worlds/stardew_valley/data/fish_data.py | 2 +- worlds/stardew_valley/data/items.csv | 15 +- worlds/stardew_valley/data/villagers_data.py | 10 +- worlds/stardew_valley/items.py | 24 ++- worlds/stardew_valley/logic/logic.py | 67 +------ worlds/stardew_valley/logic/quest_logic.py | 134 ++++++++++++++ worlds/stardew_valley/mods/logic/mod_logic.py | 8 +- worlds/stardew_valley/mods/logic/sve_logic.py | 170 ++++++++++++------ worlds/stardew_valley/rules.py | 30 +++- worlds/stardew_valley/strings/fish_names.py | 1 + 11 files changed, 322 insertions(+), 143 deletions(-) create mode 100644 worlds/stardew_valley/logic/quest_logic.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 36183a384110..8fd2a29b3f3f 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -10,6 +10,7 @@ from .locations import location_table, create_locations, LocationData from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS +from .logic.bundle_logic import BundleLogic from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \ BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems from .presets import sv_options_presets @@ -67,6 +68,7 @@ class StardewValleyWorld(World): options_dataclass = StardewValleyOptions options: StardewValleyOptions + bundle: BundleLogic logic: StardewLogic web = StardewWebWorld() @@ -186,7 +188,7 @@ def setup_construction_events(self): def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], - self.logic.can_complete_community_center().simplify(), + self.bundle.can_complete_community_center().simplify(), Event.victory) elif self.options.goal == Goal.option_grandpa_evaluation: self.create_event_location(location_table[GoalName.grandpa_evaluation], diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 23c889738d96..4119f965983d 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -48,7 +48,7 @@ def __repr__(self): highlands = (SVERegion.highlands,) sprite_spring = (SVERegion.sprite_spring,) fable_reef = (SVERegion.fable_reef,) -vineyard = (SVERegion.vineyard,) +vineyard = (SVERegion.blue_moon_vineyard,) all_fish: List[FishItem] = [] diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 59f22a1dcd93..35502144749b 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -768,19 +768,20 @@ id,name,classification,groups,mod_name 10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded -10502,Diamond Wand,progression,"WEAPON,GINGER_ISLAND",Stardew Valley Expanded +10502,Diamond Wand,useful,"GINGER_ISLAND",Stardew Valley Expanded 10503,Iridium Bomb,progression,,Stardew Valley Expanded 10504,Krobus' Protection,useful,,Stardew Valley Expanded 10505,Kittyfish Spell,progression,,Stardew Valley Expanded -10506,Nexus: Adventurer's Guild Runes,progression,,Stardew Valley Expanded -10507,Nexus: Junimo Woods Runes,progression,,Stardew Valley Expanded -10508,Nexus: Aurora Vineyard Runes,progression,,Stardew Valley Expanded -10509,Nexus: Sprite Spring Runes,progression,,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,,Stardew Valley Expanded -10511,Lance's Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded +10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded +10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded +10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10511,Fable Reef Portal,progression,"GINGER_ISLAND,MOD_WARP",Stardew Valley Expanded 10512,Super Starfruit,useful,,Stardew Valley Expanded 10513,Tempered Galaxy Sword,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded 10514,Tempered Galaxy Dagger,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded 10515,Tempered Galaxy Hammer,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded +10516,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 623c1d0b2273..13e9ab8584d1 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -2,7 +2,7 @@ from typing import List, Tuple, Optional, Dict from ..strings.food_names import Beverage -from ..strings.region_names import Region +from ..strings.region_names import Region, SVERegion from ..mods.mod_data import ModNames from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC @@ -44,13 +44,13 @@ def __repr__(self): wizard_tower = (Region.wizard_tower,) # Stardew Valley Expanded Locations -adventurer = (SVRegion.adventurer_guild,) +adventurer = (Region.adventurer_guild,) highlands = (SVERegion.highlands,) bluemoon = (SVERegion.blue_moon_vineyard,) aurora = (SVERegion.aurora_vineyard,) -museum = (SVRegion.museum,) -jojamart = (SVRegion.jojamart,) -railroad = (SVRegion.railroad,) +museum = (Region.museum,) +jojamart = (Region.jojamart,) +railroad = (Region.railroad,) junimo = (SVERegion.junimo_woods,) golden_pumpkin = ("Golden Pumpkin",) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 51166e177787..75ea36c5db8e 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -17,6 +17,7 @@ from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff from .strings.ap_names.event_names import Event +from .strings.villager_names import NPC, ModNPC ITEM_CODE_OFFSET = 717000 @@ -79,7 +80,7 @@ class Group(enum.Enum): # Mods MAGIC_SPELL = enum.auto() TEMPERED_GALAXY_WEAPONS = enum.auto() - + MOD_WARP = enum.auto() @dataclass(frozen=True) class ItemData: @@ -330,13 +331,6 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[I items.append(item_factory("Iridium Snake Milk")) items.append(item_factory("Fairy Dust Recipe")) -def create_special_quest_rewards_sve(item_factory: StardewItemFactory, items: List[Item]): - items.append(item_factory("Marlon's Boat Paddle")) - items.append(item_factory("Iridium Bomb")) - items.append(item_factory("Krobus' Protection")) - items.append(item_factory("Kittyfish Spell")) - create_nexus_warps(item_factory, items) - items.append(item_factory("Lance's Fable Reef Portal")) def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): stardrops_classification = get_stardrop_classification(options) @@ -361,6 +355,7 @@ def create_museum_items(item_factory: StardewItemFactory, options: StardewValley def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item], random): + island_villagers = [NPC.Leo, ModNPC.lance] if options.friendsanity == Friendsanity.option_none: return exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors @@ -377,7 +372,7 @@ def create_friendsanity_items(item_factory: StardewItemFactory, options: Stardew continue if not villager.bachelor and exclude_non_bachelors: continue - if villager.name == "Leo" and exclude_ginger_island: + if villager.name in island_villagers and exclude_ginger_island: continue heart_cap = 8 if villager.bachelor else 10 if include_post_marriage_hearts and villager.bachelor: @@ -562,6 +557,17 @@ def create_magic_mod_spells(item_factory: StardewItemFactory, options: StardewVa items.extend([item_factory(item) for item in items_by_group[Group.MAGIC_SPELL]]) +def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if ModNames.sve not in options.mods: + return [] + items.append(item_factory("Diamond Wand")) + items.append(item_factory("Marlon's Boat Paddle")) + items.append(item_factory("Iridium Bomb")) + items.append(item_factory("Krobus' Protection")) + items.append(item_factory("Kittyfish Spell")) + items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP]]) + + def create_unique_filler_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random, available_item_slots: int) -> List[Item]: items = [] diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index b170446cb202..61b22b234cad 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -19,6 +19,7 @@ from .monster_logic import MonsterLogic from .museum_logic import MuseumLogic from .pet_logic import PetLogic +from .quest_logic import QuestLogic from .received_logic import ReceivedLogic from .has_logic import HasLogic from .region_logic import RegionLogic @@ -35,7 +36,6 @@ from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..mods.logic.mod_logic import ModLogic from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops -from ..data.bundle_data import BundleItem from ..data.fish_data import island_fish, legendary_fish, extended_family from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes @@ -50,7 +50,7 @@ from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building from ..strings.calendar_names import Weekday -from worlds.stardew_valley.strings.craftable_names import Craftable, Consumable, Furniture, Ring, Fishing, Lighting +from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.decoration_names import Decoration @@ -70,7 +70,6 @@ from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil from ..strings.monster_drop_names import Loot from ..strings.monster_names import Monster -from ..strings.quest_names import Quest from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.seed_names import Seed, TreeSeed @@ -139,12 +138,14 @@ def __post_init__(self): self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) + self.quest = QuestLogic(self.player, skill_option, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, + self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, mods_option) self.crafting = CraftingLogic(self.player, self.options.craftsanity, self.options.festival_locations, self.options.special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, - self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability) + self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, + self.time, self.quest) self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) @@ -451,61 +452,7 @@ def __post_init__(self): self.buildings.initialize_rules() self.buildings.update_rules(self.mod.buildings.get_modded_building_rules()) - self.quest_rules.update({ - Quest.introductions: self.region.can_reach(Region.town), - Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), - Quest.getting_started: self.has(Vegetable.parsnip) & self.tool.has_tool(Tool.hoe) & self.tool.can_water(0), - Quest.to_the_beach: self.region.can_reach(Region.beach), - Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.buildings.has_building(Building.coop), - Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), - Quest.archaeology: (self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish()) & self.region.can_reach(Region.museum), - Quest.meet_the_wizard: self.region.can_reach(Region.town) & self.region.can_reach(Region.community_center) & self.region.can_reach(Region.wizard_tower), - Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), - Quest.smelting: self.has(MetalBar.copper), - Quest.initiation: self.mine.can_mine_in_the_mines_floor_1_40(), - Quest.robins_lost_axe: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.can_meet(NPC.robin), - Quest.jodis_request: self.season.has(Season.spring) & self.has(Vegetable.cauliflower) & self.relationship.can_meet(NPC.jodi), - Quest.mayors_shorts: self.season.has(Season.summer) & self.region.can_reach(Region.ranch) & - (self.relationship.has_hearts(NPC.marnie, 2) | (self.mod.magic.can_blink())) & self.relationship.can_meet(NPC.lewis), - Quest.blackberry_basket: self.season.has(Season.fall) & self.relationship.can_meet(NPC.linus), - Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot) & self.region.can_reach(Region.ranch), - Quest.pam_is_thirsty: self.season.has(Season.summer) & self.has(ArtisanGood.pale_ale) & self.relationship.can_meet(NPC.pam), - Quest.a_dark_reagent: self.season.has(Season.winter) & self.has(Loot.void_essence) & self.relationship.can_meet(NPC.wizard), - Quest.cows_delight: self.season.has(Season.fall) & self.has(Vegetable.amaranth) & self.relationship.can_meet(NPC.marnie), - Quest.the_skull_key: self.received(Wallet.skull_key) & self.region.can_reach(Region.skull_cavern_entrance), - Quest.crop_research: self.season.has(Season.summer) & self.has(Fruit.melon) & self.relationship.can_meet(NPC.demetrius), - Quest.knee_therapy: self.season.has(Season.summer) & self.has(Fruit.hot_pepper) & self.relationship.can_meet(NPC.george), - Quest.robins_request: self.season.has(Season.winter) & self.has(Material.hardwood) & self.relationship.can_meet(NPC.robin), - Quest.qis_challenge: self.mine.can_mine_in_the_skull_cavern(), - Quest.the_mysterious_qi: self.region.can_reach(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.region.can_reach(Region.desert) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), - Quest.carving_pumpkins: self.season.has(Season.fall) & self.has(Vegetable.pumpkin) & self.relationship.can_meet(NPC.caroline), - Quest.a_winter_mystery: self.season.has(Season.winter) & self.region.can_reach(Region.town), - Quest.strange_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.secret_woods) & self.has(ArtisanGood.maple_syrup), - Quest.cryptic_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.skull_cavern_100), - Quest.fresh_fruit: self.season.has(Season.spring) & self.has(Fruit.apricot) & self.relationship.can_meet(NPC.emily), - Quest.aquatic_research: self.season.has(Season.summer) & self.has(Fish.pufferfish) & self.relationship.can_meet(NPC.demetrius), - Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two() & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), - Quest.mayors_need: self.season.has(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.relationship.can_meet(NPC.lewis), - Quest.wanted_lobster: self.season.has(Season.fall) & self.season.has(Season.fall) & self.has(Fish.lobster) & self.relationship.can_meet(NPC.gus), - Quest.pam_needs_juice: self.season.has(Season.fall) & self.has(ArtisanGood.battery_pack) & self.relationship.can_meet(NPC.pam), - Quest.fish_casserole: self.relationship.has_hearts(NPC.jodi, 4) & self.has(Fish.largemouth_bass) & self.region.can_reach(Region.sam_house), - Quest.catch_a_squid: self.season.has(Season.winter) & self.has(Fish.squid) & self.relationship.can_meet(NPC.willy), - Quest.fish_stew: self.season.has(Season.winter) & self.has(Fish.albacore) & self.relationship.can_meet(NPC.gus), - Quest.pierres_notice: self.season.has(Season.spring) & self.has("Sashimi") & self.relationship.can_meet(NPC.pierre), - Quest.clints_attempt: self.season.has(Season.winter) & self.has(Mineral.amethyst) & self.relationship.can_meet(NPC.emily), - Quest.a_favor_for_clint: self.season.has(Season.winter) & self.has(MetalBar.iron) & self.relationship.can_meet(NPC.clint), - Quest.staff_of_power: self.season.has(Season.winter) & self.has(MetalBar.iridium) & self.relationship.can_meet(NPC.wizard), - Quest.grannys_gift: self.season.has(Season.spring) & self.has(Forageable.leek) & self.relationship.can_meet(NPC.evelyn), - Quest.exotic_spirits: self.season.has(Season.winter) & self.has(Forageable.coconut) & self.relationship.can_meet(NPC.gus), - Quest.catch_a_lingcod: self.season.has(Season.winter) & self.has("Lingcod") & self.relationship.can_meet(NPC.willy), - Quest.dark_talisman: self.wallet.has_rusty_key() & self.region.can_reach(Region.railroad) & self.relationship.can_meet(NPC.krobus) & self.region.can_reach(Region.mutant_bug_lair), - Quest.goblin_problem: self.region.can_reach(Region.witch_swamp) & self.has(ArtisanGood.void_mayonnaise), - Quest.magic_ink: self.region.can_reach(Region.witch_hut) & self.relationship.can_meet(NPC.wizard), - Quest.the_pirates_wife: self.region.can_reach(Region.island_west) & self.relationship.can_meet(NPC.kent) & - self.relationship.can_meet(NPC.gus) & self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & - self.relationship.can_meet(NPC.wizard) & self.relationship.can_meet(NPC.willy), - }) - + self.quest_rules.update(self.quest.set_quest_rules()) self.quest_rules.update(self.mod.quests.get_modded_quest_rules()) self.festival_rules.update({ diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py new file mode 100644 index 000000000000..eb7cc0728093 --- /dev/null +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -0,0 +1,134 @@ +from typing import Dict +from dataclasses import field + +from .action_logic import ActionLogic +from .building_logic import BuildingLogic +from .combat_logic import CombatLogic +from .cooking_logic import CookingLogic +from .fishing_logic import FishingLogic +from .has_logic import HasLogic +from .mine_logic import MineLogic +from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic +from .relationship_logic import RelationshipLogic +from .season_logic import SeasonLogic +from .skill_logic import SkillLogic +from .tool_logic import ToolLogic +from ..options import SkillProgression, Mods +from ..strings.artisan_good_names import ArtisanGood +from ..strings.building_names import Building +from ..strings.craftable_names import Craftable +from ..strings.crop_names import Fruit, Vegetable +from ..strings.fish_names import Fish +from ..strings.food_names import Meal +from ..strings.forageable_names import Forageable +from ..strings.machine_names import Machine +from ..strings.monster_drop_names import Loot +from ..strings.material_names import Material +from ..strings.metal_names import MetalBar, Ore, Mineral +from ..strings.region_names import Region +from ..strings.season_names import Season +from ..strings.tool_names import Tool +from ..strings.quest_names import Quest +from ..strings.villager_names import NPC +from ..strings.wallet_item_names import Wallet +from ..stardew_rule import StardewRule, Has + + +class QuestLogic: + player: int + received: ReceivedLogic + has: HasLogic + mine: MineLogic + region: RegionLogic + relationship: RelationshipLogic + tool: ToolLogic + fishing: FishingLogic + cooking: CookingLogic + mods_option: Mods + money: MoneyLogic + combat: CombatLogic + season: SeasonLogic + skill: SkillLogic + + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, mine: MineLogic, region: RegionLogic, action: ActionLogic, + relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, mods_option: Mods): + self.player = player + self.skill_option = skill_option + self.received = received + self.has = has + self.mine = mine + self.region = region + self.action = action + self.relationship = relationship + self.building = building + self.tool = tool + self.fishing = fishing + self.cooking = cooking + self.mods_option = mods_option + self.money = money + self.combat = combat + self.season = season + + def set_quest_rules(self): + quest_rules = Dict[self, StardewRule] = field(default_factory=dict) + quest_rules.update({ + Quest.introductions: self.region.can_reach(Region.town), + Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), + Quest.getting_started: self.has(Vegetable.parsnip) & self.tool.has_tool(Tool.hoe) & self.tool.can_water(0), + Quest.to_the_beach: self.region.can_reach(Region.beach), + Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.building.has_building(Building.coop), + Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), + Quest.archaeology: (self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish()) & self.region.can_reach(Region.museum), + Quest.meet_the_wizard: self.region.can_reach(Region.town) & self.region.can_reach(Region.community_center) & self.region.can_reach(Region.wizard_tower), + Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), + Quest.smelting: self.has(MetalBar.copper), + Quest.initiation: self.mine.can_mine_in_the_mines_floor_1_40(), + Quest.robins_lost_axe: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.can_meet(NPC.robin), + Quest.jodis_request: self.season.has(Season.spring) & self.has(Vegetable.cauliflower) & self.relationship.can_meet(NPC.jodi), + Quest.mayors_shorts: self.season.has(Season.summer) & self.region.can_reach(Region.ranch) & + (self.relationship.has_hearts(NPC.marnie, 2) | (self.mod.magic.can_blink())) & self.relationship.can_meet(NPC.lewis), + Quest.blackberry_basket: self.season.has(Season.fall) & self.relationship.can_meet(NPC.linus), + Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot) & self.region.can_reach(Region.ranch), + Quest.pam_is_thirsty: self.season.has(Season.summer) & self.has(ArtisanGood.pale_ale) & self.relationship.can_meet(NPC.pam), + Quest.a_dark_reagent: self.season.has(Season.winter) & self.has(Loot.void_essence) & self.relationship.can_meet(NPC.wizard), + Quest.cows_delight: self.season.has(Season.fall) & self.has(Vegetable.amaranth) & self.relationship.can_meet(NPC.marnie), + Quest.the_skull_key: self.received(Wallet.skull_key) & self.region.can_reach(Region.skull_cavern_entrance), + Quest.crop_research: self.season.has(Season.summer) & self.has(Fruit.melon) & self.relationship.can_meet(NPC.demetrius), + Quest.knee_therapy: self.season.has(Season.summer) & self.has(Fruit.hot_pepper) & self.relationship.can_meet(NPC.george), + Quest.robins_request: self.season.has(Season.winter) & self.has(Material.hardwood) & self.relationship.can_meet(NPC.robin), + Quest.qis_challenge: self.mine.can_mine_in_the_skull_cavern(), + Quest.the_mysterious_qi: self.region.can_reach(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.region.can_reach(Region.desert) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), + Quest.carving_pumpkins: self.season.has(Season.fall) & self.has(Vegetable.pumpkin) & self.relationship.can_meet(NPC.caroline), + Quest.a_winter_mystery: self.season.has(Season.winter) & self.region.can_reach(Region.town), + Quest.strange_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.secret_woods) & self.has(ArtisanGood.maple_syrup), + Quest.cryptic_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.skull_cavern_100), + Quest.fresh_fruit: self.season.has(Season.spring) & self.has(Fruit.apricot) & self.relationship.can_meet(NPC.emily), + Quest.aquatic_research: self.season.has(Season.summer) & self.has(Fish.pufferfish) & self.relationship.can_meet(NPC.demetrius), + Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two() & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), + Quest.mayors_need: self.season.has(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.relationship.can_meet(NPC.lewis), + Quest.wanted_lobster: self.season.has(Season.fall) & self.season.has(Season.fall) & self.has(Fish.lobster) & self.relationship.can_meet(NPC.gus), + Quest.pam_needs_juice: self.season.has(Season.fall) & self.has(ArtisanGood.battery_pack) & self.relationship.can_meet(NPC.pam), + Quest.fish_casserole: self.relationship.has_hearts(NPC.jodi, 4) & self.has(Fish.largemouth_bass) & self.region.can_reach(Region.sam_house), + Quest.catch_a_squid: self.season.has(Season.winter) & self.has(Fish.squid) & self.relationship.can_meet(NPC.willy), + Quest.fish_stew: self.season.has(Season.winter) & self.has(Fish.albacore) & self.relationship.can_meet(NPC.gus), + Quest.pierres_notice: self.season.has(Season.spring) & self.has(Meal.sashimi) & self.relationship.can_meet(NPC.pierre), + Quest.clints_attempt: self.season.has(Season.winter) & self.has(Mineral.amethyst) & self.relationship.can_meet(NPC.emily), + Quest.a_favor_for_clint: self.season.has(Season.winter) & self.has(MetalBar.iron) & self.relationship.can_meet(NPC.clint), + Quest.staff_of_power: self.season.has(Season.winter) & self.has(MetalBar.iridium) & self.relationship.can_meet(NPC.wizard), + Quest.grannys_gift: self.season.has(Season.spring) & self.has(Forageable.leek) & self.relationship.can_meet(NPC.evelyn), + Quest.exotic_spirits: self.season.has(Season.winter) & self.has(Forageable.coconut) & self.relationship.can_meet(NPC.gus), + Quest.catch_a_lingcod: self.season.has(Season.winter) & self.has(Fish.lingcod) & self.relationship.can_meet(NPC.willy), + Quest.dark_talisman: self.wallet.has_rusty_key() & self.region.can_reach(Region.railroad) & self.relationship.can_meet(NPC.krobus) & self.region.can_reach(Region.mutant_bug_lair), + Quest.goblin_problem: self.region.can_reach(Region.witch_swamp) & self.has(ArtisanGood.void_mayonnaise), + Quest.magic_ink: self.region.can_reach(Region.witch_hut) & self.relationship.can_meet(NPC.wizard), + Quest.the_pirates_wife: self.region.can_reach(Region.island_west) & self.relationship.can_meet(NPC.kent) & + self.relationship.can_meet(NPC.gus) & self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & + self.relationship.can_meet(NPC.wizard) & self.relationship.can_meet(NPC.willy), + }) + return quest_rules + + def can_complete_quest(self, quest: str) -> StardewRule: + return Has(quest, self.set_quest_rules()) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 9ecbf43394f6..6d38d372eb9c 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -7,6 +7,7 @@ from .quests_logic import QuestLogic from .skills_logic import ModSkillLogic from .special_orders_logic import ModSpecialOrderLogic +from .sve_logic import SVELogic from ...logic.ability_logic import AbilityLogic from ...logic.action_logic import ActionLogic from ...logic.building_logic import BuildingLogic @@ -16,11 +17,13 @@ from ...logic.has_logic import HasLogic from ...logic.mine_logic import MineLogic from ...logic.money_logic import MoneyLogic +from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogic from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic from ...logic.skill_logic import SkillLogic +from ...logic.time_logic import TimeLogic from ...logic.tool_logic import ToolLogic from ...logic.wallet_logic import WalletLogic from ...options import SkillProgression, ElevatorProgression, Mods @@ -34,10 +37,12 @@ class ModLogic: elevator: ModElevatorLogic deepwoods: DeepWoodsLogic skill: ModSkillLogic + sve: SVELogic def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, - combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic): + combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, + time: TimeLogic, quest: QuestLogic): self.magic = MagicLogic(player, mods, received, region) self.quests = QuestLogic(mods, has, region, season, relationship) self.buildings = ModBuildingLogic(player, has, money, mods) @@ -45,6 +50,7 @@ def __init__(self, player: int, skill_option: SkillProgression, elevator_option: self.elevator = ModElevatorLogic(player, elevator_option, mods, received) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) self.skill = ModSkillLogic(player, skill_option, received, has, region, action, relationship, building, tool, fishing, cooking, self.magic, mods) + self.sve = SVELogic(player, skill_option, received, has, quest, region, action, relationship, building, tool, fishing, cooking, money, combat, season, time) combat.set_magic(self.magic) tool.set_magic(self.magic) ability.set_magic(self.magic, self.skill) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 79739c92778a..b027b50b73a6 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -1,58 +1,112 @@ -if self.has_mod("Stardew Valley Expanded"): - self.item_rules.update({ - "Aged Blue Moon Wine": self.can_reach_region(SVERegion.sophias_house) & self.can_spend_money(28000), - "Big Bark Burger": self.can_cook() & self.has(["Puppyfish", "Bread", "Oil"]) & - self.has_relationship("Gus", 5) & self.can_spend_money(5500) & - self.can_reach_region(SVRegion.saloon), - "Blue Moon Wine": self.can_reach_region(SVERegion.sophias_house) & self.can_spend_money(3000), - "Fungus Seed": self.can_reach_region(SVERegion.highlands_cavern) & self.has_good_weapon(), - "Glazed Butterfish": self.can_cook() & self.has(["Butterfish", "Wheat", "Oil"]) & - self.has_relationship("Gus", 10) & self.can_spend_money(4000), - "Green Mushroom": self.can_reach_region(SVERegion.highlands) & self.has_tool("Axe", "Iron"), - "Monster Fruit": self.has_season("Summer") & self.has("Stalk Seed"), - "Monster Mushroom": self.has_season("Fall") & self.has("Fungus Seed"), - "Ornate Treasure Chest": self.can_reach_region(SVERegion.highlands) & self.has_galaxy_weapon() & - self.can_cook() & self.has_tool("Axe", "Iron"), - "Slime Berry": self.has_season("Spring") & self.has("Slime Seed"), - "Slime Seed": self.can_reach_region(SVERegion.highlands) & self.has_good_weapon(), - "Stalk Seed": self.can_reach_region(SVERegion.highlands) & self.has_good_weapon(), - "Swirl Stone": self.can_reach_region(SVERegion.crimson_badlands) & self.has_great_weapon(), - "Void Delight": self.has("Void Eel") & self.has("Void Essence") & self.has("Solar Essence"), - "Void Pebble": self.can_reach_region(SVERegion.crimson_badlands) & self.has_galaxy_weapon(), - "Void Root": self.has_season("Winter") & self.has("Void Seed"), - "Void Salmon Sushi": self.has("Void Salmon") & self.has("Void Mayonnaise") & self.has("Seaweed"), - "Void Seed": self.can_reach_region(SVERegion.highlands_cavern) & self.has_good_weapon(), - "Void Soul": self.can_reach_region(SVERegion.crimson_badlands) & self.has_good_weapon() & - self.can_cook(), - }) - -self.sve_location_rules.update({ - "Bear: Baked Berry Oatmeal Recipe": self.can_complete_quest("Strange Note") & self.can_spend_money(12500), - "Bear: Flower Cookie Recipe": self.can_complete_quest("Strange Note") & self.can_spend_money(8750), - "Purple Junimo: Super Starfruit": self.can_earn_relationship("Apples", 10) & - self.can_reach_region( - SVERegion.purple_junimo_shop) & self.can_spend_money(80000), - "Alesia: Tempered Galaxy Dagger": self.can_reach_region(SVERegion.alesia_shop) & self.has_galaxy_weapon() & - self.can_spend_money(350000) & self.has_lived_months(3), - "Issac: Tempered Galaxy Sword": self.can_reach_region(SVERegion.issac_shop) & self.has_galaxy_weapon() & - self.can_spend_money(600000), - "Issac: Tempered Galaxy Hammer": self.can_reach_region(SVERegion.issac_shop) & self.has_galaxy_weapon() & - self.can_spend_money(400000), - "Lance's Diamond Wand": self.can_complete_quest("Monster Crops") & self.can_reach_region( - SVERegion.lances_house), - "Volcano Caldera Prismatic Shard": self.can_reach_region(SVRegion.ginger_island) & self.has_good_weapon(), -}) - -if "Stardew Valley Expanded" in self.options[options.Mods]: - self.quest_rules.update({ - "The Railroad Boulder": self.received("Skull Key") & self.has(["Furnace", "Iridium Ore", "Coal"]) & - self.can_reach_region("Clint's Blacksmith"), - "Grandpa's Shed": self.has(["Hardwood", "Iron Bar", "Battery Pack", "Stone"]) & - self.can_reach_region(SVERegion.grandpas_shed_interior), - "Marlon's Boat": self.has(["Void Essence", "Solar Essence", "Slime", "Bat Wing", "Bug Meat"]) & - self.can_meet("Lance") & self.can_reach_region(SVERegion.guild_summit), - "Aurora Vineyard": self.can_complete_community_center() & self.has("Starfruit") & - self.can_reach_region(SVERegion.aurora_vineyard) & self.has_year_two(), - "Monster Crops": self.has(["Monster Mushroom", "Slime Berry", "Monster Fruit", "Void Root"]), - "Void Soul": self.can_reach_region(SVRegion.sewers) & self.has("Void Soul"), - }) +from typing import Dict +from dataclasses import field + +from ...logic.action_logic import ActionLogic +from ...logic.building_logic import BuildingLogic +from ...logic.combat_logic import CombatLogic +from ...logic.cooking_logic import CookingLogic +from ...logic.fishing_logic import FishingLogic +from ...logic.has_logic import HasLogic +from ...logic.money_logic import MoneyLogic +from ...logic.quest_logic import QuestLogic +from ...logic.received_logic import ReceivedLogic +from ...logic.region_logic import RegionLogic +from ...logic.relationship_logic import RelationshipLogic +from ...logic.season_logic import SeasonLogic +from ...logic.time_logic import TimeLogic +from ...logic.tool_logic import ToolLogic +from ..mod_regions import SVERegion +from ...options import SkillProgression +from ...strings.fish_names import SVEFish +from ...strings.ingredient_names import Ingredient +from ...strings.region_names import Region +from ...strings.villager_names import NPC +from ...stardew_rule import StardewRule, Or + + +class SVELogic: + player: int + received: ReceivedLogic + has: HasLogic + quest: QuestLogic + region: RegionLogic + relationship: RelationshipLogic + time: TimeLogic + tool: ToolLogic + fishing: FishingLogic + cooking: CookingLogic + money: MoneyLogic + combat: CombatLogic + season: SeasonLogic + + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, quest: QuestLogic, region: RegionLogic, action: ActionLogic, + relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, time: TimeLogic): + self.player = player + self.skill_option = skill_option + self.received = received + self.has = has + self.quest = quest + self.region = region + self.action = action + self.relationship = relationship + self.building = building + self.tool = tool + self.fishing = fishing + self.cooking = cooking + self.time = time + self.money = money + self.combat = combat + self.season = season + + def set_sve_item_rules(self, items: Dict[str, StardewRule]): + items.update({ + "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), + "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, "Bread", "Oil"]) & + self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & + self.region.can_reach(Region.saloon), + "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), + "Fungus Seed": self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & + self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend(4000) & self.region.can_reach(Region.saloon), + "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool("Axe", "Iron"), + "Monster Fruit": self.season.has("Summer") & self.has("Stalk Seed"), + "Monster Mushroom": self.has("Fall") & self.has("Fungus Seed"), + "Ornate Treasure Chest": self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & + self.cooking.can_cook() & self.tool.has_tool("Axe", "Iron"), + "Slime Berry": self.season.has("Spring") & self.has("Slime Seed"), + "Slime Seed": self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + "Stalk Seed": self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + "Swirl Stone": self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), + "Void Delight": self.has("Void Eel") & self.has("Void Essence") & self.has("Solar Essence"), + "Void Pebble": self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), + "Void Root": self.season.has("Winter") & self.has("Void Seed"), + "Void Salmon Sushi": self.has("Void Salmon") & self.has("Void Mayonnaise") & self.has("Seaweed"), + "Void Seed": self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + "Void Soul": self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & + self.cooking.can_cook(), + }) + + def sve_misc_rules(self): + sve_misc_rules = Dict[str, StardewRule] = field(default_factory=dict) + sve_misc_rules.update({ + "Bear: Baked Berry Oatmeal Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend(12500), + "Bear: Flower Cookie Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend(8750), + "Purple Junimo: Super Starfruit": self.relationship.has_hearts("Apples", 10) & + self.region.can_reach( + SVERegion.purple_junimo_shop) & self.money.can_spend(80000), + "Alesia: Tempered Galaxy Dagger": self.region.can_reach(SVERegion.alesia_shop) & self.combat.has_galaxy_weapon() & + self.money.can_spend(350000) & self.time.has_lived_months(3), + "Issac: Tempered Galaxy Sword": self.region.can_reach(SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & + self.money.can_spend(600000), + "Issac: Tempered Galaxy Hammer": self.region.can_reach(SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & + self.money.can_spend(400000), + "Lance's Diamond Wand": self.quest.can_complete_quest("Monster Crops") & self.region.can_reach( + SVERegion.lances_house), + }) + + def has_any_rune(self): + rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", + "Nexus: Outpost Runes"] + return Or([self.received(rune) for rune in rune_list]) + diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 45c00f92a1ff..e960cdb3926b 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -22,9 +22,11 @@ from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building from .strings.calendar_names import Weekday -from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance +from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance, \ + SVEEntrance from .strings.material_names import Material from .strings.metal_names import MetalBar +from .strings.quest_names import Quest, ModQuest from .strings.region_names import Region from .strings.season_names import Season from .strings.skill_names import ModSkill, Skill @@ -892,3 +894,29 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()) + + +def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if ModNames.sve not in world_options.mods: + return + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_to_junimo, player), + logic.received("Abandoned House Outskirts Clean-up").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), + logic.received("Iridium Bomb").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), + logic.can_complete_quest(Quest.strange_note).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), + logic.mod.sve.has_any_rune().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), + logic.can_complete_quest(Quest.magic_ink).simplify()) + set_sve_ginger_island_rules(logic, multiworld, player, world_options) + + +def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: + return + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.summit_to_boat, player), + logic.received("Marlon's Boat Paddle").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), + logic.received("Fable Reef Portal").simplify()) + diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 24fed4c98b94..3633ecd96a7a 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -20,6 +20,7 @@ class Fish: legend = "Legend" legend_ii = "Legend II" lionfish = "Lionfish" + lingcod = "Lingcod" lobster = "Lobster" midnight_carp = "Midnight Carp" ms_angler = "Ms. Angler" From 4bb32405af9bbde1b5ae8ed51191660434ffc3a8 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 30 Oct 2023 07:25:38 -0500 Subject: [PATCH 098/482] Finalize initial SVE logic porting --- worlds/stardew_valley/data/locations.csv | 1 - worlds/stardew_valley/logic/logic.py | 10 +++-- .../logic/relationship_logic.py | 5 ++- worlds/stardew_valley/mods/logic/mod_logic.py | 7 +++- .../mods/logic/special_orders_logic.py | 38 ++++++++++++++++-- worlds/stardew_valley/mods/logic/sve_logic.py | 40 ++++++++++--------- worlds/stardew_valley/rules.py | 29 ++++++++++++++ .../strings/special_order_names.py | 5 +++ 8 files changed, 107 insertions(+), 28 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 83b46613289c..3338452b6649 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2449,7 +2449,6 @@ id,region,name,tags,mod_name 7605,Issac Shop,Issac: Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7606,Issac Shop,Issac: Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded 7607,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded -7608,Volcano – Floor 10,Volcano Caldera Prismatic Shard,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded 7501,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7502,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded 7503,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 61b22b234cad..2c8553fdf294 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -56,7 +56,7 @@ from ..strings.decoration_names import Decoration from ..strings.fertilizer_names import Fertilizer from ..strings.festival_check_names import FestivalCheck -from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest +from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest, SVEFish from ..strings.flower_names import Flower from ..strings.forageable_names import Forageable from ..strings.fruit_tree_names import Sapling @@ -145,7 +145,7 @@ def __post_init__(self): self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, - self.time, self.quest) + self.time, self.quest, self.crafting, self.crop) self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) @@ -542,7 +542,11 @@ def can_catch_fish(self, fish: FishItem) -> StardewRule: difficulty_rule = self.skill.can_crab_pot() else: difficulty_rule = self.skill.can_fish([], 120 if fish.legendary else fish.difficulty) - return quest_rule & region_rule & season_rule & difficulty_rule + if fish.name == SVEFish.kittyfish: + item_rule = self.received("Kittyfish Spell") + else: + item_rule = True_() + return quest_rule & region_rule & season_rule & difficulty_rule & item_rule def can_catch_every_fish(self) -> StardewRule: rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 400b91fd54ca..5a553b67fcb3 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -15,7 +15,8 @@ from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic from ..strings.gift_names import Gift -from ..strings.villager_names import NPC +from ..strings.villager_names import NPC, ModNPC +from ..strings.region_names import Region class RelationshipLogic: @@ -122,6 +123,8 @@ def can_meet(self, npc: str) -> StardewRule: rules.append(self.time.has_year_two()) elif npc == NPC.leo: rules.append(self.received("Island West Turtle")) + elif npc == ModNPC.lance: + rules.append(self.region.can_reach(Region.volcano_floor_10)) return And(rules) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 6d38d372eb9c..79d4f5b8a877 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -13,6 +13,8 @@ from ...logic.building_logic import BuildingLogic from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic +from ...logic.crafting_logic import CraftingLogic +from ...logic.crop_logic import CropLogic from ...logic.fishing_logic import FishingLogic from ...logic.has_logic import HasLogic from ...logic.mine_logic import MineLogic @@ -31,6 +33,7 @@ class ModLogic: quests: QuestLogic + region: RegionLogic magic: MagicLogic buildings: ModBuildingLogic special_orders: ModSpecialOrderLogic @@ -42,11 +45,11 @@ class ModLogic: def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, - time: TimeLogic, quest: QuestLogic): + time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): self.magic = MagicLogic(player, mods, received, region) self.quests = QuestLogic(mods, has, region, season, relationship) self.buildings = ModBuildingLogic(player, has, money, mods) - self.special_orders = ModSpecialOrderLogic(player, has, region, relationship, wallet, mods) + self.special_orders = ModSpecialOrderLogic(player, action, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) self.skill = ModSkillLogic(player, skill_option, received, has, region, action, relationship, building, tool, fishing, cooking, self.magic, mods) diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index a99d5ab90a3a..44289a6c813c 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -1,15 +1,26 @@ from typing import Iterable +from ...logic.action_logic import ActionLogic +from ...logic.crafting_logic import CraftingLogic +from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogic from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic +from ...logic.season_logic import SeasonLogic from ...logic.wallet_logic import WalletLogic from ...options import Mods -from ...strings.craftable_names import Consumable, Edible +from ...strings.artisan_good_names import ArtisanGood +from ...strings.craftable_names import Consumable, Edible, Bomb +from ...strings.fertilizer_names import Fertilizer +from ...strings.flower_names import Flower from ...strings.food_names import Meal +from ...strings.crop_names import Fruit +from ...strings.geode_names import Geode +from ...strings.machine_names import Machine from ...strings.material_names import Material +from ...strings.metal_names import MetalBar from ...strings.monster_drop_names import Loot -from ...strings.region_names import Region +from ...strings.region_names import Region, SVERegion from ...strings.special_order_names import SpecialOrder, ModSpecialOrder from ...strings.villager_names import ModNPC from ..mod_data import ModNames @@ -17,17 +28,25 @@ class ModSpecialOrderLogic: player: int + crafting: CraftingLogic + crop: CropLogic has: HasLogic region: RegionLogic relationship: RelationshipLogic + season: SeasonLogic wallet: WalletLogic mods_option: Mods - def __init__(self, player: int, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, wallet: WalletLogic, mods_option: Mods): + def __init__(self, player: int, action: ActionLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, + season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): self.player = player + self.action = action + self.crafting = crafting + self.crop = crop self.has = has self.region = region self.relationship = relationship + self.season = season self.wallet = wallet self.mods_option = mods_option @@ -42,5 +61,18 @@ def get_modded_special_orders_rules(self, vanilla_rules): self.has("Energy Tonic") & self.has(Material.sap) & self.has(Loot.bug_meat) & self.has(Edible.oil_of_garlic) & self.has(Meal.strange_bun) }) + if ModNames.sve in self.mods_option: + special_orders.update({ + ModSpecialOrder.andys_cellar: self.has(Material.stone) & self.has(Material.wood) & self.has(Material.hardwood) & self.has(MetalBar.iron) & + self.region.can_reach(SVERegion.fairhaven_farm), + ModSpecialOrder.a_mysterious_venture: self.has(Bomb.cherry_bomb) & self.has(Bomb.bomb) & self.has(Bomb.mega_bomb) & + self.region.can_reach(Region.adventurer_guild), + ModSpecialOrder.an_elegant_reception: self.crop.can_grow(Fruit.starfruit) & self.has(Machine.keg) & self.has(ArtisanGood.cheese) & + self.has(ArtisanGood.goat_cheese) & self.season.has_any_not_winter() & self.region.can_reach(SVERegion.jenkins_cellar), + ModSpecialOrder.fairy_garden: self.crop.can_grow(Flower.fairy_rose) & self.crafting.can_craft(Consumable.fairy_dust) & + self.region.can_reach(Region.island_south) & [self.action.can_open_geode(Geode.frozen) | self.action.can_open_geode(Geode.omni)] & + self.region.can_reach(SVERegion.blue_moon_vineyard), + ModSpecialOrder.homemade_fertilizer: self.crafting.can_craft(Fertilizer.quality) & self.region.can_reach(SVERegion.susans_house) + }) return special_orders diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index b027b50b73a6..14efa8e05620 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -39,6 +39,8 @@ class SVELogic: combat: CombatLogic season: SeasonLogic + sve_location_rules: Dict[str, StardewRule] = field(default_factory=dict) + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, quest: QuestLogic, region: RegionLogic, action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, time: TimeLogic): @@ -59,6 +61,26 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv self.combat = combat self.season = season + self.sve_location_rules.update({ + "Bear: Baked Berry Oatmeal Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend( + 12500), + "Bear: Flower Cookie Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend(8750), + "Purple Junimo: Super Starfruit": self.relationship.has_hearts("Apples", 10) & + self.region.can_reach( + SVERegion.purple_junimo_shop) & self.money.can_spend(80000), + "Alesia: Tempered Galaxy Dagger": self.region.can_reach( + SVERegion.alesia_shop) & self.combat.has_galaxy_weapon() & + self.money.can_spend(350000) & self.time.has_lived_months(3), + "Issac: Tempered Galaxy Sword": self.region.can_reach( + SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & + self.money.can_spend(600000), + "Issac: Tempered Galaxy Hammer": self.region.can_reach( + SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & + self.money.can_spend(400000), + "Lance's Diamond Wand": self.quest.can_complete_quest("Monster Crops") & self.region.can_reach( + SVERegion.lances_house), + }) + def set_sve_item_rules(self, items: Dict[str, StardewRule]): items.update({ "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), @@ -87,24 +109,6 @@ def set_sve_item_rules(self, items: Dict[str, StardewRule]): self.cooking.can_cook(), }) - def sve_misc_rules(self): - sve_misc_rules = Dict[str, StardewRule] = field(default_factory=dict) - sve_misc_rules.update({ - "Bear: Baked Berry Oatmeal Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend(12500), - "Bear: Flower Cookie Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend(8750), - "Purple Junimo: Super Starfruit": self.relationship.has_hearts("Apples", 10) & - self.region.can_reach( - SVERegion.purple_junimo_shop) & self.money.can_spend(80000), - "Alesia: Tempered Galaxy Dagger": self.region.can_reach(SVERegion.alesia_shop) & self.combat.has_galaxy_weapon() & - self.money.can_spend(350000) & self.time.has_lived_months(3), - "Issac: Tempered Galaxy Sword": self.region.can_reach(SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & - self.money.can_spend(600000), - "Issac: Tempered Galaxy Hammer": self.region.can_reach(SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & - self.money.can_spend(400000), - "Lance's Diamond Wand": self.quest.can_complete_quest("Monster Crops") & self.region.can_reach( - SVERegion.lances_house), - }) - def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", "Nexus: Outpost Runes"] diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index e960cdb3926b..2cc7f82de3c7 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -909,6 +909,35 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.mod.sve.has_any_rune().simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), logic.can_complete_quest(Quest.magic_ink).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), + logic.tool.has_tool(Tool.axe, ToolMaterial.iron).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), + logic.received("Fable Reef Portal").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), + logic.tool.has_tool(Tool.axe, ToolMaterial.iron).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_aurora, player), + logic.received("Nexus: Aurora Vineyard Runes").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_farm, player), + logic.mod.sve.has_any_rune().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_guild, player), + logic.received("Nexus: Adventurer's Guild Runes").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_junimo, player), + logic.received("Nexus: Junimo Woods Runes").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_spring, player), + logic.received("Nexus: Sprite Spring Runes").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_outpost, player), + logic.received("Nexus: Outpost Runes").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_wizard, player), + logic.mod.sve.has_any_rune().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), + logic.relationship.has_hearts(ModNPC.apples, 10).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.to_grandpa_upstairs, player), + logic.special_order.can_complete_special_order("Grandpa's Shed").simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron).simplify()) + for location in logic.mod.sve.sve_location_rules: + MultiWorldRules.set_rule(multiworld.get_location(location, player), + logic.mod.sve.sve_location_rules[location].simplify()) set_sve_ginger_island_rules(logic, multiworld, player, world_options) diff --git a/worlds/stardew_valley/strings/special_order_names.py b/worlds/stardew_valley/strings/special_order_names.py index f7b49cdf05e9..76cd9634e3d8 100644 --- a/worlds/stardew_valley/strings/special_order_names.py +++ b/worlds/stardew_valley/strings/special_order_names.py @@ -31,3 +31,8 @@ class SpecialOrder: class ModSpecialOrder: junas_monster_mash = "Juna's Monster Mash" + andys_cellar = "Andy's Cellar" + a_mysterious_venture = "A Mysterious Venture" + an_elegant_reception = "An Elegant Reception" + fairy_garden = "Fairy Garden" + homemade_fertilizer = "Homemade Fertilizer" From 09929a9bbbbcc65bcf6b19a6bcdbd771d0c466d5 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 30 Oct 2023 07:27:55 -0500 Subject: [PATCH 099/482] Modified NPC injection method --- worlds/stardew_valley/data/villagers_data.py | 35 +++++++++++-------- worlds/stardew_valley/items.py | 5 ++- worlds/stardew_valley/locations.py | 5 ++- .../stardew_valley/strings/villager_names.py | 15 +++++++- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 13e9ab8584d1..242aa41cdf30 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -354,7 +354,8 @@ def __repr__(self): def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: str, gifts: Tuple[str, ...], available: bool, mod_name: Optional[str] = None) -> Villager: npc = Villager(name, bachelor, locations, birthday, gifts, available, mod_name) - all_villagers.append(npc) + if npc not in all_modified_villagers: + all_villagers.append(npc) return npc @@ -407,22 +408,26 @@ def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: st riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley) # SVE Villagers -claire = villager("Claire", True, town + jojamart, "Fall", universal_loves + claire_loves, True, "Stardew Valley Expanded") -lance = villager("Lance", True, adventurer + highlands + island, "Spring", lance_loves, False, "Stardew Valley Expanded") -mommy = villager("Olivia", True, town, "Spring", universal_loves_no_rabbit_foot + olivia_loves, True, "Stardew Valley Expanded") -sophia = villager("Sophia", True, bluemoon, "Winter", universal_loves_no_rabbit_foot + sophia_loves, True, "Stardew Valley Expanded") -victor = villager("Victor", True, town, "Summer", universal_loves + victor_loves, True, "Stardew Valley Expanded") -andy = villager("Andy", False, forest, "Spring", universal_loves + andy_loves, True, "Stardew Valley Expanded") -apples = villager("Apples", False, aurora + junimo, "Spring", starfruit, False, "Stardew Valley Expanded") -gunther = villager("Gunther", False, museum, "Winter", universal_loves + gunther_loves, True, "Stardew Valley Expanded") -martin = villager("Martin", False, town + jojamart, "Summer", universal_loves + martin_loves, True, "Stardew Valley Expanded") -marlon = villager("Marlon", False, adventurer, "Winter", universal_loves + marlon_loves, False, "Stardew Valley Expanded") -morgan = villager("Morgan", False, forest, "Fall", universal_loves_no_rabbit_foot + morgan_loves, False, "Stardew Valley Expanded") -scarlett = villager("Scarlett", False, bluemoon, "Summer", universal_loves + scarlett_loves, False, "Stardew Valley Expanded") -susan = villager("Susan", False, railroad, "Fall", universal_loves + susan_loves, False, "Stardew Valley Expanded") -morris = villager("Morris", False, jojamart, "Spring", universal_loves + morris_loves, True, "Stardew Valley Expanded") +claire = villager(ModNPC.claire, True, town + jojamart, Season.fall, universal_loves + claire_loves, True, ModNames.sve) +lance = villager(ModNPC.lance, True, adventurer + highlands + island, Season.spring, lance_loves, False, ModNames.sve) +mommy = villager(ModNPC.olivia, True, town, Season.spring, universal_loves_no_rabbit_foot + olivia_loves, True, ModNames.sve) +sophia = villager(ModNPC.sophia, True, bluemoon, Season.winter, universal_loves_no_rabbit_foot + sophia_loves, True, ModNames.sve) +victor = villager(ModNPC.victor, True, town, Season.summer, universal_loves + victor_loves, True, ModNames.sve) +andy = villager(ModNPC.andy, False, forest, Season.spring, universal_loves + andy_loves, True, ModNames.sve) +apples = villager(ModNPC.apples, False, aurora + junimo, Season.spring, starfruit, False, ModNames.sve) +gunther = villager(ModNPC.gunther, False, museum, Season.winter, universal_loves + gunther_loves, True, ModNames.sve) +martin = villager(ModNPC.martin, False, town + jojamart, Season.summer, universal_loves + martin_loves, True, ModNames.sve) +marlon = villager(ModNPC.marlon, False, adventurer, Season.winter, universal_loves + marlon_loves, False, ModNames.sve) +morgan = villager(ModNPC.morgan, False, forest, Season.fall, universal_loves_no_rabbit_foot + morgan_loves, False, ModNames.sve) +scarlett = villager(ModNPC.scarlett, False, bluemoon, Season.summer, universal_loves + scarlett_loves, False, ModNames.sve) +susan = villager(ModNPC.susan, False, railroad, Season.fall, universal_loves + susan_loves, False, ModNames.sve) +morris = villager(ModNPC.morris, False, jojamart, Season.spring, universal_loves + morris_loves, True, ModNames.sve) +# Modified villagers; not included in all villagers +magnus = villager(NPC.wizard, True, wizard_tower, Season.winter, universal_loves + wizard_loves, True, ModNames.sve) +all_modified_villagers = [magnus] +all_modified_villagers_by_name_by_mod: Dict[str, Dict[str, Villager]] = {NPC.wizard: {ModNames.sve: magnus}} all_villagers_by_name: Dict[str, Villager] = {villager.name: villager for villager in all_villagers} all_villagers_by_mod: Dict[str, List[Villager]] = {} all_villagers_by_mod_by_name: Dict[str, Dict[str, Villager]] = {} diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 75ea36c5db8e..14f10595dcfd 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -8,7 +8,7 @@ from BaseClasses import Item, ItemClassification from . import data -from .data.villagers_data import all_villagers +from .data.villagers_data import all_villagers, all_modified_villagers_by_name_by_mod from .mods.mod_data import ModNames from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, \ Friendsanity, Museumsanity, \ @@ -368,6 +368,9 @@ def create_friendsanity_items(item_factory: StardewItemFactory, options: Stardew for villager in all_villagers: if villager.mod_name not in mods and villager.mod_name is not None: continue + if villager.name in all_modified_villagers_by_name_by_mod and all_modified_villagers_by_name_by_mod[villager.name] in mods: + modified_villager_mod = all_modified_villagers_by_name_by_mod[villager.name] + villager = modified_villager_mod[villager.name] if not villager.available and exclude_locked_villagers: continue if not villager.bachelor and exclude_non_bachelors: diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 3825b9bb81f5..71a55c8a6314 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -8,7 +8,7 @@ from .options import StardewValleyOptions, Craftsanity, Chefsanity, Cooksanity, Shipsanity, Monstersanity from .data.fish_data import legendary_fish, special_fish, all_fish from .data.museum_data import all_museum_items -from .data.villagers_data import all_villagers +from .data.villagers_data import all_villagers, all_modified_villagers_by_name_by_mod from .options import ExcludeGingerIsland, Friendsanity, ArcadeMachineLocations, SpecialOrderLocations, Cropsanity, Fishsanity, Museumsanity, FestivalLocations, SkillProgression, BuildingProgression, ToolProgression, ElevatorProgression, BackpackProgression from .strings.goal_names import Goal from .strings.region_names import Region @@ -234,6 +234,9 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti for villager in all_villagers: if villager.mod_name not in options.mods and villager.mod_name is not None: continue + if villager.name in all_modified_villagers_by_name_by_mod and all_modified_villagers_by_name_by_mod[villager.name] in mods: + modified_villager_mod = all_modified_villagers_by_name_by_mod[villager.name] + villager = modified_villager_mod[villager.name] if not villager.available and exclude_locked_villagers: continue if not villager.bachelor and exclude_non_bachelors: diff --git a/worlds/stardew_valley/strings/villager_names.py b/worlds/stardew_valley/strings/villager_names.py index 2ff616d3dfd5..61443aa5e138 100644 --- a/worlds/stardew_valley/strings/villager_names.py +++ b/worlds/stardew_valley/strings/villager_names.py @@ -47,4 +47,17 @@ class ModNPC: shiko = "Shiko" wellwick = "Wellwick" yoba = "Yoba" - lance = "Lance" \ No newline at end of file + lance = "Lance" + apples = "Apples" + claire = "Claire" + olivia = "Olivia" + sophia = "Sophia" + victor = "Victor" + andy = "Andy" + gunther = "Gunther" + martin = "Martin" + marlon = "Marlon" + morgan = "Morgan" + morris = "Morris" + scarlett = "Scarlett" + susan = "Susan" From 4afd0ec7c6a93112d7b0cee8ca2f9e12f017810c Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 30 Oct 2023 08:59:15 -0500 Subject: [PATCH 100/482] Introduce new modified flags for mods. --- worlds/stardew_valley/data/villagers_data.py | 10 +++++----- worlds/stardew_valley/region_classes.py | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 242aa41cdf30..dadf2b748bd9 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -16,6 +16,7 @@ class Villager: birthday: str gifts: Tuple[str] available: bool + modified: Optional[bool] mod_name: Optional[str] def __repr__(self): @@ -352,9 +353,9 @@ def __repr__(self): def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: str, gifts: Tuple[str, ...], - available: bool, mod_name: Optional[str] = None) -> Villager: - npc = Villager(name, bachelor, locations, birthday, gifts, available, mod_name) - if npc not in all_modified_villagers: + available: bool, modified: Optional[bool] = False, mod_name: Optional[str] = None) -> Villager: + npc = Villager(name, bachelor, locations, birthday, gifts, available, modified, mod_name) + if not npc.modified: all_villagers.append(npc) return npc @@ -424,9 +425,8 @@ def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: st morris = villager(ModNPC.morris, False, jojamart, Season.spring, universal_loves + morris_loves, True, ModNames.sve) # Modified villagers; not included in all villagers -magnus = villager(NPC.wizard, True, wizard_tower, Season.winter, universal_loves + wizard_loves, True, ModNames.sve) +magnus = villager(NPC.wizard, True, wizard_tower, Season.winter, universal_loves + wizard_loves, True, True, ModNames.sve) -all_modified_villagers = [magnus] all_modified_villagers_by_name_by_mod: Dict[str, Dict[str, Villager]] = {NPC.wizard: {ModNames.sve: magnus}} all_villagers_by_name: Dict[str, Villager] = {villager.name: villager for villager in all_villagers} all_villagers_by_mod: Dict[str, List[Villager]] = {} diff --git a/worlds/stardew_valley/region_classes.py b/worlds/stardew_valley/region_classes.py index 9db322416a4d..41ff65d1294a 100644 --- a/worlds/stardew_valley/region_classes.py +++ b/worlds/stardew_valley/region_classes.py @@ -5,6 +5,10 @@ connector_keyword = " to " +class ModificationFlag(IntFlag): + NOT_MODIFIED = 0 + MODIFIED = 1 + class RandomizationFlag(IntFlag): NOT_RANDOMIZED = 0b0 PELICAN_TOWN = 0b11111 @@ -20,6 +24,7 @@ class RandomizationFlag(IntFlag): class RegionData: name: str exits: List[str] = field(default_factory=list) + flag: ModificationFlag = ModificationFlag.NOT_MODIFIED def get_merged_with(self, exits: List[str]): merged_exits = [] From d56bacec0072db4788c993f8b8adc4c4f307896b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 30 Oct 2023 09:00:09 -0500 Subject: [PATCH 101/482] Add remove exit method. --- worlds/stardew_valley/mods/mod_regions.py | 5 +++-- worlds/stardew_valley/regions.py | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 805dbd4a5da6..baa73b2f1811 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -1,8 +1,8 @@ -from ..strings.entrance_names import DeepWoodsEntrance, EugeneEntrance, \ +from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, \ JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, \ AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion -from ..region_classes import RegionData, ConnectionData, RandomizationFlag, ModRegionData +from ..region_classes import RegionData, ConnectionData, ModificationFlag, RandomizationFlag, ModRegionData from .mod_data import ModNames deep_woods_regions = [ @@ -184,6 +184,7 @@ RegionData(SVERegion.issac_shop), RegionData(SVERegion.summit), RegionData(SVERegion.susans_house), + RegionData(Region.mountain, [Entrance.mountain_to_adventurer_guild, Entrance.mountain_to_the_mines], ModificationFlag.MODIFIED) ] diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index d2b57ae34b97..590e688f2621 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -5,7 +5,7 @@ from .options import EntranceRandomization, ExcludeGingerIsland, Museumsanity from .strings.entrance_names import Entrance from .strings.region_names import Region -from .region_classes import RegionData, ConnectionData, RandomizationFlag +from .region_classes import RegionData, ConnectionData, RandomizationFlag, ModificationFlag from .mods.mod_regions import ModDataList @@ -480,10 +480,12 @@ def create_final_regions(world_options) -> List[RegionData]: (region for region in final_regions if region.name == mod_region.name), None) if existing_region: final_regions.remove(existing_region) + if ModificationFlag.MODIFIED in mod_region.flag: + mod_region = modify_vanilla_regions(existing_region, mod_region) final_regions.append(existing_region.get_merged_with(mod_region.exits)) continue - final_regions.append(mod_region.get_clone()) + return final_regions @@ -499,6 +501,17 @@ def create_final_connections(world_options) -> List[ConnectionData]: return final_connections +def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionData) -> RegionData: + + updated_region = existing_region + region_exits = updated_region.exits + modified_exits = modified_region.exits + for exits in modified_exits: + region_exits.remove(exits) + + return updated_region + + def create_regions(region_factory: RegionFactory, random: Random, world_options) -> Tuple[ Dict[str, Region], Dict[str, str]]: final_regions = create_final_regions(world_options) From 10b519e5fc736741a0acfbfaa542a036f98e7e71 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 06:14:38 -0600 Subject: [PATCH 102/482] Add SVE to options. --- worlds/stardew_valley/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index c52e40edd884..129e171e3ccc 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -699,7 +699,7 @@ class Mods(OptionSet): ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator + ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve } From 8c866e4c637e150cda68d25f0a08c3713b08062c Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 10:15:53 -0600 Subject: [PATCH 103/482] Fix some errors. --- worlds/stardew_valley/data/items.csv | 12 ++++++------ worlds/stardew_valley/items.py | 1 - worlds/stardew_valley/logic/bundle_logic.py | 1 - worlds/stardew_valley/logic/crop_logic.py | 19 +------------------ worlds/stardew_valley/logic/logic.py | 13 +++++++++++++ 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 35502144749b..68eda290a5ae 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -767,8 +767,10 @@ id,name,classification,groups,mod_name 10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded 10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods +10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded -10502,Diamond Wand,useful,"GINGER_ISLAND",Stardew Valley Expanded +10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10503,Iridium Bomb,progression,,Stardew Valley Expanded 10504,Krobus' Protection,useful,,Stardew Valley Expanded 10505,Kittyfish Spell,progression,,Stardew Valley Expanded @@ -779,9 +781,7 @@ id,name,classification,groups,mod_name 10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded 10511,Fable Reef Portal,progression,"GINGER_ISLAND,MOD_WARP",Stardew Valley Expanded 10512,Super Starfruit,useful,,Stardew Valley Expanded -10513,Tempered Galaxy Sword,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded -10514,Tempered Galaxy Dagger,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded -10515,Tempered Galaxy Hammer,progression,"TEMPERED_GALAXY_WEAPONS,WEAPON",Stardew Valley Expanded +10513,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10514,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10515,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10516,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded -10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods -10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 14f10595dcfd..8a72f06afc3e 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -79,7 +79,6 @@ class Group(enum.Enum): CRAFTSANITY = enum.auto() # Mods MAGIC_SPELL = enum.auto() - TEMPERED_GALAXY_WEAPONS = enum.auto() MOD_WARP = enum.auto() @dataclass(frozen=True) diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 0ed79fee0256..ae7d7d748442 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -15,7 +15,6 @@ class BundleLogic: has: HasLogic money: MoneyLogic region: RegionLogic - crop: CropLogic def __init__(self, player: int, crop: CropLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): self.player = player diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 5ed2d7356464..a839893c4149 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -3,7 +3,6 @@ from .has_logic import HasLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic -from .skill_logic import SkillLogic from .tool_logic import ToolLogic from ..data import CropItem from ..stardew_rule import StardewRule, True_ @@ -17,15 +16,13 @@ class CropLogic: has: HasLogic region: RegionLogic season: SeasonLogic - skill: SkillLogic tool: ToolLogic - def __init__(self, player: int, has: HasLogic, region: RegionLogic, season: SeasonLogic, skill: SkillLogic, tool: ToolLogic): + def __init__(self, player: int, has: HasLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic): self.player = player self.has = has self.region = region self.season = season - self.skill = skill self.tool = tool def can_grow(self, crop: CropItem) -> StardewRule: @@ -56,17 +53,3 @@ def has_fertilizer(self, tier: int) -> StardewRule: return self.has(Fertilizer.quality) if tier >= 3: return self.has(Fertilizer.deluxe) - - def can_grow_gold_quality(self, quality: int) -> StardewRule: - if quality <= 0: - return True_() - if quality == 1: - return self.skill.has_farming_level(5) | (self.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( - self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) - if quality == 2: - return self.skill.has_farming_level(10) | (self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( - self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( - self.has_fertilizer(3) & self.skill.has_farming_level(2)) - if quality >= 3: - return self.has_fertilizer(3) & self.skill.has_farming_level(4) - diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 2c8553fdf294..e6f802a2916a 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -577,6 +577,19 @@ def has_traveling_merchant(self, tier: int = 1): traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] return self.received(traveling_merchant_days, tier) + def can_grow_gold_quality(self, quality: int) -> StardewRule: + if quality <= 0: + return True_() + if quality == 1: + return self.skill.has_farming_level(5) | (self.crop.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( + self.crop.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.crop.has_fertilizer(3) + if quality == 2: + return self.skill.has_farming_level(10) | (self.crop.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( + self.crop.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( + self.crop.has_fertilizer(3) & self.skill.has_farming_level(2)) + if quality >= 3: + return self.crop.has_fertilizer(3) & self.skill.has_farming_level(4) + def can_complete_field_office(self) -> StardewRule: field_office = self.region.can_reach(Region.field_office) professor_snail = self.received("Open Professor Snail Cave") From 7c5675eb122cb7509e9b21d2a4a284ffa710ae1c Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 10:16:33 -0600 Subject: [PATCH 104/482] Fill out more strings --- worlds/stardew_valley/strings/crop_names.py | 11 +++++++++++ worlds/stardew_valley/strings/forageable_names.py | 6 +++++- worlds/stardew_valley/strings/monster_drop_names.py | 8 ++++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/strings/crop_names.py b/worlds/stardew_valley/strings/crop_names.py index 646f19dd4bce..a2668650bc36 100644 --- a/worlds/stardew_valley/strings/crop_names.py +++ b/worlds/stardew_valley/strings/crop_names.py @@ -58,3 +58,14 @@ class Vegetable: yam = veggie("Yam") radish = veggie("Radish") taro_root = veggie("Taro Root") + + +class SVEFruit: + slime_berry = "Slime Berry" + monster_fruit = "Monster Fruit" + + +class SVEVegetable: + monster_mushroom = "Monster Mushroom" + void_root = "Void Root" + diff --git a/worlds/stardew_valley/strings/forageable_names.py b/worlds/stardew_valley/strings/forageable_names.py index e482d3ef1558..163ce7ab5d61 100644 --- a/worlds/stardew_valley/strings/forageable_names.py +++ b/worlds/stardew_valley/strings/forageable_names.py @@ -33,4 +33,8 @@ class Forageable: spring_onion = "Spring Onion" - +class SVEForage: + ornate_treasure_chest = "Ornate Treasure Chest" + swirl_stone = "Swirl Stone" + void_pebble = "Void Pebble" + void_soul = "Void Soul" diff --git a/worlds/stardew_valley/strings/monster_drop_names.py b/worlds/stardew_valley/strings/monster_drop_names.py index 51ed84a245be..84c0f0d30277 100644 --- a/worlds/stardew_valley/strings/monster_drop_names.py +++ b/worlds/stardew_valley/strings/monster_drop_names.py @@ -7,7 +7,7 @@ class Loot: class ModLoot: - monster_mushroom = "Monster Mushroom" - slime_berry = "Slime Berry" - monster_fruit = "Monster Fruit" - void_root = "Void Root" + stalk_seed = "Stalk Seed" + fungus_seed = "Fungus Seed" + slime_seed = "Slime Seed" + void_seed = "Void Seed" From 791857b3851846ef3c52cad45143e464d44b3fe7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 10:17:02 -0600 Subject: [PATCH 105/482] Utilize new strings, fix class name issue --- worlds/stardew_valley/mods/logic/mod_logic.py | 6 +-- .../stardew_valley/mods/logic/quests_logic.py | 14 ++---- worlds/stardew_valley/mods/logic/sve_logic.py | 47 +++++++++++-------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 79d4f5b8a877..7989807e2363 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -4,7 +4,7 @@ from .deepwoods_logic import DeepWoodsLogic from .elevator_logic import ModElevatorLogic from .magic_logic import MagicLogic -from .quests_logic import QuestLogic +from .quests_logic import ModQuestLogic from .skills_logic import ModSkillLogic from .special_orders_logic import ModSpecialOrderLogic from .sve_logic import SVELogic @@ -32,7 +32,7 @@ class ModLogic: - quests: QuestLogic + quests: ModQuestLogic region: RegionLogic magic: MagicLogic buildings: ModBuildingLogic @@ -47,7 +47,7 @@ def __init__(self, player: int, skill_option: SkillProgression, elevator_option: combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): self.magic = MagicLogic(player, mods, received, region) - self.quests = QuestLogic(mods, has, region, season, relationship) + self.quests = ModQuestLogic(mods, has, region, season, relationship, received, time) self.buildings = ModBuildingLogic(player, has, money, mods) self.special_orders = ModSpecialOrderLogic(player, action, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 0c7091e8ad1a..ec458b9c9269 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -1,6 +1,5 @@ from typing import Dict -from ...logic.bundle_logic import BundleLogic from ...logic.has_logic import HasLogic from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic @@ -23,9 +22,8 @@ from ...stardew_rule import StardewRule -class QuestLogic: +class ModQuestLogic: mods: Mods - bundle: BundleLogic has: HasLogic region: RegionLogic season: SeasonLogic @@ -33,9 +31,8 @@ class QuestLogic: received: ReceivedLogic time: TimeLogic - def __init__(self, bundle: BundleLogic, mods: Mods, has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, + def __init__(self, mods: Mods, has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, received: ReceivedLogic, time: TimeLogic): - self.bundle = bundle self.mods = mods self.has = has self.region = region @@ -68,11 +65,10 @@ def get_modded_quest_rules(self) -> Dict[str, StardewRule]: ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has([Ore.iridium, Material.coal]) & self.region.can_reach(Region.blacksmith) & self.region.can_reach(Region.railroad), ModQuest.GrandpasShed: self.has([Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone]) & - self.region.can_reach(SVERegion.grandpas_shed_interior), + self.region.can_reach(SVERegion.grandpas_shed_interior), ModQuest.MarlonsBoat: self.has([Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat]) & - self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), - ModQuest.AuroraVineyard: self.bundle.can_complete_community_center() & self.has(Fruit.starfruit) & - self.region.can_reach(SVERegion.aurora_vineyard) & self.time.has_year_two(), + self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), + ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), ModQuest.MonsterCrops: self.has([ModLoot.monster_mushroom, ModLoot.slime_berry, ModLoot.monster_fruit, ModLoot.void_root]), ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(ModQuest.VoidSoul), }) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 14efa8e05620..f910348b4b97 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -1,5 +1,5 @@ from typing import Dict -from dataclasses import field +from dataclasses import field, dataclass from ...logic.action_logic import ActionLogic from ...logic.building_logic import BuildingLogic @@ -17,13 +17,20 @@ from ...logic.tool_logic import ToolLogic from ..mod_regions import SVERegion from ...options import SkillProgression -from ...strings.fish_names import SVEFish +from ...strings.crop_names import SVEVegetable, SVEFruit +from ...strings.fish_names import Fish, SVEFish +from ...strings.forageable_names import SVEForage from ...strings.ingredient_names import Ingredient +from ...strings.food_names import Meal +from ...strings.monster_drop_names import Loot, ModLoot from ...strings.region_names import Region +from ...strings.season_names import Season +from ...strings.tool_names import Tool, ToolMaterial from ...strings.villager_names import NPC from ...stardew_rule import StardewRule, Or +@dataclass(frozen=False, repr=False) class SVELogic: player: int received: ReceivedLogic @@ -84,29 +91,29 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv def set_sve_item_rules(self, items: Dict[str, StardewRule]): items.update({ "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), - "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, "Bread", "Oil"]) & + "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & self.region.can_reach(Region.saloon), "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), - "Fungus Seed": self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend(4000) & self.region.can_reach(Region.saloon), - "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool("Axe", "Iron"), - "Monster Fruit": self.season.has("Summer") & self.has("Stalk Seed"), - "Monster Mushroom": self.has("Fall") & self.has("Fungus Seed"), - "Ornate Treasure Chest": self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & - self.cooking.can_cook() & self.tool.has_tool("Axe", "Iron"), - "Slime Berry": self.season.has("Spring") & self.has("Slime Seed"), - "Slime Seed": self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - "Stalk Seed": self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - "Swirl Stone": self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), - "Void Delight": self.has("Void Eel") & self.has("Void Essence") & self.has("Solar Essence"), - "Void Pebble": self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), - "Void Root": self.season.has("Winter") & self.has("Void Seed"), - "Void Salmon Sushi": self.has("Void Salmon") & self.has("Void Mayonnaise") & self.has("Seaweed"), - "Void Seed": self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - "Void Soul": self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & - self.cooking.can_cook(), + "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), + SVEVegetable.monster_mushroom: self.has(Season.fall) & self.has(ModLoot.fungus_seed), + SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & + self.cooking.can_cook() & self.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(ModLoot.slime_seed), + ModLoot.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), + "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), + SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), + SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), + "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), + ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & + self.cooking.can_cook(), }) def has_any_rune(self): From 24b7d5e447800b8f587facb2f64bf30da08d74d9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 16:46:58 +0200 Subject: [PATCH 106/482] - Add system for modifying villagers when some mods are active --- worlds/stardew_valley/data/villagers_data.py | 63 ++++++--- worlds/stardew_valley/items.py | 9 +- worlds/stardew_valley/locations.py | 9 +- .../test/mods/TestModVillagers.py | 129 ++++++++++++++++++ 4 files changed, 178 insertions(+), 32 deletions(-) create mode 100644 worlds/stardew_valley/test/mods/TestModVillagers.py diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index dadf2b748bd9..c45bd26a11b3 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Tuple, Optional, Dict +from typing import List, Tuple, Optional, Dict, Callable, Set from ..strings.food_names import Beverage from ..strings.region_names import Region, SVERegion @@ -16,15 +16,14 @@ class Villager: birthday: str gifts: Tuple[str] available: bool - modified: Optional[bool] - mod_name: Optional[str] + mod_names: List[str] def __repr__(self): return f"{self.name} [Bachelor: {self.bachelor}] [Available from start: {self.available}]" \ f"(Locations: {self.locations} |" \ f" Birthday: {self.birthday} |" \ f" Gifts: {self.gifts}) |" \ - f" Mod: {self.mod_name}" + f" Mod: {self.mod_names}" town = (Region.town,) @@ -350,16 +349,26 @@ def __repr__(self): blueberry_tart + blackberry_cobbler + cranberry_candy + red_plate all_villagers: List[Villager] = [] +villager_modifications_by_mod: Dict[str, Dict[str, Callable[[str, Villager], Villager]]] = {} def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: str, gifts: Tuple[str, ...], - available: bool, modified: Optional[bool] = False, mod_name: Optional[str] = None) -> Villager: - npc = Villager(name, bachelor, locations, birthday, gifts, available, modified, mod_name) - if not npc.modified: - all_villagers.append(npc) + available: bool, mod_name: Optional[str] = None) -> Villager: + npc = Villager(name, bachelor, locations, birthday, gifts, available, [mod_name] if mod_name is not None else []) + all_villagers.append(npc) return npc +def make_bachelor(mod_name: str, npc: Villager): + return Villager(npc.name, True, npc.locations, npc.birthday, npc.gifts, npc.available, [*npc.mod_names, mod_name]) + + +def register_villager_modification(mod_name: str, npc: Villager, modification_function): + if mod_name not in villager_modifications_by_mod: + villager_modifications_by_mod[mod_name] = {} + villager_modifications_by_mod[mod_name][npc.name] = modification_function + + josh = villager(NPC.alex, True, town + alex_house, Season.summer, universal_loves + complete_breakfast + salmon_dinner, True) elliott = villager(NPC.elliott, True, town + beach + elliott_house, Season.fall, universal_loves + elliott_loves, True) harvey = villager(NPC.harvey, True, town + hospital, Season.winter, universal_loves + harvey_loves, True) @@ -425,20 +434,38 @@ def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: st morris = villager(ModNPC.morris, False, jojamart, Season.spring, universal_loves + morris_loves, True, ModNames.sve) # Modified villagers; not included in all villagers -magnus = villager(NPC.wizard, True, wizard_tower, Season.winter, universal_loves + wizard_loves, True, True, ModNames.sve) -all_modified_villagers_by_name_by_mod: Dict[str, Dict[str, Villager]] = {NPC.wizard: {ModNames.sve: magnus}} +register_villager_modification(ModNames.sve, wizard, make_bachelor) + all_villagers_by_name: Dict[str, Villager] = {villager.name: villager for villager in all_villagers} all_villagers_by_mod: Dict[str, List[Villager]] = {} all_villagers_by_mod_by_name: Dict[str, Dict[str, Villager]] = {} + for npc in all_villagers: - mod = npc.mod_name + mods = npc.mod_names name = npc.name - if mod in all_villagers_by_mod: - all_villagers_by_mod[mod].append(npc) - all_villagers_by_mod_by_name[mod][name] = npc - else: - all_villagers_by_mod[mod] = [npc] - all_villagers_by_mod_by_name[mod] = {} - all_villagers_by_mod_by_name[mod][name] = npc + for mod in mods: + if mod in all_villagers_by_mod: + all_villagers_by_mod[mod].append(npc) + all_villagers_by_mod_by_name[mod][name] = npc + else: + all_villagers_by_mod[mod] = [npc] + all_villagers_by_mod_by_name[mod] = {} + all_villagers_by_mod_by_name[mod][name] = npc + + +def all_villagers_for_current_mods(mods: Set[str]) -> List[Villager]: + villagers_for_current_mods = [] + for npc in all_villagers: + if npc.mod_names and not all([mod in mods for mod in npc.mod_names]): + continue + modified_npc = npc + for active_mod in mods: + if (active_mod not in villager_modifications_by_mod or + npc.name not in villager_modifications_by_mod[active_mod]): + continue + modification = villager_modifications_by_mod[active_mod][npc.name] + modified_npc = modification(active_mod, modified_npc) + villagers_for_current_mods.append(modified_npc) + return villagers_for_current_mods diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 8a72f06afc3e..02ab700eb88b 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -8,7 +8,7 @@ from BaseClasses import Item, ItemClassification from . import data -from .data.villagers_data import all_villagers, all_modified_villagers_by_name_by_mod +from .data.villagers_data import all_villagers_for_current_mods from .mods.mod_data import ModNames from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, \ Friendsanity, Museumsanity, \ @@ -364,12 +364,7 @@ def create_friendsanity_items(item_factory: StardewItemFactory, options: Stardew exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true mods = options.mods heart_size = options.friendsanity_heart_size - for villager in all_villagers: - if villager.mod_name not in mods and villager.mod_name is not None: - continue - if villager.name in all_modified_villagers_by_name_by_mod and all_modified_villagers_by_name_by_mod[villager.name] in mods: - modified_villager_mod = all_modified_villagers_by_name_by_mod[villager.name] - villager = modified_villager_mod[villager.name] + for villager in all_villagers_for_current_mods(mods.value): if not villager.available and exclude_locked_villagers: continue if not villager.bachelor and exclude_non_bachelors: diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 71a55c8a6314..db0aac9fbbfc 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -8,7 +8,7 @@ from .options import StardewValleyOptions, Craftsanity, Chefsanity, Cooksanity, Shipsanity, Monstersanity from .data.fish_data import legendary_fish, special_fish, all_fish from .data.museum_data import all_museum_items -from .data.villagers_data import all_villagers, all_modified_villagers_by_name_by_mod +from .data.villagers_data import all_villagers_for_current_mods from .options import ExcludeGingerIsland, Friendsanity, ArcadeMachineLocations, SpecialOrderLocations, Cropsanity, Fishsanity, Museumsanity, FestivalLocations, SkillProgression, BuildingProgression, ToolProgression, ElevatorProgression, BackpackProgression from .strings.goal_names import Goal from .strings.region_names import Region @@ -231,12 +231,7 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti options.friendsanity == Friendsanity.option_bachelors include_post_marriage_hearts = options.friendsanity == Friendsanity.option_all_with_marriage heart_size = options.friendsanity_heart_size - for villager in all_villagers: - if villager.mod_name not in options.mods and villager.mod_name is not None: - continue - if villager.name in all_modified_villagers_by_name_by_mod and all_modified_villagers_by_name_by_mod[villager.name] in mods: - modified_villager_mod = all_modified_villagers_by_name_by_mod[villager.name] - villager = modified_villager_mod[villager.name] + for villager in all_villagers_for_current_mods(options.mods.value): if not villager.available and exclude_locked_villagers: continue if not villager.bachelor and exclude_non_bachelors: diff --git a/worlds/stardew_valley/test/mods/TestModVillagers.py b/worlds/stardew_valley/test/mods/TestModVillagers.py new file mode 100644 index 000000000000..bc38ccc70f0b --- /dev/null +++ b/worlds/stardew_valley/test/mods/TestModVillagers.py @@ -0,0 +1,129 @@ +import unittest +from typing import Set + +from ...data.villagers_data import all_villagers_for_current_mods +from ...mods.mod_data import ModNames +from ...strings.villager_names import NPC, ModNPC + +no_mods: Set[str] = set() +sve: Set[str] = {ModNames.sve} + + +class TestGetVillagersForMods(unittest.TestCase): + + def test_no_mods_all_vanilla_villagers(self): + villagers = all_villagers_for_current_mods(no_mods) + villager_names = {villager.name for villager in villagers} + + self.assertIn(NPC.alex, villager_names) + self.assertIn(NPC.elliott, villager_names) + self.assertIn(NPC.harvey, villager_names) + self.assertIn(NPC.sam, villager_names) + self.assertIn(NPC.sebastian, villager_names) + self.assertIn(NPC.shane, villager_names) + self.assertIn(NPC.abigail, villager_names) + self.assertIn(NPC.emily, villager_names) + self.assertIn(NPC.haley, villager_names) + self.assertIn(NPC.leah, villager_names) + self.assertIn(NPC.maru, villager_names) + self.assertIn(NPC.penny, villager_names) + self.assertIn(NPC.caroline, villager_names) + self.assertIn(NPC.clint, villager_names) + self.assertIn(NPC.demetrius, villager_names) + self.assertIn(NPC.dwarf, villager_names) + self.assertIn(NPC.evelyn, villager_names) + self.assertIn(NPC.george, villager_names) + self.assertIn(NPC.gus, villager_names) + self.assertIn(NPC.jas, villager_names) + self.assertIn(NPC.jodi, villager_names) + self.assertIn(NPC.kent, villager_names) + self.assertIn(NPC.krobus, villager_names) + self.assertIn(NPC.leo, villager_names) + self.assertIn(NPC.lewis, villager_names) + self.assertIn(NPC.linus, villager_names) + self.assertIn(NPC.marnie, villager_names) + self.assertIn(NPC.pam, villager_names) + self.assertIn(NPC.pierre, villager_names) + self.assertIn(NPC.robin, villager_names) + self.assertIn(NPC.sandy, villager_names) + self.assertIn(NPC.vincent, villager_names) + self.assertIn(NPC.willy, villager_names) + self.assertIn(NPC.wizard, villager_names) + + def test_no_mods_no_mod_villagers(self): + villagers = all_villagers_for_current_mods(no_mods) + villager_names = {villager.name for villager in villagers} + + self.assertNotIn(ModNPC.alec, villager_names) + self.assertNotIn(ModNPC.ayeisha, villager_names) + self.assertNotIn(ModNPC.delores, villager_names) + self.assertNotIn(ModNPC.eugene, villager_names) + self.assertNotIn(ModNPC.jasper, villager_names) + self.assertNotIn(ModNPC.juna, villager_names) + self.assertNotIn(ModNPC.mr_ginger, villager_names) + self.assertNotIn(ModNPC.riley, villager_names) + self.assertNotIn(ModNPC.shiko, villager_names) + self.assertNotIn(ModNPC.wellwick, villager_names) + self.assertNotIn(ModNPC.yoba, villager_names) + self.assertNotIn(ModNPC.lance, villager_names) + self.assertNotIn(ModNPC.apples, villager_names) + self.assertNotIn(ModNPC.claire, villager_names) + self.assertNotIn(ModNPC.olivia, villager_names) + self.assertNotIn(ModNPC.sophia, villager_names) + self.assertNotIn(ModNPC.victor, villager_names) + self.assertNotIn(ModNPC.andy, villager_names) + self.assertNotIn(ModNPC.gunther, villager_names) + self.assertNotIn(ModNPC.martin, villager_names) + self.assertNotIn(ModNPC.marlon, villager_names) + self.assertNotIn(ModNPC.morgan, villager_names) + self.assertNotIn(ModNPC.morris, villager_names) + self.assertNotIn(ModNPC.scarlett, villager_names) + self.assertNotIn(ModNPC.susan, villager_names) + + def test_sve_has_sve_villagers(self): + villagers = all_villagers_for_current_mods(sve) + villager_names = {villager.name for villager in villagers} + + self.assertIn(ModNPC.lance, villager_names) + self.assertIn(ModNPC.apples, villager_names) + self.assertIn(ModNPC.claire, villager_names) + self.assertIn(ModNPC.olivia, villager_names) + self.assertIn(ModNPC.sophia, villager_names) + self.assertIn(ModNPC.victor, villager_names) + self.assertIn(ModNPC.andy, villager_names) + self.assertIn(ModNPC.gunther, villager_names) + self.assertIn(ModNPC.martin, villager_names) + self.assertIn(ModNPC.marlon, villager_names) + self.assertIn(ModNPC.morgan, villager_names) + self.assertIn(ModNPC.morris, villager_names) + self.assertIn(ModNPC.scarlett, villager_names) + self.assertIn(ModNPC.susan, villager_names) + + def test_sve_has_no_other_mod_villagers(self): + villagers = all_villagers_for_current_mods(sve) + villager_names = {villager.name for villager in villagers} + + self.assertNotIn(ModNPC.alec, villager_names) + self.assertNotIn(ModNPC.ayeisha, villager_names) + self.assertNotIn(ModNPC.delores, villager_names) + self.assertNotIn(ModNPC.eugene, villager_names) + self.assertNotIn(ModNPC.jasper, villager_names) + self.assertNotIn(ModNPC.juna, villager_names) + self.assertNotIn(ModNPC.mr_ginger, villager_names) + self.assertNotIn(ModNPC.riley, villager_names) + self.assertNotIn(ModNPC.shiko, villager_names) + self.assertNotIn(ModNPC.wellwick, villager_names) + self.assertNotIn(ModNPC.yoba, villager_names) + + def test_no_mods_wizard_is_not_bachelor(self): + villagers = all_villagers_for_current_mods(no_mods) + villagers_by_name = {villager.name: villager for villager in villagers} + self.assertFalse(villagers_by_name[NPC.wizard].bachelor) + self.assertEqual(len(villagers_by_name[NPC.wizard].mod_names), 0) + + def test_sve_wizard_is_bachelor(self): + villagers = all_villagers_for_current_mods(sve) + villagers_by_name = {villager.name: villager for villager in villagers} + self.assertTrue(villagers_by_name[NPC.wizard].bachelor) + self.assertEqual(len(villagers_by_name[NPC.wizard].mod_names), 1) + self.assertIn(ModNames.sve, villagers_by_name[NPC.wizard].mod_names) From ca244e4b2a59755849f479e55a2487e4b1e7d77a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 20:53:51 +0200 Subject: [PATCH 107/482] - Fix Quests Logic --- worlds/stardew_valley/logic/logic.py | 4 ++-- worlds/stardew_valley/logic/quest_logic.py | 13 ++++++++----- worlds/stardew_valley/mods/logic/buildings_logic.py | 7 ++++--- worlds/stardew_valley/mods/logic/quests_logic.py | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index e6f802a2916a..4601bef188af 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -452,8 +452,8 @@ def __post_init__(self): self.buildings.initialize_rules() self.buildings.update_rules(self.mod.buildings.get_modded_building_rules()) - self.quest_rules.update(self.quest.set_quest_rules()) - self.quest_rules.update(self.mod.quests.get_modded_quest_rules()) + self.quest.initialize_rules() + self.quest.update_rules(self.mod.quests.get_modded_quest_rules()) self.festival_rules.update({ FestivalCheck.egg_hunt: self.can_win_egg_hunt(), diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index eb7cc0728093..0d1b92d711d0 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -51,6 +51,7 @@ class QuestLogic: combat: CombatLogic season: SeasonLogic skill: SkillLogic + quest_rules: Dict[str, StardewRule] def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, mine: MineLogic, region: RegionLogic, action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, @@ -71,10 +72,10 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv self.money = money self.combat = combat self.season = season + self.quest_rules = dict() - def set_quest_rules(self): - quest_rules = Dict[self, StardewRule] = field(default_factory=dict) - quest_rules.update({ + def initialize_rules(self): + self.quest_rules.update({ Quest.introductions: self.region.can_reach(Region.town), Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), Quest.getting_started: self.has(Vegetable.parsnip) & self.tool.has_tool(Tool.hoe) & self.tool.can_water(0), @@ -128,7 +129,9 @@ def set_quest_rules(self): self.relationship.can_meet(NPC.gus) & self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & self.relationship.can_meet(NPC.wizard) & self.relationship.can_meet(NPC.willy), }) - return quest_rules + + def update_rules(self, new_rules: Dict[str, StardewRule]): + self.quest_rules.update(new_rules) def can_complete_quest(self, quest: str) -> StardewRule: - return Has(quest, self.set_quest_rules()) + return Has(quest, self.quest_rules) diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 2e151538c1a8..19e77ea8cd15 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -1,5 +1,6 @@ -from typing import Iterable +from typing import Iterable, Dict +from ... import StardewRule from ...logic.has_logic import HasLogic from ...logic.money_logic import MoneyLogic from ...options import Mods @@ -22,8 +23,8 @@ def __init__(self, player: int, has: HasLogic, money: MoneyLogic, mods_option: M self.money = money self.mods_option = mods_option - def get_modded_building_rules(self): - buildings = {} + def get_modded_building_rules(self) -> Dict[str, StardewRule]: + buildings = dict() if ModNames.tractor in self.mods_option: tractor_rule = self.money.can_spend_at(Region.carpenter, 150000) & self.has(MetalBar.iron) & self.has(MetalBar.iridium) & self.has(ArtisanGood.battery_pack) buildings.update({ModBuilding.tractor_garage: tractor_rule}) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index ec458b9c9269..1242629bf208 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -42,7 +42,7 @@ def __init__(self, mods: Mods, has: HasLogic, region: RegionLogic, season: Seaso self.time = time def get_modded_quest_rules(self) -> Dict[str, StardewRule]: - quests = {} + quests = dict() if ModNames.juna in self.mods: quests.update({ ModQuest.JunaCola: self.relationship.has_hearts(ModNPC.juna, 3) & self.has(Beverage.joja_cola), From 63a9ab3a18db31aaaa8ee527f8be5b127933341f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 8 Nov 2023 20:55:56 +0200 Subject: [PATCH 108/482] - Gave SVE logic a little push in the right direction --- worlds/stardew_valley/mods/logic/sve_logic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index f910348b4b97..b1b11688921d 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -30,7 +30,6 @@ from ...stardew_rule import StardewRule, Or -@dataclass(frozen=False, repr=False) class SVELogic: player: int received: ReceivedLogic @@ -45,8 +44,7 @@ class SVELogic: money: MoneyLogic combat: CombatLogic season: SeasonLogic - - sve_location_rules: Dict[str, StardewRule] = field(default_factory=dict) + sve_location_rules: Dict[str, StardewRule] def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, quest: QuestLogic, region: RegionLogic, action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, @@ -67,7 +65,9 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv self.money = money self.combat = combat self.season = season + self.sve_location_rules = dict() + def initialize_rules(self): self.sve_location_rules.update({ "Bear: Baked Berry Oatmeal Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend( 12500), From b9326b790d6a06de5144c39a5ac87e788d916e7c Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 21:32:45 -0600 Subject: [PATCH 109/482] Clean up relationship logic due to villager change. --- worlds/stardew_valley/data/villagers_data.py | 3 +-- worlds/stardew_valley/logic/relationship_logic.py | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index c45bd26a11b3..03893a0ede09 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -308,7 +308,6 @@ def __repr__(self): bruschetta = ("Brushetta",) apricot = ("Apricot",) ocean_stone = ("Ocean Stone",) -galaxy_soul = ("Galaxy Soul",) fairy_stone = ("Fairy Stone",) lunarite = ("Lunarite",) bean_hotpot = ("Bean Hotpot",) @@ -326,7 +325,7 @@ def __repr__(self): blueberry_tart = ("Blueberry Tart",) claire_loves = green_tea + sunflower + energy_tonic + bruschetta + apricot + ocean_stone + glazed_butterfish -lance_loves = aged_blue_moon_wine + daggerfish + galaxy_soul + gemfish + golden_pumpkin + \ +lance_loves = aged_blue_moon_wine + daggerfish + gemfish + golden_pumpkin + \ green_mushroom + monster_mushroom + swirl_stone + torpedo_trout + tropical_curry + void_shard + \ ornate_treasure_chest olivia_loves = wine + chocolate_cake + pink_cake + golden_mask + golden_relic + \ diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 5a553b67fcb3..242e22e41bf3 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -10,7 +10,7 @@ from .season_logic import SeasonLogic from .time_logic import TimeLogic from .. import options -from ..data.villagers_data import all_villagers_by_name, Villager +from ..data.villagers_data import all_villagers_by_name, all_villagers_for_current_mods, Villager from ..options import Friendsanity, FriendsanityHeartSize, Mods from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic @@ -168,8 +168,8 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] - mod = npc.mod_name - return mod is None or mod in self.mods_option + mod = npc.mod_names + return not mod or npc in all_villagers_for_current_mods(self.mods_option.value) def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): From 13bcb81669d57ebd4342cfd6430078217a9663f2 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 21:36:10 -0600 Subject: [PATCH 110/482] Clean up logic with more proper imports. --- worlds/stardew_valley/logic/bundle_logic.py | 15 ++++++---- worlds/stardew_valley/logic/farming_logic.py | 29 +++++++++++++++++++ worlds/stardew_valley/logic/logic.py | 21 ++++---------- worlds/stardew_valley/logic/quest_logic.py | 15 ++++++---- .../mods/logic/buildings_logic.py | 4 +-- 5 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 worlds/stardew_valley/logic/farming_logic.py diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index ae7d7d748442..fb7d7e27b1dd 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -2,9 +2,10 @@ from ..data.bundle_data import BundleItem from .crop_logic import CropLogic -from ..logic.has_logic import HasLogic -from ..logic.money_logic import MoneyLogic -from ..logic.region_logic import RegionLogic +from .farming_logic import FarmingLogic +from .has_logic import HasLogic +from .money_logic import MoneyLogic +from .region_logic import RegionLogic from ..stardew_rule import StardewRule from ..strings.region_names import Region @@ -12,13 +13,15 @@ class BundleLogic: player: int crop: CropLogic + farming: FarmingLogic has: HasLogic - money: MoneyLogic region: RegionLogic + money: MoneyLogic - def __init__(self, player: int, crop: CropLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + def __init__(self, player: int, crop: CropLogic, farming: FarmingLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): self.player = player self.crop = crop + self.farming = farming self.has = has self.region = region self.money = money @@ -34,7 +37,7 @@ def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_requ item_rules.append(bundle_item.item.name) if bundle_item.quality > highest_quality_yet: highest_quality_yet = bundle_item.quality - return can_speak_junimo & self.has(item_rules, number_required) & self.crop.can_grow_gold_quality(highest_quality_yet) + return can_speak_junimo & self.has(item_rules, number_required) & self.farming.can_grow_gold_quality(highest_quality_yet) def can_complete_community_center(self) -> StardewRule: return (self.region.can_reach_location("Complete Crafts Room") & diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py new file mode 100644 index 000000000000..3a9ced9948ba --- /dev/null +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -0,0 +1,29 @@ +from ..stardew_rule import StardewRule, True_ +from .skill_logic import SkillLogic +from .crop_logic import CropLogic + + +class FarmingLogic: + player: int + crop: CropLogic + skill: SkillLogic + + def __init__(self, player: int, crop: CropLogic, skill: SkillLogic): + self.player = player + self.crop = crop + self.skill = skill + + def can_grow_gold_quality(self, quality: int) -> StardewRule: + if quality <= 0: + return True_() + if quality == 1: + return self.skill.has_farming_level(5) | (self.crop.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( + self.crop.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.crop.has_fertilizer(3) + if quality == 2: + return self.skill.has_farming_level(10) | ( + self.crop.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( + self.crop.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( + self.crop.has_fertilizer(3) & self.skill.has_farming_level(2)) + if quality >= 3: + return self.crop.has_fertilizer(3) & self.skill.has_farming_level(4) + diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 4601bef188af..52e71047e1c9 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -8,10 +8,12 @@ from .arcade_logic import ArcadeLogic from .artisan_logic import ArtisanLogic from .building_logic import BuildingLogic +from .bundle_logic import BundleLogic from .combat_logic import CombatLogic from .cooking_logic import CookingLogic from .crafting_logic import CraftingLogic from .crop_logic import CropLogic +from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic from .gift_logic import GiftLogic from .mine_logic import MineLogic @@ -130,6 +132,8 @@ def __post_init__(self): self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) self.crop = CropLogic(self.player, self.has, self.region, self.season, self.tool) self.skill = SkillLogic(self.player, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) + self.farming = FarmingLogic(self.player, self.crop, self.skill) + self.bundle = BundleLogic(self.player, self.crop, self.farming, self.has, self.region, self.money) self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) @@ -138,8 +142,8 @@ def __post_init__(self): self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) - self.quest = QuestLogic(self.player, skill_option, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, - self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, mods_option) + self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, + self.time, self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, self.wallet, mods_option) self.crafting = CraftingLogic(self.player, self.options.craftsanity, self.options.festival_locations, self.options.special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) @@ -577,19 +581,6 @@ def has_traveling_merchant(self, tier: int = 1): traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] return self.received(traveling_merchant_days, tier) - def can_grow_gold_quality(self, quality: int) -> StardewRule: - if quality <= 0: - return True_() - if quality == 1: - return self.skill.has_farming_level(5) | (self.crop.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( - self.crop.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.crop.has_fertilizer(3) - if quality == 2: - return self.skill.has_farming_level(10) | (self.crop.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( - self.crop.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( - self.crop.has_fertilizer(3) & self.skill.has_farming_level(2)) - if quality >= 3: - return self.crop.has_fertilizer(3) & self.skill.has_farming_level(4) - def can_complete_field_office(self) -> StardewRule: field_office = self.region.can_reach(Region.field_office) professor_snail = self.received("Open Professor Snail Cave") diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 0d1b92d711d0..82b067374fac 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -14,7 +14,9 @@ from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic from .skill_logic import SkillLogic +from .time_logic import TimeLogic from .tool_logic import ToolLogic +from .wallet_logic import WalletLogic from ..options import SkillProgression, Mods from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building @@ -51,13 +53,14 @@ class QuestLogic: combat: CombatLogic season: SeasonLogic skill: SkillLogic + wallet: WalletLogic quest_rules: Dict[str, StardewRule] - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, mine: MineLogic, region: RegionLogic, action: ActionLogic, - relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, mods_option: Mods): + def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogic, has: HasLogic, mine: MineLogic, region: RegionLogic, action: ActionLogic, + relationship: RelationshipLogic, building: BuildingLogic, time: TimeLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): self.player = player - self.skill_option = skill_option + self.skill = skill self.received = received self.has = has self.mine = mine @@ -65,6 +68,7 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv self.action = action self.relationship = relationship self.building = building + self.time = time self.tool = tool self.fishing = fishing self.cooking = cooking @@ -72,6 +76,7 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv self.money = money self.combat = combat self.season = season + self.wallet = wallet self.quest_rules = dict() def initialize_rules(self): @@ -90,7 +95,7 @@ def initialize_rules(self): Quest.robins_lost_axe: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.can_meet(NPC.robin), Quest.jodis_request: self.season.has(Season.spring) & self.has(Vegetable.cauliflower) & self.relationship.can_meet(NPC.jodi), Quest.mayors_shorts: self.season.has(Season.summer) & self.region.can_reach(Region.ranch) & - (self.relationship.has_hearts(NPC.marnie, 2) | (self.mod.magic.can_blink())) & self.relationship.can_meet(NPC.lewis), + self.relationship.has_hearts(NPC.marnie, 2) & self.relationship.can_meet(NPC.lewis), Quest.blackberry_basket: self.season.has(Season.fall) & self.relationship.can_meet(NPC.linus), Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot) & self.region.can_reach(Region.ranch), Quest.pam_is_thirsty: self.season.has(Season.summer) & self.has(ArtisanGood.pale_ale) & self.relationship.can_meet(NPC.pam), diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 19e77ea8cd15..45d4dcb1d11f 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -1,6 +1,6 @@ -from typing import Iterable, Dict +from typing import Dict -from ... import StardewRule +from ...stardew_rule import StardewRule from ...logic.has_logic import HasLogic from ...logic.money_logic import MoneyLogic from ...options import Mods From eec692b7c03d419ac5074efbcdff3cc842a592a4 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 8 Nov 2023 21:36:46 -0600 Subject: [PATCH 111/482] Fix friendsanity villager checks. --- worlds/stardew_valley/items.py | 2 +- worlds/stardew_valley/locations.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 02ab700eb88b..e77188720fec 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -354,7 +354,7 @@ def create_museum_items(item_factory: StardewItemFactory, options: StardewValley def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item], random): - island_villagers = [NPC.Leo, ModNPC.lance] + island_villagers = [NPC.leo, ModNPC.lance] if options.friendsanity == Friendsanity.option_none: return exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index db0aac9fbbfc..5f65b1da8136 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -11,6 +11,7 @@ from .data.villagers_data import all_villagers_for_current_mods from .options import ExcludeGingerIsland, Friendsanity, ArcadeMachineLocations, SpecialOrderLocations, Cropsanity, Fishsanity, Museumsanity, FestivalLocations, SkillProgression, BuildingProgression, ToolProgression, ElevatorProgression, BackpackProgression from .strings.goal_names import Goal +from .strings.villager_names import NPC, ModNPC from .strings.region_names import Region LOCATION_CODE_OFFSET = 717000 @@ -222,10 +223,11 @@ def extend_museumsanity_locations(randomized_locations: List[LocationData], opti def extend_friendsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + island_villagers = [NPC.leo, ModNPC.lance] if options.friendsanity == Friendsanity.option_none: return - exclude_leo = options.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors exclude_locked_villagers = options.friendsanity == Friendsanity.option_starting_npcs or \ options.friendsanity == Friendsanity.option_bachelors @@ -236,7 +238,7 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti continue if not villager.bachelor and exclude_non_bachelors: continue - if villager.name == "Leo" and exclude_leo: + if villager.name in island_villagers and exclude_ginger_island: continue heart_cap = 8 if villager.bachelor else 10 if include_post_marriage_hearts and villager.bachelor: From b5215609dbd9010246cbfb3956a5a17dd0323eaa Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 9 Nov 2023 14:39:56 +0200 Subject: [PATCH 112/482] - Fixed a bunch of syntax errors left and right - Fixed mod fish - Added test for mod fish - Fixed missing regions - Fixed logic rules --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/data/craftable_data.py | 2 +- worlds/stardew_valley/data/fish_data.py | 65 ++--- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 60 ++--- worlds/stardew_valley/data/recipe_data.py | 2 +- worlds/stardew_valley/data/villagers_data.py | 31 +-- worlds/stardew_valley/items.py | 12 +- worlds/stardew_valley/locations.py | 17 +- worlds/stardew_valley/logic/logic.py | 33 +-- .../logic/relationship_logic.py | 6 +- worlds/stardew_valley/mods/logic/mod_logic.py | 5 +- .../mods/logic/special_orders_logic.py | 14 +- worlds/stardew_valley/mods/mod_regions.py | 5 + worlds/stardew_valley/rules.py | 4 +- worlds/stardew_valley/strings/fish_names.py | 28 ++- .../strings/monster_drop_names.py | 4 + .../stardew_valley/test/mods/TestModFish.py | 226 ++++++++++++++++++ .../test/mods/TestModVillagers.py | 19 +- 19 files changed, 399 insertions(+), 138 deletions(-) create mode 100644 worlds/stardew_valley/test/mods/TestModFish.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 8fd2a29b3f3f..a16a6eb2a2af 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -188,7 +188,7 @@ def setup_construction_events(self): def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], - self.bundle.can_complete_community_center().simplify(), + self.logic.bundle.can_complete_community_center().simplify(), Event.victory) elif self.options.goal == Goal.option_grandpa_evaluation: self.create_event_location(location_table[GoalName.grandpa_evaluation], diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 4ac8c614b72f..386625ae019d 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -129,7 +129,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) basic_fertilizer = skill_recipe(Fertilizer.basic, Skill.farming, 1, {Material.sap: 2}) quality_fertilizer = skill_recipe(Fertilizer.quality, Skill.farming, 9, {Material.sap: 2, Fish.any: 1}) deluxe_fertilizer = ap_recipe(Fertilizer.deluxe, {MetalBar.iridium: 1, Material.sap: 40}) -basic_speed_gro = skill_recipe(SpeedGro.basic, Skill.farming, 3, {ArtisanGood.pine_tar: 1, WaterItem.clam: 1}) +basic_speed_gro = skill_recipe(SpeedGro.basic, Skill.farming, 3, {ArtisanGood.pine_tar: 1, Fish.clam: 1}) deluxe_speed_gro = skill_recipe(SpeedGro.deluxe, Skill.farming, 8, {ArtisanGood.oak_resin: 1, WaterItem.coral: 1}) hyper_speed_gro = ap_recipe(SpeedGro.hyper, {Ore.radioactive: 1, Fossil.bone_fragment: 3, Loot.solar_essence: 1}) basic_retaining_soil = skill_recipe(RetainingSoil.basic, Skill.farming, 4, {Material.stone: 2}) diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 4119f965983d..7fcccbb0e40b 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Tuple, Union, Optional +from typing import List, Tuple, Union, Optional, Set from . import season_data as season from .game_item import GameItem @@ -129,33 +129,33 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un legend_ii = create_fish(Fish.legend_ii, 163, mountain_lake, season.spring, 110, True, True) radioactive_carp = create_fish(Fish.radioactive_carp, 682, sewers, season.all_seasons, 80, True, True) -baby_lunaloo = create_fish(SVEFish.baby_lunaloo, 3006, ginger_island_ocean, season.all_seasons, 15, ModNames.sve) -bonefish = create_fish(SVEFish.bonefish, 3013, crimson_badlands, season.all_seasons, 70, ModNames.sve) -bull_trout = create_fish(SVEFish.bull_trout, 3014, forest_river, season.not_spring, 45, ModNames.sve) -butterfish = create_fish(SVEFish.butterfish, 3015, shearwater, season.not_winter, 75, ModNames.sve) -clownfish = create_fish(SVEFish.clownfish, 3016, ginger_island_ocean, season.all_seasons, 45, ModNames.sve) -daggerfish = create_fish(SVEFish.daggerfish, 3017, highlands, season.all_seasons, 50, ModNames.sve) -frog = create_fish(SVEFish.frog, 3023, mountain_lake, (season.spring, season.summer), 70, ModNames.sve) -gemfish = create_fish(SVEFish.gemfish, 3027, highlands, season.all_seasons, 100, ModNames.sve) -goldenfish = create_fish(SVEFish.goldenfish, 3031, sprite_spring, season.all_seasons, 60, ModNames.sve) -grass_carp = create_fish(SVEFish.grass_carp, 3034, secret_woods, (season.spring, season.summer), 85, ModNames.sve) -king_salmon = create_fish(SVEFish.king_salmon, 3044, forest_river, (season.spring, season.summer), 80, ModNames.sve) -kittyfish = create_fish(SVEFish.kittyfish, 3045, shearwater, (season.fall, season.winter), 85, ModNames.sve) -lunaloo = create_fish(SVEFish.lunaloo, 3049, ginger_island_ocean, season.all_seasons, 70, ModNames.sve) -meteor_carp = create_fish(SVEFish.meteor_carp, 3051, sprite_spring, season.all_seasons, 80, ModNames.sve) -minnow = create_fish(SVEFish.minnow, 3052, town_river, season.all_seasons, 1, ModNames.sve) -puppyfish = create_fish(SVEFish.puppyfish, 3061, shearwater, season.not_winter, 85, ModNames.sve) -radioactive_bass = create_fish(SVEFish.radioactive_bass, 3062, sewers, season.all_seasons, 90, ModNames.sve) -seahorse = create_fish(SVEFish.seahorse, 3068, ginger_island_ocean, season.all_seasons, 25, ModNames.sve) -shiny_lunaloo = create_fish(SVEFish.shiny_lunaloo, 3070, ginger_island_ocean, season.all_seasons, 110, ModNames.sve) -snatcher_worm = create_fish(SVEFish.snatcher_worm, 3075, mutant_bug_lair, season.all_seasons, 75, ModNames.sve) -starfish = create_fish(SVEFish.starfish, 3079, ginger_island_ocean, season.all_seasons, 75, ModNames.sve) -torpedo_trout = create_fish(SVEFish.torpedo_trout, 3084, fable_reef, season.all_seasons, 70, ModNames.sve) -undeadfish = create_fish(SVEFish.undeadfish, 3085, crimson_badlands, season.all_seasons, 80, ModNames.sve) -void_eel = create_fish(SVEFish.void_eel, 3087, witch_swamp, season.all_seasons, 100, ModNames.sve) -water_grub = create_fish(SVEFish.water_grub, 3094, mutant_bug_lair, season.all_seasons, 60, ModNames.sve) -sea_sponge = create_fish(SVEFish.sea_sponge, 3067, ginger_island_ocean, season.all_seasons, 40, ModNames.sve) -dulse_seaweed = create_fish(SVEFish.dulse_seaweed, 3020, vineyard, season.all_seasons, 50, ModNames.sve) +baby_lunaloo = create_fish(SVEFish.baby_lunaloo, 3006, ginger_island_ocean, season.all_seasons, 15, mod_name=ModNames.sve) +bonefish = create_fish(SVEFish.bonefish, 3013, crimson_badlands, season.all_seasons, 70, mod_name=ModNames.sve) +bull_trout = create_fish(SVEFish.bull_trout, 3014, forest_river, season.not_spring, 45, mod_name=ModNames.sve) +butterfish = create_fish(SVEFish.butterfish, 3015, shearwater, season.not_winter, 75, mod_name=ModNames.sve) +clownfish = create_fish(SVEFish.clownfish, 3016, ginger_island_ocean, season.all_seasons, 45, mod_name=ModNames.sve) +daggerfish = create_fish(SVEFish.daggerfish, 3017, highlands, season.all_seasons, 50, mod_name=ModNames.sve) +frog = create_fish(SVEFish.frog, 3023, mountain_lake, (season.spring, season.summer), 70, mod_name=ModNames.sve) +gemfish = create_fish(SVEFish.gemfish, 3027, highlands, season.all_seasons, 100, mod_name=ModNames.sve) +goldenfish = create_fish(SVEFish.goldenfish, 3031, sprite_spring, season.all_seasons, 60, mod_name=ModNames.sve) +grass_carp = create_fish(SVEFish.grass_carp, 3034, secret_woods, (season.spring, season.summer), 85, mod_name=ModNames.sve) +king_salmon = create_fish(SVEFish.king_salmon, 3044, forest_river, (season.spring, season.summer), 80, mod_name=ModNames.sve) +kittyfish = create_fish(SVEFish.kittyfish, 3045, shearwater, (season.fall, season.winter), 85, mod_name=ModNames.sve) +lunaloo = create_fish(SVEFish.lunaloo, 3049, ginger_island_ocean, season.all_seasons, 70, mod_name=ModNames.sve) +meteor_carp = create_fish(SVEFish.meteor_carp, 3051, sprite_spring, season.all_seasons, 80, mod_name=ModNames.sve) +minnow = create_fish(SVEFish.minnow, 3052, town_river, season.all_seasons, 1, mod_name=ModNames.sve) +puppyfish = create_fish(SVEFish.puppyfish, 3061, shearwater, season.not_winter, 85, mod_name=ModNames.sve) +radioactive_bass = create_fish(SVEFish.radioactive_bass, 3062, sewers, season.all_seasons, 90, mod_name=ModNames.sve) +seahorse = create_fish(SVEFish.seahorse, 3068, ginger_island_ocean, season.all_seasons, 25, mod_name=ModNames.sve) +shiny_lunaloo = create_fish(SVEFish.shiny_lunaloo, 3070, ginger_island_ocean, season.all_seasons, 110, mod_name=ModNames.sve) +snatcher_worm = create_fish(SVEFish.snatcher_worm, 3075, mutant_bug_lair, season.all_seasons, 75, mod_name=ModNames.sve) +starfish = create_fish(SVEFish.starfish, 3079, ginger_island_ocean, season.all_seasons, 75, mod_name=ModNames.sve) +torpedo_trout = create_fish(SVEFish.torpedo_trout, 3084, fable_reef, season.all_seasons, 70, mod_name=ModNames.sve) +undeadfish = create_fish(SVEFish.undeadfish, 3085, crimson_badlands, season.all_seasons, 80, mod_name=ModNames.sve) +void_eel = create_fish(SVEFish.void_eel, 3087, witch_swamp, season.all_seasons, 100, mod_name=ModNames.sve) +water_grub = create_fish(SVEFish.water_grub, 3094, mutant_bug_lair, season.all_seasons, 60, mod_name=ModNames.sve) +sea_sponge = create_fish(SVEFish.sea_sponge, 3067, ginger_island_ocean, season.all_seasons, 40, mod_name=ModNames.sve) +dulse_seaweed = create_fish(SVEFish.dulse_seaweed, 3020, vineyard, season.all_seasons, 50, mod_name=ModNames.sve) clam = create_fish("Clam", 372, ocean, season.all_seasons, -1) @@ -175,3 +175,12 @@ def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Un island_fish = [lionfish, blue_discus, stingray, *extended_family] all_fish_by_name = {fish.name: fish for fish in all_fish} + + +def get_fish_for_mods(mods: Set[str]) -> List[FishItem]: + fish_for_mods = [] + for fish in all_fish: + if fish.mod_name and fish.mod_name not in mods: + continue + fish_for_mods.append(fish) + return fish_for_mods diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 68eda290a5ae..32f15b7b9dbc 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -79,7 +79,7 @@ id,name,classification,groups,mod_name 93,Shipping Bin,progression,BUILDING, 94,Beach Bridge,progression,, 95,Adventurer's Guild,progression,, -96,Club Card,useful,, +96,Club Card,progression,, 97,Magnifying Glass,progression,, 98,Bear's Knowledge,useful,, 99,Iridium Snake Milk,useful,, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3338452b6649..403a7e959712 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2267,20 +2267,20 @@ id,region,name,tags,mod_name 6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded 6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded 6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6167,Jenkins Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6168,Jenkins Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6169,Jenkins Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6170,Jenkins Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6171,Jenkins Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6172,Jenkins Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6173,Jenkins Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6174,Jenkins Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6175,Jenkins Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6176,Jenkins Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6177,Jenkins Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6178,Jenkins Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6179,Jenkins Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6180,Jenkins Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded 6181,Forest,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded 6182,Forest,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded 6183,Forest,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2299,20 +2299,20 @@ id,region,name,tags,mod_name 6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded 6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded 6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6199,Jenkins Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded -6200,Jenkins Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded -6201,Jenkins Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded -6202,Jenkins Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded -6203,Jenkins Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded -6204,Jenkins Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded -6205,Jenkins Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded -6206,Jenkins Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded -6207,Jenkins Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded -6208,Jenkins Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded -6209,Jenkins Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded -6210,Jenkins Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded -6211,Jenkins Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded -6212,Jenkins Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded +6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded +6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded +6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded +6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded +6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded +6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded +6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded +6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded +6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded +6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded +6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded +6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded +6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded +6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded 6213,Forest,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded 6214,Forest,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded 6215,Forest,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2441,7 +2441,7 @@ id,region,name,tags,mod_name 7509,Farm,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded 7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded 7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewers,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded +7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded 7601,Bear Shop,Bear: Baked Berry Oatmeal Recipe,MANDATORY,Stardew Valley Expanded 7602,Bear Shop,Bear: Flower Cookie Recipe,MANDATORY,Stardew Valley Expanded 7603,Purple Junimo Shop,Purple Junimo: Super Starfruit,MANDATORY,Stardew Valley Expanded @@ -2464,7 +2464,7 @@ id,region,name,tags,mod_name 8005,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded 8006,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded 8007,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded -8008,Sewers,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +8008,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded 8009,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 8010,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 8011,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 80125b85511b..7dc6e79809d5 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -87,7 +87,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) cheese_cauliflower = friendship_recipe(Meal.cheese_cauliflower, NPC.pam, 3, {Vegetable.cauliflower: 1, ArtisanGood.cheese: 1}) chocolate_cake_ingredients = {Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.chicken_egg: 1} chocolate_cake_qos = queen_of_sauce_recipe(Meal.chocolate_cake, 1, Season.winter, 14, chocolate_cake_ingredients) -chowder = friendship_recipe(Meal.chowder, NPC.willy, 3, {WaterItem.clam: 1, AnimalProduct.cow_milk: 1}) +chowder = friendship_recipe(Meal.chowder, NPC.willy, 3, {Fish.clam: 1, AnimalProduct.cow_milk: 1}) coleslaw = queen_of_sauce_recipe(Meal.coleslaw, 14, Season.spring, 14, {Vegetable.red_cabbage: 1, Ingredient.vinegar: 1, ArtisanGood.mayonnaise: 1}) complete_breakfast_ingredients = {Meal.fried_egg: 1, AnimalProduct.milk: 1, Meal.hashbrowns: 1, Meal.pancakes: 1} complete_breakfast = queen_of_sauce_recipe(Meal.complete_breakfast, 2, Season.spring, 21, complete_breakfast_ingredients) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 03893a0ede09..7d2299be281b 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -16,14 +16,14 @@ class Villager: birthday: str gifts: Tuple[str] available: bool - mod_names: List[str] + mod_name: str def __repr__(self): return f"{self.name} [Bachelor: {self.bachelor}] [Available from start: {self.available}]" \ f"(Locations: {self.locations} |" \ f" Birthday: {self.birthday} |" \ f" Gifts: {self.gifts}) |" \ - f" Mod: {self.mod_names}" + f" Mod: {self.mod_name}" town = (Region.town,) @@ -353,13 +353,15 @@ def __repr__(self): def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: str, gifts: Tuple[str, ...], available: bool, mod_name: Optional[str] = None) -> Villager: - npc = Villager(name, bachelor, locations, birthday, gifts, available, [mod_name] if mod_name is not None else []) + npc = Villager(name, bachelor, locations, birthday, gifts, available, mod_name) all_villagers.append(npc) return npc def make_bachelor(mod_name: str, npc: Villager): - return Villager(npc.name, True, npc.locations, npc.birthday, npc.gifts, npc.available, [*npc.mod_names, mod_name]) + if npc.mod_name: + mod_name = npc.mod_name + return Villager(npc.name, True, npc.locations, npc.birthday, npc.gifts, npc.available, mod_name) def register_villager_modification(mod_name: str, npc: Villager, modification_function): @@ -441,22 +443,21 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu all_villagers_by_mod_by_name: Dict[str, Dict[str, Villager]] = {} for npc in all_villagers: - mods = npc.mod_names + mod = npc.mod_name name = npc.name - for mod in mods: - if mod in all_villagers_by_mod: - all_villagers_by_mod[mod].append(npc) - all_villagers_by_mod_by_name[mod][name] = npc - else: - all_villagers_by_mod[mod] = [npc] - all_villagers_by_mod_by_name[mod] = {} - all_villagers_by_mod_by_name[mod][name] = npc + if mod in all_villagers_by_mod: + all_villagers_by_mod[mod].append(npc) + all_villagers_by_mod_by_name[mod][name] = npc + else: + all_villagers_by_mod[mod] = [npc] + all_villagers_by_mod_by_name[mod] = {} + all_villagers_by_mod_by_name[mod][name] = npc -def all_villagers_for_current_mods(mods: Set[str]) -> List[Villager]: +def get_villagers_for_mods(mods: Set[str]) -> List[Villager]: villagers_for_current_mods = [] for npc in all_villagers: - if npc.mod_names and not all([mod in mods for mod in npc.mod_names]): + if npc.mod_name and npc.mod_name not in mods: continue modified_npc = npc for active_mod in mods: diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index e77188720fec..540a0225b8c1 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -8,7 +8,7 @@ from BaseClasses import Item, ItemClassification from . import data -from .data.villagers_data import all_villagers_for_current_mods +from .data.villagers_data import get_villagers_for_mods from .mods.mod_data import ModNames from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, \ Friendsanity, Museumsanity, \ @@ -194,9 +194,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items.append(item_factory("Beach Bridge")) items.append(item_factory("Dark Talisman")) create_tv_channels(item_factory, items) - create_special_quest_rewards(item_factory, items) - if ModNames.sve in options.mods: - create_special_quest_rewards_sve(item_factory, items) + create_special_quest_rewards(item_factory, options, items) create_stardrops(item_factory, options, items) create_museum_items(item_factory, options, items) create_arcade_machine_items(item_factory, options, items) @@ -322,13 +320,15 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, options: Starde items.append(item_factory("Tractor Garage")) -def create_special_quest_rewards(item_factory: StardewItemFactory, items: List[Item]): +def create_special_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): items.append(item_factory("Adventurer's Guild")) items.append(item_factory("Club Card")) items.append(item_factory("Magnifying Glass")) items.append(item_factory("Bear's Knowledge")) items.append(item_factory("Iridium Snake Milk")) items.append(item_factory("Fairy Dust Recipe")) + if ModNames.sve in options.mods: + create_special_quest_rewards_sve(item_factory, options, items) def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -364,7 +364,7 @@ def create_friendsanity_items(item_factory: StardewItemFactory, options: Stardew exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true mods = options.mods heart_size = options.friendsanity_heart_size - for villager in all_villagers_for_current_mods(mods.value): + for villager in get_villagers_for_mods(mods.value): if not villager.available and exclude_locked_villagers: continue if not villager.bachelor and exclude_non_bachelors: diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 5f65b1da8136..3a43344b9377 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -6,9 +6,9 @@ from . import data from .options import StardewValleyOptions, Craftsanity, Chefsanity, Cooksanity, Shipsanity, Monstersanity -from .data.fish_data import legendary_fish, special_fish, all_fish +from .data.fish_data import legendary_fish, special_fish, get_fish_for_mods from .data.museum_data import all_museum_items -from .data.villagers_data import all_villagers_for_current_mods +from .data.villagers_data import get_villagers_for_mods from .options import ExcludeGingerIsland, Friendsanity, ArcadeMachineLocations, SpecialOrderLocations, Cropsanity, Fishsanity, Museumsanity, FestivalLocations, SkillProgression, BuildingProgression, ToolProgression, ElevatorProgression, BackpackProgression from .strings.goal_names import Goal from .strings.villager_names import NPC, ModNPC @@ -186,6 +186,7 @@ def extend_help_wanted_quests(randomized_locations: List[LocationData], desired_ def extend_fishsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, random: Random): prefix = "Fishsanity: " fishsanity = options.fishsanity + active_fish = get_fish_for_mods(options.mods.value) if fishsanity == Fishsanity.option_none: return elif fishsanity == Fishsanity.option_legendaries: @@ -193,19 +194,19 @@ def extend_fishsanity_locations(randomized_locations: List[LocationData], option elif fishsanity == Fishsanity.option_special: randomized_locations.extend(location_table[f"{prefix}{special.name}"] for special in special_fish) elif fishsanity == Fishsanity.option_randomized: - fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if random.random() < 0.4] + fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in active_fish if random.random() < 0.4] randomized_locations.extend(filter_disabled_locations(options, fish_locations)) elif fishsanity == Fishsanity.option_all: - fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish] + fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in active_fish] randomized_locations.extend(filter_disabled_locations(options, fish_locations)) elif fishsanity == Fishsanity.option_exclude_legendaries: - fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish not in legendary_fish] + fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in active_fish if fish not in legendary_fish] randomized_locations.extend(filter_disabled_locations(options, fish_locations)) elif fishsanity == Fishsanity.option_exclude_hard_fish: - fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish.difficulty < 80] + fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in active_fish if fish.difficulty < 80] randomized_locations.extend(filter_disabled_locations(options, fish_locations)) elif options.fishsanity == Fishsanity.option_only_easy_fish: - fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in all_fish if fish.difficulty < 50] + fish_locations = [location_table[f"{prefix}{fish.name}"] for fish in active_fish if fish.difficulty < 50] randomized_locations.extend(filter_disabled_locations(options, fish_locations)) @@ -233,7 +234,7 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti options.friendsanity == Friendsanity.option_bachelors include_post_marriage_hearts = options.friendsanity == Friendsanity.option_all_with_marriage heart_size = options.friendsanity_heart_size - for villager in all_villagers_for_current_mods(options.mods.value): + for villager in get_villagers_for_mods(options.mods.value): if not villager.available and exclude_locked_villagers: continue if not villager.bachelor and exclude_non_bachelors: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 52e71047e1c9..b899ebf9fbc7 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import field, dataclass -from typing import Dict, List, Set +from typing import Dict, Set from .ability_logic import AbilityLogic from .action_logic import ActionLogic @@ -38,7 +38,7 @@ from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..mods.logic.mod_logic import ModLogic from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops -from ..data.fish_data import island_fish, legendary_fish, extended_family +from ..data.fish_data import island_fish, legendary_fish, extended_family, get_fish_for_mods from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions @@ -99,7 +99,6 @@ class StardewLogic: crop_rules: Dict[str, StardewRule] = field(default_factory=dict) fish_rules: Dict[str, StardewRule] = field(default_factory=dict) museum_rules: Dict[str, StardewRule] = field(default_factory=dict) - quest_rules: Dict[str, StardewRule] = field(default_factory=dict) festival_rules: Dict[str, StardewRule] = field(default_factory=dict) def __post_init__(self): @@ -147,7 +146,7 @@ def __post_init__(self): self.crafting = CraftingLogic(self.player, self.options.craftsanity, self.options.festival_locations, self.options.special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.season, self.money, + self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) @@ -425,8 +424,8 @@ def __post_init__(self): TreeSeed.mushroom: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 5), TreeSeed.pine: self.skill.has_level(Skill.foraging, 1) & self.ability.can_chop_trees(), Vegetable.tea_leaves: self.has(Sapling.tea) & self.time.has_lived_months(2) & self.season.has_any_not_winter(), - WaterItem.clam: self.tool.can_forage(Generic.any, Region.beach), - WaterItem.cockle: self.tool.can_forage(Generic.any, Region.beach), + Fish.clam: self.tool.can_forage(Generic.any, Region.beach), + Fish.cockle: self.tool.can_forage(Generic.any, Region.beach), WaterItem.coral: self.tool.can_forage(Generic.any, Region.tide_pools) | self.tool.can_forage(Season.summer, Region.beach), WaterItem.green_algae: self.fishing.can_fish_in_freshwater(), WaterItem.nautilus_shell: self.tool.can_forage(Season.winter, Region.beach), @@ -500,9 +499,6 @@ def __post_init__(self): self.special_order.initialize_rules() self.special_order.update_rules(self.mod.special_orders.get_modded_special_orders_rules(self.special_order.special_order_rules)) - def can_complete_quest(self, quest: str) -> StardewRule: - return Has(quest, self.quest_rules) - def can_buy_seed(self, seed: SeedItem) -> StardewRule: if self.options.cropsanity == Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() @@ -556,7 +552,7 @@ def can_catch_every_fish(self) -> StardewRule: rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true exclude_extended_family = self.options.special_order_locations != SpecialOrderLocations.option_board_qi - for fish in all_fish: + for fish in get_fish_for_mods(self.options.mods.value): if exclude_island and fish in island_fish: continue if exclude_extended_family and fish in extended_family: @@ -612,9 +608,9 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: self.relationship.has_hearts("5", 8), # 5 Friends self.relationship.has_hearts("10", 8), # 10 friends self.pet.has_hearts(5), # Max Pet - self.can_complete_community_center(), # Community Center Completion - self.can_complete_community_center(), # CC Ceremony first point - self.can_complete_community_center(), # CC Ceremony second point + self.bundle.can_complete_community_center(), # Community Center Completion + self.bundle.can_complete_community_center(), # CC Ceremony first point + self.bundle.can_complete_community_center(), # CC Ceremony second point self.received(Wallet.skull_key), # Skull Key obtained self.wallet.has_rusty_key(), # Rusty key obtained ] @@ -795,14 +791,5 @@ def has_movie_theater(self) -> StardewRule: return self.received(CommunityUpgrade.movie_theater, 2) def can_use_obelisk(self, obelisk: str) -> StardewRule: - return self.region.can_reach(Region.wizard_tower) & self.region.can_reach(Region.farm) & self.received(obelisk) - - def has_abandoned_jojamart(self) -> StardewRule: - return self.received(CommunityUpgrade.movie_theater, 1) - - def has_movie_theater(self) -> StardewRule: - return self.received(CommunityUpgrade.movie_theater, 2) - - def can_use_obelisk(self, obelisk: str) -> StardewRule: - return self.region.can_reach(Region.wizard_tower) & self.region.can_reach(Region.farm) & self.received(obelisk) + return self.region.can_reach(Region.wizard_tower) & self.received(obelisk) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 242e22e41bf3..53010b6e5127 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -10,7 +10,7 @@ from .season_logic import SeasonLogic from .time_logic import TimeLogic from .. import options -from ..data.villagers_data import all_villagers_by_name, all_villagers_for_current_mods, Villager +from ..data.villagers_data import all_villagers_by_name, get_villagers_for_mods, Villager from ..options import Friendsanity, FriendsanityHeartSize, Mods from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic @@ -168,8 +168,8 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] - mod = npc.mod_names - return not mod or npc in all_villagers_for_current_mods(self.mods_option.value) + mod = npc.mod_name + return not mod or npc in get_villagers_for_mods(self.mods_option.value) def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 7989807e2363..4713aac978ae 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -10,6 +10,7 @@ from .sve_logic import SVELogic from ...logic.ability_logic import AbilityLogic from ...logic.action_logic import ActionLogic +from ...logic.artisan_logic import ArtisanLogic from ...logic.building_logic import BuildingLogic from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic @@ -43,13 +44,13 @@ class ModLogic: sve: SVELogic def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, - action: ActionLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, + action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, has, region, season, relationship, received, time) self.buildings = ModBuildingLogic(player, has, money, mods) - self.special_orders = ModSpecialOrderLogic(player, action, crafting, crop, has, region, relationship, season, wallet, mods) + self.special_orders = ModSpecialOrderLogic(player, action, artisan, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) self.skill = ModSkillLogic(player, skill_option, received, has, region, action, relationship, building, tool, fishing, cooking, self.magic, mods) diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index 44289a6c813c..121bff87a777 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -1,6 +1,7 @@ from typing import Iterable from ...logic.action_logic import ActionLogic +from ...logic.artisan_logic import ArtisanLogic from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogic @@ -28,6 +29,8 @@ class ModSpecialOrderLogic: player: int + action: ActionLogic + artisan: ArtisanLogic crafting: CraftingLogic crop: CropLogic has: HasLogic @@ -37,10 +40,11 @@ class ModSpecialOrderLogic: wallet: WalletLogic mods_option: Mods - def __init__(self, player: int, action: ActionLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, + def __init__(self, player: int, action: ActionLogic, artisan: ArtisanLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): self.player = player self.action = action + self.artisan = artisan self.crafting = crafting self.crop = crop self.has = has @@ -67,12 +71,12 @@ def get_modded_special_orders_rules(self, vanilla_rules): self.region.can_reach(SVERegion.fairhaven_farm), ModSpecialOrder.a_mysterious_venture: self.has(Bomb.cherry_bomb) & self.has(Bomb.bomb) & self.has(Bomb.mega_bomb) & self.region.can_reach(Region.adventurer_guild), - ModSpecialOrder.an_elegant_reception: self.crop.can_grow(Fruit.starfruit) & self.has(Machine.keg) & self.has(ArtisanGood.cheese) & + ModSpecialOrder.an_elegant_reception: self.artisan.can_keg(Fruit.starfruit) & self.has(ArtisanGood.cheese) & self.has(ArtisanGood.goat_cheese) & self.season.has_any_not_winter() & self.region.can_reach(SVERegion.jenkins_cellar), - ModSpecialOrder.fairy_garden: self.crop.can_grow(Flower.fairy_rose) & self.crafting.can_craft(Consumable.fairy_dust) & - self.region.can_reach(Region.island_south) & [self.action.can_open_geode(Geode.frozen) | self.action.can_open_geode(Geode.omni)] & + ModSpecialOrder.fairy_garden: self.has(Consumable.fairy_dust) & + self.region.can_reach(Region.island_south) & (self.action.can_open_geode(Geode.frozen) | self.action.can_open_geode(Geode.omni)) & self.region.can_reach(SVERegion.blue_moon_vineyard), - ModSpecialOrder.homemade_fertilizer: self.crafting.can_craft(Fertilizer.quality) & self.region.can_reach(SVERegion.susans_house) + ModSpecialOrder.homemade_fertilizer: self.has(Fertilizer.quality) & self.region.can_reach(SVERegion.susans_house) }) return special_orders diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index baa73b2f1811..83cfe53eebfc 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -215,9 +215,14 @@ ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), ConnectionData(SVEEntrance.grove_to_spring, SVERegion.sprite_spring), ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef), + ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild), + ConnectionData(SVEEntrance.to_outpost_roof, SVERegion.outpost_roof), ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance), ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands), + ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave), ConnectionData(SVEEntrance.guild_to_mines, Region.mines), + ConnectionData(SVEEntrance.mountain_to_guild_summit, SVERegion.guild_summit), + ConnectionData(SVEEntrance.summit_to_boat, SVERegion.marlon_boat), ConnectionData(SVEEntrance.forest_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.secret_woods_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 2cc7f82de3c7..47fca2a545bb 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -133,7 +133,7 @@ def set_building_rules(logic: StardewLogic, multiworld, player, world_options: S def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): for bundle in current_bundles.values(): location = multiworld.get_location(bundle.get_name_with_bundle(), player) - rules = logic.can_complete_bundle(bundle.requirements, bundle.number_required) + rules = logic.bundle.can_complete_bundle(bundle.requirements, bundle.number_required) simplified_rules = rules.simplify() MultiWorldRules.set_rule(location, simplified_rules) MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), @@ -469,7 +469,7 @@ def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, m for quest in locations.locations_by_tag[LocationTags.QUEST]: if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options.mods): MultiWorldRules.set_rule(multiworld.get_location(quest.name, player), - logic.quest_rules[quest.name].simplify()) + logic.quest.quest_rules[quest.name].simplify()) def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 3633ecd96a7a..58b771dc87e4 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -1,4 +1,28 @@ class Fish: + spook_fish = "Spook Fish" + midnight_squid = "Midnight Squid" + blob_fish = "Blobfish" + woodskip = "Woodskip" + walleye = "Walleye" + tilapia = "Tilapia" + tiger_trout = "Tiger Trout" + super_cucumber = "Super Cucumber" + stonefish = "Stonefish" + slimejack = "Slimejack" + shad = "Shad" + scorpion_carp = "Scorpion Carp" + sandfish = "Sandfish" + red_snapper = "Red Snapper" + red_mullet = "Red Mullet" + pike = "Pike" + perch = "Perch" + ice_pip = "Ice Pip" + herring = "Herring" + halibut = "Halibut" + ghostfish = "Ghostfish" + chub = "Chub" + bullhead = "Bullhead" + anchovy = "Anchovy" albacore = "Albacore" angler = "Angler" any = "Any Fish" @@ -7,6 +31,8 @@ class Fish: bream = "Bream" carp = "Carp" catfish = "Catfish" + clam = "Clam" + cockle = "Cockle" crab = "Crab" crayfish = "Crayfish" crimsonfish = "Crimsonfish" @@ -53,8 +79,6 @@ class WaterItem: seaweed = "Seaweed" green_algae = "Green Algae" white_algae = "White Algae" - clam = "Clam" - cockle = "Cockle" coral = "Coral" nautilus_shell = "Nautilus Shell" sea_urchin = "Sea Urchin" diff --git a/worlds/stardew_valley/strings/monster_drop_names.py b/worlds/stardew_valley/strings/monster_drop_names.py index 84c0f0d30277..9f370829afbe 100644 --- a/worlds/stardew_valley/strings/monster_drop_names.py +++ b/worlds/stardew_valley/strings/monster_drop_names.py @@ -7,6 +7,10 @@ class Loot: class ModLoot: + void_root = "Void Root" + monster_fruit = "Monster Fruit" + slime_berry = "Slime Berry" + monster_mushroom = "Monster Mushroom" stalk_seed = "Stalk Seed" fungus_seed = "Fungus Seed" slime_seed = "Slime Seed" diff --git a/worlds/stardew_valley/test/mods/TestModFish.py b/worlds/stardew_valley/test/mods/TestModFish.py new file mode 100644 index 000000000000..81ac6ac0fb99 --- /dev/null +++ b/worlds/stardew_valley/test/mods/TestModFish.py @@ -0,0 +1,226 @@ +import unittest +from typing import Set + +from ...data.fish_data import get_fish_for_mods +from ...mods.mod_data import ModNames +from ...strings.fish_names import Fish, SVEFish + +no_mods: Set[str] = set() +sve: Set[str] = {ModNames.sve} + + +class TestGetFishForMods(unittest.TestCase): + + def test_no_mods_all_vanilla_fish(self): + all_fish = get_fish_for_mods(no_mods) + fish_names = {fish.name for fish in all_fish} + + self.assertIn(Fish.albacore, fish_names) + self.assertIn(Fish.anchovy, fish_names) + self.assertIn(Fish.blue_discus, fish_names) + self.assertIn(Fish.bream, fish_names) + self.assertIn(Fish.bullhead, fish_names) + self.assertIn(Fish.carp, fish_names) + self.assertIn(Fish.catfish, fish_names) + self.assertIn(Fish.chub, fish_names) + self.assertIn(Fish.dorado, fish_names) + self.assertIn(Fish.eel, fish_names) + self.assertIn(Fish.flounder, fish_names) + self.assertIn(Fish.ghostfish, fish_names) + self.assertIn(Fish.halibut, fish_names) + self.assertIn(Fish.herring, fish_names) + self.assertIn(Fish.ice_pip, fish_names) + self.assertIn(Fish.largemouth_bass, fish_names) + self.assertIn(Fish.lava_eel, fish_names) + self.assertIn(Fish.lingcod, fish_names) + self.assertIn(Fish.lionfish, fish_names) + self.assertIn(Fish.midnight_carp, fish_names) + self.assertIn(Fish.octopus, fish_names) + self.assertIn(Fish.perch, fish_names) + self.assertIn(Fish.pike, fish_names) + self.assertIn(Fish.pufferfish, fish_names) + self.assertIn(Fish.rainbow_trout, fish_names) + self.assertIn(Fish.red_mullet, fish_names) + self.assertIn(Fish.red_snapper, fish_names) + self.assertIn(Fish.salmon, fish_names) + self.assertIn(Fish.sandfish, fish_names) + self.assertIn(Fish.sardine, fish_names) + self.assertIn(Fish.scorpion_carp, fish_names) + self.assertIn(Fish.sea_cucumber, fish_names) + self.assertIn(Fish.shad, fish_names) + self.assertIn(Fish.slimejack, fish_names) + self.assertIn(Fish.smallmouth_bass, fish_names) + self.assertIn(Fish.squid, fish_names) + self.assertIn(Fish.stingray, fish_names) + self.assertIn(Fish.stonefish, fish_names) + self.assertIn(Fish.sturgeon, fish_names) + self.assertIn(Fish.sunfish, fish_names) + self.assertIn(Fish.super_cucumber, fish_names) + self.assertIn(Fish.tiger_trout, fish_names) + self.assertIn(Fish.tilapia, fish_names) + self.assertIn(Fish.tuna, fish_names) + self.assertIn(Fish.void_salmon, fish_names) + self.assertIn(Fish.walleye, fish_names) + self.assertIn(Fish.woodskip, fish_names) + self.assertIn(Fish.blob_fish, fish_names) + self.assertIn(Fish.midnight_squid, fish_names) + self.assertIn(Fish.spook_fish, fish_names) + self.assertIn(Fish.angler, fish_names) + self.assertIn(Fish.crimsonfish, fish_names) + self.assertIn(Fish.glacierfish, fish_names) + self.assertIn(Fish.legend, fish_names) + self.assertIn(Fish.mutant_carp, fish_names) + self.assertIn(Fish.ms_angler, fish_names) + self.assertIn(Fish.son_of_crimsonfish, fish_names) + self.assertIn(Fish.glacierfish_jr, fish_names) + self.assertIn(Fish.legend_ii, fish_names) + self.assertIn(Fish.radioactive_carp, fish_names) + self.assertIn(Fish.clam, fish_names) + self.assertIn(Fish.cockle, fish_names) + self.assertIn(Fish.crab, fish_names) + self.assertIn(Fish.crayfish, fish_names) + self.assertIn(Fish.lobster, fish_names) + self.assertIn(Fish.mussel, fish_names) + self.assertIn(Fish.oyster, fish_names) + self.assertIn(Fish.periwinkle, fish_names) + self.assertIn(Fish.shrimp, fish_names) + self.assertIn(Fish.snail, fish_names) + + def test_no_mods_no_sve_fish(self): + all_fish = get_fish_for_mods(no_mods) + fish_names = {fish.name for fish in all_fish} + + self.assertNotIn(SVEFish.baby_lunaloo, fish_names) + self.assertNotIn(SVEFish.bonefish, fish_names) + self.assertNotIn(SVEFish.bull_trout, fish_names) + self.assertNotIn(SVEFish.butterfish, fish_names) + self.assertNotIn(SVEFish.clownfish, fish_names) + self.assertNotIn(SVEFish.daggerfish, fish_names) + self.assertNotIn(SVEFish.frog, fish_names) + self.assertNotIn(SVEFish.gemfish, fish_names) + self.assertNotIn(SVEFish.goldenfish, fish_names) + self.assertNotIn(SVEFish.grass_carp, fish_names) + self.assertNotIn(SVEFish.king_salmon, fish_names) + self.assertNotIn(SVEFish.kittyfish, fish_names) + self.assertNotIn(SVEFish.lunaloo, fish_names) + self.assertNotIn(SVEFish.meteor_carp, fish_names) + self.assertNotIn(SVEFish.minnow, fish_names) + self.assertNotIn(SVEFish.puppyfish, fish_names) + self.assertNotIn(SVEFish.radioactive_bass, fish_names) + self.assertNotIn(SVEFish.seahorse, fish_names) + self.assertNotIn(SVEFish.shiny_lunaloo, fish_names) + self.assertNotIn(SVEFish.snatcher_worm, fish_names) + self.assertNotIn(SVEFish.starfish, fish_names) + self.assertNotIn(SVEFish.torpedo_trout, fish_names) + self.assertNotIn(SVEFish.undeadfish, fish_names) + self.assertNotIn(SVEFish.void_eel, fish_names) + self.assertNotIn(SVEFish.water_grub, fish_names) + self.assertNotIn(SVEFish.sea_sponge, fish_names) + self.assertNotIn(SVEFish.dulse_seaweed, fish_names) + + def test_sve_all_vanilla_fish(self): + all_fish = get_fish_for_mods(no_mods) + fish_names = {fish.name for fish in all_fish} + + self.assertIn(Fish.albacore, fish_names) + self.assertIn(Fish.anchovy, fish_names) + self.assertIn(Fish.blue_discus, fish_names) + self.assertIn(Fish.bream, fish_names) + self.assertIn(Fish.bullhead, fish_names) + self.assertIn(Fish.carp, fish_names) + self.assertIn(Fish.catfish, fish_names) + self.assertIn(Fish.chub, fish_names) + self.assertIn(Fish.dorado, fish_names) + self.assertIn(Fish.eel, fish_names) + self.assertIn(Fish.flounder, fish_names) + self.assertIn(Fish.ghostfish, fish_names) + self.assertIn(Fish.halibut, fish_names) + self.assertIn(Fish.herring, fish_names) + self.assertIn(Fish.ice_pip, fish_names) + self.assertIn(Fish.largemouth_bass, fish_names) + self.assertIn(Fish.lava_eel, fish_names) + self.assertIn(Fish.lingcod, fish_names) + self.assertIn(Fish.lionfish, fish_names) + self.assertIn(Fish.midnight_carp, fish_names) + self.assertIn(Fish.octopus, fish_names) + self.assertIn(Fish.perch, fish_names) + self.assertIn(Fish.pike, fish_names) + self.assertIn(Fish.pufferfish, fish_names) + self.assertIn(Fish.rainbow_trout, fish_names) + self.assertIn(Fish.red_mullet, fish_names) + self.assertIn(Fish.red_snapper, fish_names) + self.assertIn(Fish.salmon, fish_names) + self.assertIn(Fish.sandfish, fish_names) + self.assertIn(Fish.sardine, fish_names) + self.assertIn(Fish.scorpion_carp, fish_names) + self.assertIn(Fish.sea_cucumber, fish_names) + self.assertIn(Fish.shad, fish_names) + self.assertIn(Fish.slimejack, fish_names) + self.assertIn(Fish.smallmouth_bass, fish_names) + self.assertIn(Fish.squid, fish_names) + self.assertIn(Fish.stingray, fish_names) + self.assertIn(Fish.stonefish, fish_names) + self.assertIn(Fish.sturgeon, fish_names) + self.assertIn(Fish.sunfish, fish_names) + self.assertIn(Fish.super_cucumber, fish_names) + self.assertIn(Fish.tiger_trout, fish_names) + self.assertIn(Fish.tilapia, fish_names) + self.assertIn(Fish.tuna, fish_names) + self.assertIn(Fish.void_salmon, fish_names) + self.assertIn(Fish.walleye, fish_names) + self.assertIn(Fish.woodskip, fish_names) + self.assertIn(Fish.blob_fish, fish_names) + self.assertIn(Fish.midnight_squid, fish_names) + self.assertIn(Fish.spook_fish, fish_names) + self.assertIn(Fish.angler, fish_names) + self.assertIn(Fish.crimsonfish, fish_names) + self.assertIn(Fish.glacierfish, fish_names) + self.assertIn(Fish.legend, fish_names) + self.assertIn(Fish.mutant_carp, fish_names) + self.assertIn(Fish.ms_angler, fish_names) + self.assertIn(Fish.son_of_crimsonfish, fish_names) + self.assertIn(Fish.glacierfish_jr, fish_names) + self.assertIn(Fish.legend_ii, fish_names) + self.assertIn(Fish.radioactive_carp, fish_names) + self.assertIn(Fish.clam, fish_names) + self.assertIn(Fish.cockle, fish_names) + self.assertIn(Fish.crab, fish_names) + self.assertIn(Fish.crayfish, fish_names) + self.assertIn(Fish.lobster, fish_names) + self.assertIn(Fish.mussel, fish_names) + self.assertIn(Fish.oyster, fish_names) + self.assertIn(Fish.periwinkle, fish_names) + self.assertIn(Fish.shrimp, fish_names) + self.assertIn(Fish.snail, fish_names) + + def test_sve_has_sve_fish(self): + all_fish = get_fish_for_mods(sve) + fish_names = {fish.name for fish in all_fish} + + self.assertIn(SVEFish.baby_lunaloo, fish_names) + self.assertIn(SVEFish.bonefish, fish_names) + self.assertIn(SVEFish.bull_trout, fish_names) + self.assertIn(SVEFish.butterfish, fish_names) + self.assertIn(SVEFish.clownfish, fish_names) + self.assertIn(SVEFish.daggerfish, fish_names) + self.assertIn(SVEFish.frog, fish_names) + self.assertIn(SVEFish.gemfish, fish_names) + self.assertIn(SVEFish.goldenfish, fish_names) + self.assertIn(SVEFish.grass_carp, fish_names) + self.assertIn(SVEFish.king_salmon, fish_names) + self.assertIn(SVEFish.kittyfish, fish_names) + self.assertIn(SVEFish.lunaloo, fish_names) + self.assertIn(SVEFish.meteor_carp, fish_names) + self.assertIn(SVEFish.minnow, fish_names) + self.assertIn(SVEFish.puppyfish, fish_names) + self.assertIn(SVEFish.radioactive_bass, fish_names) + self.assertIn(SVEFish.seahorse, fish_names) + self.assertIn(SVEFish.shiny_lunaloo, fish_names) + self.assertIn(SVEFish.snatcher_worm, fish_names) + self.assertIn(SVEFish.starfish, fish_names) + self.assertIn(SVEFish.torpedo_trout, fish_names) + self.assertIn(SVEFish.undeadfish, fish_names) + self.assertIn(SVEFish.void_eel, fish_names) + self.assertIn(SVEFish.water_grub, fish_names) + self.assertIn(SVEFish.sea_sponge, fish_names) + self.assertIn(SVEFish.dulse_seaweed, fish_names) diff --git a/worlds/stardew_valley/test/mods/TestModVillagers.py b/worlds/stardew_valley/test/mods/TestModVillagers.py index bc38ccc70f0b..85fe6d5ce3a3 100644 --- a/worlds/stardew_valley/test/mods/TestModVillagers.py +++ b/worlds/stardew_valley/test/mods/TestModVillagers.py @@ -1,7 +1,7 @@ import unittest from typing import Set -from ...data.villagers_data import all_villagers_for_current_mods +from ...data.villagers_data import get_villagers_for_mods from ...mods.mod_data import ModNames from ...strings.villager_names import NPC, ModNPC @@ -12,7 +12,7 @@ class TestGetVillagersForMods(unittest.TestCase): def test_no_mods_all_vanilla_villagers(self): - villagers = all_villagers_for_current_mods(no_mods) + villagers = get_villagers_for_mods(no_mods) villager_names = {villager.name for villager in villagers} self.assertIn(NPC.alex, villager_names) @@ -51,7 +51,7 @@ def test_no_mods_all_vanilla_villagers(self): self.assertIn(NPC.wizard, villager_names) def test_no_mods_no_mod_villagers(self): - villagers = all_villagers_for_current_mods(no_mods) + villagers = get_villagers_for_mods(no_mods) villager_names = {villager.name for villager in villagers} self.assertNotIn(ModNPC.alec, villager_names) @@ -81,7 +81,7 @@ def test_no_mods_no_mod_villagers(self): self.assertNotIn(ModNPC.susan, villager_names) def test_sve_has_sve_villagers(self): - villagers = all_villagers_for_current_mods(sve) + villagers = get_villagers_for_mods(sve) villager_names = {villager.name for villager in villagers} self.assertIn(ModNPC.lance, villager_names) @@ -100,7 +100,7 @@ def test_sve_has_sve_villagers(self): self.assertIn(ModNPC.susan, villager_names) def test_sve_has_no_other_mod_villagers(self): - villagers = all_villagers_for_current_mods(sve) + villagers = get_villagers_for_mods(sve) villager_names = {villager.name for villager in villagers} self.assertNotIn(ModNPC.alec, villager_names) @@ -116,14 +116,13 @@ def test_sve_has_no_other_mod_villagers(self): self.assertNotIn(ModNPC.yoba, villager_names) def test_no_mods_wizard_is_not_bachelor(self): - villagers = all_villagers_for_current_mods(no_mods) + villagers = get_villagers_for_mods(no_mods) villagers_by_name = {villager.name: villager for villager in villagers} self.assertFalse(villagers_by_name[NPC.wizard].bachelor) - self.assertEqual(len(villagers_by_name[NPC.wizard].mod_names), 0) + self.assertEqual(villagers_by_name[NPC.wizard].mod_name, ModNames.vanilla) def test_sve_wizard_is_bachelor(self): - villagers = all_villagers_for_current_mods(sve) + villagers = get_villagers_for_mods(sve) villagers_by_name = {villager.name: villager for villager in villagers} self.assertTrue(villagers_by_name[NPC.wizard].bachelor) - self.assertEqual(len(villagers_by_name[NPC.wizard].mod_names), 1) - self.assertIn(ModNames.sve, villagers_by_name[NPC.wizard].mod_names) + self.assertEqual(villagers_by_name[NPC.wizard].mod_name, ModNames.sve) From 3a44bf00a00d56133078989f4e4695b31555b52f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 9 Nov 2023 14:52:22 +0200 Subject: [PATCH 113/482] - Fixes to tests --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/test/TestGeneration.py | 5 +- worlds/stardew_valley/test/TestLogic.py | 4 +- worlds/stardew_valley/test/__init__.py | 84 +++++++++++++++++++- 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index a16a6eb2a2af..3ab556bd9975 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -200,7 +200,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_cryptic_note: self.create_event_location(location_table[GoalName.cryptic_note], - self.logic.can_complete_quest("Cryptic Note").simplify(), + self.logic.quest.can_complete_quest("Cryptic Note").simplify(), Event.victory) elif self.options.goal == Goal.option_master_angler: self.create_event_location(location_table[GoalName.master_angler], diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 5116cd47fb6a..ab3eab44474d 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -1,10 +1,11 @@ from typing import List from BaseClasses import ItemClassification, MultiWorld, Item -from . import setup_solo_multiworld, SVTestBase, get_minsanity_options +from . import setup_solo_multiworld, SVTestBase, get_minsanity_options, allsanity_options_without_mods, \ + allsanity_options_with_mods, minimal_locations_maximal_items from .. import locations, items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name -from ..items import items_by_group, Group, item_table +from ..items import Group, item_table from ..locations import LocationTags from ..mods.mod_data import ModNames from ..options import Friendsanity, SpecialOrderLocations, Shipsanity, Chefsanity, SeasonRandomization, Craftsanity, ExcludeGingerIsland, ToolProgression, \ diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 494daa9e873f..1371fbdabdeb 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -1,10 +1,10 @@ import unittest -from . import SVTestBase, setup_solo_multiworld +from . import setup_solo_multiworld, allsanity_options_with_mods from ..data.bundle_data import all_bundle_items_except_money from ..stardew_rule import MISSING_ITEM, False_ -multi_world = setup_solo_multiworld(SVTestBase.allsanity_options_without_mods()) +multi_world = setup_solo_multiworld(allsanity_options_with_mods()) world = multi_world.worlds[1] logic = world.logic diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 366c37dca58a..d4346372152a 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -50,7 +50,89 @@ def get_minsanity_options(): return minsanity -class SVTestCase(unittest.TestCase): +def minimal_locations_maximal_items(): + min_max_options = { + Goal.internal_name: Goal.option_bottom_of_the_mines, + BundleRandomization.internal_name: BundleRandomization.option_vanilla, + BundlePrice.internal_name: BundlePrice.option_very_cheap, + SeasonRandomization.internal_name: SeasonRandomization.option_randomized, + Cropsanity.internal_name: Cropsanity.option_shuffled, + BackpackProgression.internal_name: BackpackProgression.option_vanilla, + ToolProgression.internal_name: ToolProgression.option_vanilla, + SkillProgression.internal_name: SkillProgression.option_vanilla, + BuildingProgression.internal_name: BuildingProgression.option_vanilla, + FestivalLocations.internal_name: FestivalLocations.option_disabled, + ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, + ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, + HelpWantedLocations.internal_name: 0, + Fishsanity.internal_name: Fishsanity.option_none, + Museumsanity.internal_name: Museumsanity.option_none, + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, + Friendsanity.internal_name: Friendsanity.option_none, + FriendsanityHeartSize.internal_name: 8, + NumberOfMovementBuffs.internal_name: 12, + NumberOfLuckBuffs.internal_name: 12, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, + TrapItems.internal_name: TrapItems.option_nightmare, + Mods.internal_name: (), + } + return min_max_options + + +def allsanity_options_without_mods(): + allsanity = { + Goal.internal_name: Goal.option_perfection, + BundleRandomization.internal_name: BundleRandomization.option_thematic, + BundlePrice.internal_name: BundlePrice.option_expensive, + SeasonRandomization.internal_name: SeasonRandomization.option_randomized, + Cropsanity.internal_name: Cropsanity.option_shuffled, + BackpackProgression.internal_name: BackpackProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive, + SkillProgression.internal_name: SkillProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, + FestivalLocations.internal_name: FestivalLocations.option_hard, + ElevatorProgression.internal_name: ElevatorProgression.option_progressive, + ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, + HelpWantedLocations.internal_name: 56, + Fishsanity.internal_name: Fishsanity.option_all, + Museumsanity.internal_name: Museumsanity.option_all, + Monstersanity.internal_name: Monstersanity.option_progressive_goals, + Shipsanity.internal_name: Shipsanity.option_everything, + Cooksanity.internal_name: Cooksanity.option_all, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + FriendsanityHeartSize.internal_name: 1, + NumberOfMovementBuffs.internal_name: 12, + NumberOfLuckBuffs.internal_name: 12, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, + TrapItems.internal_name: TrapItems.option_nightmare, + } + return allsanity + + +def allsanity_options_with_mods(): + allsanity = {} + allsanity.update(allsanity_options_without_mods()) + all_mods = ( + ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, + ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, + ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, + ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, + ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, + ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, + ModNames.sve + ) + allsanity.update({Mods.internal_name: all_mods}) + return allsanity + + +class SVTestBase(WorldTestBase): + game = "Stardew Valley" + world: StardewValleyWorld player: ClassVar[int] = 1 """Set to False to not skip some 'extra' tests""" skip_extra_tests: bool = True From fa2dd41f2a3371786f9c21ecdd65fea77d8e4792 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 9 Nov 2023 15:08:24 +0200 Subject: [PATCH 114/482] - Fix adventure guild entrance - Fix more tests --- worlds/stardew_valley/rules.py | 11 +++++++++-- worlds/stardew_valley/test/TestItems.py | 2 +- worlds/stardew_valley/test/TestLogic.py | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 47fca2a545bb..1d6a600c6e6b 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -249,8 +249,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S set_farm_buildings_entrance_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player), - logic.received("Adventurer's Guild")) + set_adventure_guild_entrance_rules(logic, multiworld, player, world_options) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), logic.time.has_lived_months(2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), @@ -271,6 +270,14 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce).simplify()) +def set_adventure_guild_entrance_rules(logic, multiworld, player, world_options): + if ModNames.sve in world_options.mods: + entrance = multiworld.get_entrance(SVEEntrance.guild_to_interior, player) + else: + entrance = multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player) + MultiWorldRules.set_rule(entrance, logic.received("Adventurer's Guild")) + + def set_farm_buildings_entrance_rules(logic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk).simplify()) diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index c0b9e4f77dec..adfa21eba843 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -53,7 +53,7 @@ def test_correct_number_of_stardrops(self): def test_no_duplicate_rings(self): seed = random.randrange(sys.maxsize) - allsanity_options = self.allsanity_options_without_mods() + allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options, seed=seed) ring_items = [item.name for item in multiworld.get_items() if Group.RING in item_table[item.name].groups] self.assertEqual(len(ring_items), len(set(ring_items))) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 1371fbdabdeb..5ad3107d6517 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -38,7 +38,7 @@ def test_given_building_rule_then_can_be_resolved(self): self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve building rule for {building} {rule}") def test_given_quest_rule_then_can_be_resolved(self): - for quest in logic.quest_rules.keys(): + for quest in logic.quest.quest_rules.keys(): with self.subTest(msg=quest): rule = logic.quest_rules[quest] self.assertNotIn(MISSING_ITEM, repr(rule)) From 865c55721d57707800d709093880ab0ef35740ad Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 9 Nov 2023 15:12:19 +0200 Subject: [PATCH 115/482] - Fix quest test --- worlds/stardew_valley/test/TestLogic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 5ad3107d6517..701d9600b3a5 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -40,7 +40,7 @@ def test_given_building_rule_then_can_be_resolved(self): def test_given_quest_rule_then_can_be_resolved(self): for quest in logic.quest.quest_rules.keys(): with self.subTest(msg=quest): - rule = logic.quest_rules[quest] + rule = logic.quest.quest_rules[quest] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve quest rule for {quest} {rule}") From 0a2302354f1f4251248800f3ba31dc3aa0bee742 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 9 Nov 2023 14:05:29 -0600 Subject: [PATCH 116/482] Fix item logic. --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/items.py | 8 +- worlds/stardew_valley/logic/logic.py | 1 + .../stardew_valley/mods/logic/item_logic.py | 83 +++++++++++++++++++ worlds/stardew_valley/mods/logic/mod_logic.py | 3 + .../stardew_valley/mods/logic/quests_logic.py | 3 +- worlds/stardew_valley/mods/logic/sve_logic.py | 38 --------- 7 files changed, 96 insertions(+), 42 deletions(-) create mode 100644 worlds/stardew_valley/mods/logic/item_logic.py diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 32f15b7b9dbc..26934610f678 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -779,7 +779,7 @@ id,name,classification,groups,mod_name 10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded 10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded 10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded -10511,Fable Reef Portal,progression,"GINGER_ISLAND,MOD_WARP",Stardew Valley Expanded +10511,Fable Reef Portal,progression,"GINGER_ISLAND",Stardew Valley Expanded 10512,Super Starfruit,useful,,Stardew Valley Expanded 10513,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10514,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 540a0225b8c1..494b17493faa 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -555,14 +555,18 @@ def create_magic_mod_spells(item_factory: StardewItemFactory, options: StardewVa def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true if ModNames.sve not in options.mods: return [] - items.append(item_factory("Diamond Wand")) - items.append(item_factory("Marlon's Boat Paddle")) items.append(item_factory("Iridium Bomb")) items.append(item_factory("Krobus' Protection")) items.append(item_factory("Kittyfish Spell")) items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP]]) + if exclude_ginger_island: + return + items.append(item_factory("Diamond Wand")) + items.append(item_factory("Marlon's Boat Paddle")) + items.append(item_factory("Fable Reef Portal")) def create_unique_filler_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random, diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index b899ebf9fbc7..9e7a5d48e80a 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -439,6 +439,7 @@ def __post_init__(self): self.item_rules.update(self.tree_fruit_rules) self.item_rules.update(self.seed_rules) self.item_rules.update(self.crop_rules) + self.item_rules.update(self.mod.item.get_modded_item_rules()) # For some recipes, the cooked item can be obtained directly, so we either cook it or get it for recipe in self.cooking_rules: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py new file mode 100644 index 000000000000..76a60ead63ee --- /dev/null +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -0,0 +1,83 @@ +from typing import Dict + +from ...logic.combat_logic import CombatLogic +from ...logic.cooking_logic import CookingLogic +from ...logic.has_logic import HasLogic +from ...logic.money_logic import MoneyLogic +from ...logic.region_logic import RegionLogic +from ...logic.relationship_logic import RelationshipLogic +from ...logic.season_logic import SeasonLogic +from ...logic.received_logic import ReceivedLogic +from ...logic.tool_logic import ToolLogic +from ...options import Mods +from ..mod_data import ModNames +from ...strings.crop_names import SVEVegetable, SVEFruit +from ...strings.fish_names import Fish, SVEFish +from ...strings.ingredient_names import Ingredient +from ...strings.tool_names import Tool, ToolMaterial +from ...strings.villager_names import NPC +from ...strings.food_names import Meal +from ...strings.forageable_names import SVEForage +from ...strings.monster_drop_names import Loot, ModLoot +from ...strings.season_names import Season +from ...strings.region_names import Region, SVERegion +from ...stardew_rule import StardewRule + + +class ModItemLogic: + mods: Mods + combat: CombatLogic + cooking: CookingLogic + has: HasLogic + money: MoneyLogic + region: RegionLogic + season: SeasonLogic + relationship: RelationshipLogic + received: ReceivedLogic + tool: ToolLogic + + def __init__(self, mods: Mods, combat: CombatLogic, cooking: CookingLogic, has: HasLogic, money: MoneyLogic, region: RegionLogic, + season: SeasonLogic, relationship: RelationshipLogic, tool: ToolLogic): + self.combat = combat + self.cooking = cooking + self.mods = mods + self.has = has + self.money = money + self.region = region + self.season = season + self.relationship = relationship + self.tool = tool + + def get_modded_item_rules(self) -> Dict[str, StardewRule]: + items = dict() + if ModNames.sve in self.mods: + items.update({ + "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), + "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & + self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & + self.region.can_reach(Region.saloon), + "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), + ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & + self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend( + 4000) & self.region.can_reach(Region.saloon), + "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), + SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(ModLoot.fungus_seed), + SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & + self.tool.has_tool(Tool.axe,ToolMaterial.iron), + SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(ModLoot.slime_seed), + ModLoot.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), + "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), + SVEForage.void_pebble: self.region.can_reach( + SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), + SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), + "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), + ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & + self.cooking.can_cook(), + }) + + return items diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 4713aac978ae..07eb795d8f32 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -3,6 +3,7 @@ from .buildings_logic import ModBuildingLogic from .deepwoods_logic import DeepWoodsLogic from .elevator_logic import ModElevatorLogic +from .item_logic import ModItemLogic from .magic_logic import MagicLogic from .quests_logic import ModQuestLogic from .skills_logic import ModSkillLogic @@ -33,6 +34,7 @@ class ModLogic: + items: ModItemLogic quests: ModQuestLogic region: RegionLogic magic: MagicLogic @@ -47,6 +49,7 @@ def __init__(self, player: int, skill_option: SkillProgression, elevator_option: action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): + self.item = ModItemLogic(mods,combat, cooking, has, money, region, season, relationship, tool) self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, has, region, season, relationship, received, time) self.buildings = ModBuildingLogic(player, has, money, mods) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 1242629bf208..238d0b8c1907 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -12,6 +12,7 @@ from ...strings.artisan_good_names import ArtisanGood from ...strings.crop_names import Fruit from ...strings.food_names import Meal, Beverage +from ...strings.forageable_names import SVEForage from ...strings.monster_drop_names import Loot, ModLoot from ...strings.villager_names import ModNPC from ...strings.season_names import Season @@ -70,7 +71,7 @@ def get_modded_quest_rules(self) -> Dict[str, StardewRule]: self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), ModQuest.MonsterCrops: self.has([ModLoot.monster_mushroom, ModLoot.slime_berry, ModLoot.monster_fruit, ModLoot.void_root]), - ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(ModQuest.VoidSoul), + ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(SVEForage.void_soul), }) return quests diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index b1b11688921d..d63373b4823a 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -17,16 +17,6 @@ from ...logic.tool_logic import ToolLogic from ..mod_regions import SVERegion from ...options import SkillProgression -from ...strings.crop_names import SVEVegetable, SVEFruit -from ...strings.fish_names import Fish, SVEFish -from ...strings.forageable_names import SVEForage -from ...strings.ingredient_names import Ingredient -from ...strings.food_names import Meal -from ...strings.monster_drop_names import Loot, ModLoot -from ...strings.region_names import Region -from ...strings.season_names import Season -from ...strings.tool_names import Tool, ToolMaterial -from ...strings.villager_names import NPC from ...stardew_rule import StardewRule, Or @@ -88,34 +78,6 @@ def initialize_rules(self): SVERegion.lances_house), }) - def set_sve_item_rules(self, items: Dict[str, StardewRule]): - items.update({ - "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), - "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & - self.region.can_reach(Region.saloon), - "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), - ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend(4000) & self.region.can_reach(Region.saloon), - "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), - SVEVegetable.monster_mushroom: self.has(Season.fall) & self.has(ModLoot.fungus_seed), - SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & - self.cooking.can_cook() & self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(ModLoot.slime_seed), - ModLoot.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), - "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), - SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), - SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), - "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), - ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & - self.cooking.can_cook(), - }) - def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", "Nexus: Outpost Runes"] From 2c2b2c348a4606e591731bb27e56c37f2ca09bd6 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 9 Nov 2023 14:05:39 -0600 Subject: [PATCH 117/482] Move grandpa's shed location --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 403a7e959712..9a58b3e171ab 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2438,7 +2438,7 @@ id,region,name,tags,mod_name 7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC 7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded 7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded -7509,Farm,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded +7509,Grandpa's Shed Interior,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded 7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded 7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded 7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded From 60c524dacb6bf2003f408799a8e66addbc6a388b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 9 Nov 2023 14:06:21 -0600 Subject: [PATCH 118/482] Fix region rules for ER --- worlds/stardew_valley/mods/mod_regions.py | 76 +++++++++++++---------- worlds/stardew_valley/regions.py | 6 +- worlds/stardew_valley/rules.py | 7 ++- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 83cfe53eebfc..f272c520d027 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -189,8 +189,8 @@ ] mandatory_sve_connections = [ - ConnectionData(SVEEntrance.town_to_jenkins, SVERegion.jenkins_residence), - ConnectionData(SVEEntrance.jenkins_to_cellar, SVERegion.jenkins_cellar), + ConnectionData(SVEEntrance.town_to_jenkins, SVERegion.jenkins_residence, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(SVEEntrance.jenkins_to_cellar, SVERegion.jenkins_cellar, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.forest_to_bmv, SVERegion.blue_moon_vineyard), ConnectionData(SVEEntrance.bmv_to_beach, Region.beach), ConnectionData(SVEEntrance.town_to_plot, SVERegion.unclaimed_plot), @@ -198,50 +198,58 @@ ConnectionData(SVEEntrance.town_to_bridge, SVERegion.shearwater), ConnectionData(SVEEntrance.plot_to_bridge, SVERegion.shearwater), ConnectionData(SVEEntrance.bus_stop_to_shed, SVERegion.grandpas_shed), - ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior), - ConnectionData(SVEEntrance.to_grandpa_upstairs, SVERegion.grandpas_shed_upstairs), + ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior, flag=RandomizationFlag.NON_PROGRESSION| RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(SVEEntrance.to_grandpa_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), - ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house), - ConnectionData(SVEEntrance.boat_to_highlands, SVERegion.highlands), - ConnectionData(SVEEntrance.guild_to_interior, SVERegion.guild_summit), - ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove), - ConnectionData(SVEEntrance.grove_to_outpost, SVERegion.galmoran_outpost), - ConnectionData(SVEEntrance.grove_to_wizard, Region.wizard_basement), - ConnectionData(SVEEntrance.grove_to_aurora, SVERegion.aurora_vineyard_basement), - ConnectionData(SVEEntrance.to_aurora_basement, SVERegion.aurora_vineyard_basement), - ConnectionData(SVEEntrance.grove_to_farm, Region.farm), - ConnectionData(SVEEntrance.grove_to_guild, Region.adventurer_guild), - ConnectionData(SVEEntrance.grove_to_junimo, SVERegion.junimo_woods), + ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(SVEEntrance.boat_to_highlands, SVERegion.highlands, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(SVEEntrance.grove_to_outpost, SVERegion.galmoran_outpost, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_wizard, Region.wizard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_aurora, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.to_aurora_basement, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_farm, Region.farm, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_guild, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_junimo, SVERegion.junimo_woods, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), - ConnectionData(SVEEntrance.grove_to_spring, SVERegion.sprite_spring), - ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef), - ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild), - ConnectionData(SVEEntrance.to_outpost_roof, SVERegion.outpost_roof), - ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance), - ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands), - ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave), - ConnectionData(SVEEntrance.guild_to_mines, Region.mines), + ConnectionData(SVEEntrance.grove_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.to_outpost_roof, SVERegion.outpost_roof, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.guild_to_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.mountain_to_guild_summit, SVERegion.guild_summit), ConnectionData(SVEEntrance.summit_to_boat, SVERegion.marlon_boat), ConnectionData(SVEEntrance.forest_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.secret_woods_to_west, SVERegion.forest_west), - ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard), - ConnectionData(SVEEntrance.forest_to_junimo, SVERegion.junimo_woods), - ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed), - ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring), - ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house), - ConnectionData(SVEEntrance.enter_summit, SVERegion.summit), - ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm), - ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house), - ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands), - ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern), + ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_to_junimo, SVERegion.junimo_woods, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop), ConnectionData(SVEEntrance.use_issac_shop, SVERegion.issac_shop), - ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison), + ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.NON_PROGRESSION), ] +remove_vanilla_connections = { + ModNames.sve: [ConnectionData(Entrance.mountain_to_the_mines, Region.mines, + flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(Entrance.mountain_to_adventurer_guild, Region.adventurer_guild, + flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), + ] +} + ModDataList = { ModNames.deepwoods: ModRegionData(ModNames.deepwoods, deep_woods_regions, deep_woods_entrances), ModNames.eugene: ModRegionData(ModNames.eugene, eugene_regions, eugene_entrances), diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 590e688f2621..6c420bc53ea6 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -6,7 +6,7 @@ from .strings.entrance_names import Entrance from .strings.region_names import Region from .region_classes import RegionData, ConnectionData, RandomizationFlag, ModificationFlag -from .mods.mod_regions import ModDataList +from .mods.mod_regions import ModDataList, remove_vanilla_connections class RegionFactory(Protocol): @@ -497,6 +497,9 @@ def create_final_connections(world_options) -> List[ConnectionData]: for mod in world_options.mods.value: if mod not in ModDataList: continue + if mod in remove_vanilla_connections: + for connection_data in remove_vanilla_connections[mod]: + final_connections.remove(connection_data) final_connections.extend(ModDataList[mod].connections) return final_connections @@ -511,7 +514,6 @@ def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionD return updated_region - def create_regions(region_factory: RegionFactory, random: Random, world_options) -> Tuple[ Dict[str, Region], Dict[str, str]]: final_regions = create_final_regions(world_options) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 1d6a600c6e6b..9f8d1c1fa2a4 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -80,6 +80,7 @@ def set_rules(world): set_deepwoods_rules(logic, multiworld, player, world_options) set_magic_spell_rules(logic, multiworld, player, world_options) + set_sve_rules(logic, multiworld, player, world_options) # 1min52 - 1min53 # These times are for TestOptions # 1min36 - 1min38 # After the combat not duplicating a bunch of stuff # 1min28 - 1min30 # with the caching of combat rules @@ -911,11 +912,11 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), logic.received("Iridium Bomb").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), - logic.can_complete_quest(Quest.strange_note).simplify()) + logic.quest.can_complete_quest(Quest.strange_note).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), logic.mod.sve.has_any_rune().simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), - logic.can_complete_quest(Quest.magic_ink).simplify()) + logic.quest.can_complete_quest(Quest.magic_ink).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), logic.tool.has_tool(Tool.axe, ToolMaterial.iron).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), @@ -939,7 +940,7 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), logic.relationship.has_hearts(ModNPC.apples, 10).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.to_grandpa_upstairs, player), - logic.special_order.can_complete_special_order("Grandpa's Shed").simplify()) + logic.quest.can_complete_quest("Grandpa's Shed").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron).simplify()) for location in logic.mod.sve.sve_location_rules: From dfe5bfc08bace8e4ad61d6f6cb3d5b7947afdf59 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 9 Nov 2023 14:39:14 -0600 Subject: [PATCH 119/482] Fix ginger island discrepency --- worlds/stardew_valley/data/locations.csv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 9a58b3e171ab..627182f7ac74 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2454,9 +2454,9 @@ id,region,name,tags,mod_name 7503,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded 7504,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded 7505,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7506,Highlands,Fishsanity: Daggerfish,FISHSANITY,Stardew Valley Expanded +7506,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7507,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7508,Highlands,Fishsanity: Gemfish,FISHSANITY,Stardew Valley Expanded +7508,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 8001,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded 8002,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded 8003,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded @@ -2470,7 +2470,7 @@ id,region,name,tags,mod_name 8011,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 8012,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded 8013,Beach,Fishsanity: Starfish,FISHSANITY,Stardew Valley Expanded -8014,Fable Reef,Fishsanity: Torpedo Trout,FISHSANITY,Stardew Valley Expanded +8014,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 8015,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded 8016,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded 8017,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded From faed4e9fe8c4f306e8e2b2597162854d13134562 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 09:22:48 -0500 Subject: [PATCH 120/482] - removed redundant array creations --- worlds/stardew_valley/items.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 494b17493faa..e6bf8fd1d35a 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -550,14 +550,14 @@ def create_filler_festival_rewards(item_factory: StardewItemFactory, options: St def create_magic_mod_spells(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): if ModNames.magic not in options.mods: - return [] + return items.extend([item_factory(item) for item in items_by_group[Group.MAGIC_SPELL]]) def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true if ModNames.sve not in options.mods: - return [] + return items.append(item_factory("Iridium Bomb")) items.append(item_factory("Krobus' Protection")) items.append(item_factory("Kittyfish Spell")) From d65411f81ef2057f0a2bb4058c58d91f80909e63 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 09:30:45 -0500 Subject: [PATCH 121/482] - Slight refactoring for bundle logic --- worlds/stardew_valley/logic/bundle_logic.py | 12 ++++++------ worlds/stardew_valley/logic/farming_logic.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index fb7d7e27b1dd..fef950f0170c 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -12,19 +12,19 @@ class BundleLogic: player: int - crop: CropLogic - farming: FarmingLogic has: HasLogic region: RegionLogic money: MoneyLogic + crop: CropLogic + farming: FarmingLogic - def __init__(self, player: int, crop: CropLogic, farming: FarmingLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + def __init__(self, player: int, has: HasLogic, region: RegionLogic, money: MoneyLogic, crop: CropLogic, farming: FarmingLogic): self.player = player - self.crop = crop - self.farming = farming self.has = has self.region = region self.money = money + self.crop = crop + self.farming = farming def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: item_rules = [] @@ -37,7 +37,7 @@ def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_requ item_rules.append(bundle_item.item.name) if bundle_item.quality > highest_quality_yet: highest_quality_yet = bundle_item.quality - return can_speak_junimo & self.has(item_rules, number_required) & self.farming.can_grow_gold_quality(highest_quality_yet) + return can_speak_junimo & self.has(item_rules, number_required) & self.farming.can_grow_crop_quality(highest_quality_yet) def can_complete_community_center(self) -> StardewRule: return (self.region.can_reach_location("Complete Crafts Room") & diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 3a9ced9948ba..6c317fe42e86 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -13,7 +13,7 @@ def __init__(self, player: int, crop: CropLogic, skill: SkillLogic): self.crop = crop self.skill = skill - def can_grow_gold_quality(self, quality: int) -> StardewRule: + def can_grow_crop_quality(self, quality: int) -> StardewRule: if quality <= 0: return True_() if quality == 1: From 375145711c87c519d58d17129f4ee46c884dc185 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 09:34:06 -0500 Subject: [PATCH 122/482] - Simplified rules --- worlds/stardew_valley/logic/bundle_logic.py | 5 +--- worlds/stardew_valley/logic/crop_logic.py | 13 +------- worlds/stardew_valley/logic/farming_logic.py | 31 +++++++++++++------- worlds/stardew_valley/logic/logic.py | 4 +-- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index fef950f0170c..54fdb1555489 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,7 +1,6 @@ from typing import List from ..data.bundle_data import BundleItem -from .crop_logic import CropLogic from .farming_logic import FarmingLogic from .has_logic import HasLogic from .money_logic import MoneyLogic @@ -15,15 +14,13 @@ class BundleLogic: has: HasLogic region: RegionLogic money: MoneyLogic - crop: CropLogic farming: FarmingLogic - def __init__(self, player: int, has: HasLogic, region: RegionLogic, money: MoneyLogic, crop: CropLogic, farming: FarmingLogic): + def __init__(self, player: int, has: HasLogic, region: RegionLogic, money: MoneyLogic, farming: FarmingLogic): self.player = player self.has = has self.region = region self.money = money - self.crop = crop self.farming = farming def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index a839893c4149..661ba845b4ac 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -5,8 +5,7 @@ from .season_logic import SeasonLogic from .tool_logic import ToolLogic from ..data import CropItem -from ..stardew_rule import StardewRule, True_ -from ..strings.fertilizer_names import Fertilizer +from ..stardew_rule import StardewRule from ..strings.region_names import Region from ..strings.tool_names import Tool @@ -43,13 +42,3 @@ def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> Stardew def has_island_farm(self) -> StardewRule: return self.region.can_reach(Region.island_south) - - def has_fertilizer(self, tier: int) -> StardewRule: - if tier <= 0: - return True_() - if tier == 1: - return self.has(Fertilizer.basic) - if tier == 2: - return self.has(Fertilizer.quality) - if tier >= 3: - return self.has(Fertilizer.deluxe) diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 6c317fe42e86..6c2e5b1107cb 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -1,29 +1,40 @@ +from .has_logic import HasLogic from ..stardew_rule import StardewRule, True_ from .skill_logic import SkillLogic -from .crop_logic import CropLogic +from ..strings.fertilizer_names import Fertilizer class FarmingLogic: player: int - crop: CropLogic + has: HasLogic skill: SkillLogic - def __init__(self, player: int, crop: CropLogic, skill: SkillLogic): + def __init__(self, player: int, has: HasLogic, skill: SkillLogic): self.player = player - self.crop = crop + self.has = has self.skill = skill + def has_fertilizer(self, tier: int) -> StardewRule: + if tier <= 0: + return True_() + if tier == 1: + return self.has(Fertilizer.basic) + if tier == 2: + return self.has(Fertilizer.quality) + if tier >= 3: + return self.has(Fertilizer.deluxe) + def can_grow_crop_quality(self, quality: int) -> StardewRule: if quality <= 0: return True_() if quality == 1: - return self.skill.has_farming_level(5) | (self.crop.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( - self.crop.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.crop.has_fertilizer(3) + return self.skill.has_farming_level(5) | (self.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( + self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) if quality == 2: return self.skill.has_farming_level(10) | ( - self.crop.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( - self.crop.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( - self.crop.has_fertilizer(3) & self.skill.has_farming_level(2)) + self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( + self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( + self.has_fertilizer(3) & self.skill.has_farming_level(2)) if quality >= 3: - return self.crop.has_fertilizer(3) & self.skill.has_farming_level(4) + return self.has_fertilizer(3) & self.skill.has_farming_level(4) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9e7a5d48e80a..e4d7aedd8819 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -131,8 +131,8 @@ def __post_init__(self): self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) self.crop = CropLogic(self.player, self.has, self.region, self.season, self.tool) self.skill = SkillLogic(self.player, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) - self.farming = FarmingLogic(self.player, self.crop, self.skill) - self.bundle = BundleLogic(self.player, self.crop, self.farming, self.has, self.region, self.money) + self.farming = FarmingLogic(self.player, self.has, self.skill) + self.bundle = BundleLogic(self.player, self.has, self.region, self.money, self.farming) self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) From a77cd32b54350adee01b76a10809c6077b774164 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 10:28:49 -0500 Subject: [PATCH 123/482] - revert a change that wasn't necessary --- worlds/stardew_valley/logic/relationship_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 53010b6e5127..7c9a82c1ddb5 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -169,7 +169,7 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] mod = npc.mod_name - return not mod or npc in get_villagers_for_mods(self.mods_option.value) + return mod is None or mod in self.mods_option def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): From ab562e9c5dc5542d26e165b9986a4b4336360dde Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 10:30:23 -0500 Subject: [PATCH 124/482] - extracted a method in sve item rules --- .../stardew_valley/mods/logic/item_logic.py | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 76a60ead63ee..dea5fb1714ec 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -51,33 +51,36 @@ def __init__(self, mods: Mods, combat: CombatLogic, cooking: CookingLogic, has: def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() if ModNames.sve in self.mods: - items.update({ - "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), - "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & - self.region.can_reach(Region.saloon), - "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), - ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend( - 4000) & self.region.can_reach(Region.saloon), - "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), - SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(ModLoot.fungus_seed), - SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & - self.tool.has_tool(Tool.axe,ToolMaterial.iron), - SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(ModLoot.slime_seed), - ModLoot.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), - "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), - SVEForage.void_pebble: self.region.can_reach( - SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), - SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), - "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), - ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & - self.cooking.can_cook(), - }) + items.update(self._get_sve_item_rules()) return items + + def _get_sve_item_rules(self): + return { + "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), + "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & + self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & + self.region.can_reach(Region.saloon), + "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), + ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & + self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend( + 4000) & self.region.can_reach(Region.saloon), + "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), + SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(ModLoot.fungus_seed), + SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & + self.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(ModLoot.slime_seed), + ModLoot.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), + "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), + SVEForage.void_pebble: self.region.can_reach( + SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), + SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), + "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), + ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & + self.cooking.can_cook(), + } From daf0c8380fae688443fa2e17cf7dd3170e74f02d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 10:38:01 -0500 Subject: [PATCH 125/482] - Item logic improvements --- worlds/stardew_valley/mods/logic/item_logic.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index dea5fb1714ec..af936bf67b74 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -57,15 +57,13 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: def _get_sve_item_rules(self): return { - "Aged Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(28000), + "Aged Blue Moon Wine": self.money.can_spend_at(SVERegion.sophias_house, 28000), "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend(5500) & - self.region.can_reach(Region.saloon), - "Blue Moon Wine": self.region.can_reach(SVERegion.sophias_house) & self.money.can_spend(3000), + self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend_at(Region.saloon, 5500), + "Blue Moon Wine": self.money.can_spend_at(SVERegion.sophias_house, 3000), ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend( - 4000) & self.region.can_reach(Region.saloon), + self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend_at(Region.saloon, 4000), "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(ModLoot.fungus_seed), @@ -76,11 +74,9 @@ def _get_sve_item_rules(self): ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), - SVEForage.void_pebble: self.region.can_reach( - SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), + SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & - self.cooking.can_cook(), + SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & self.cooking.can_cook(), } From 6e1f600d95668ac2215514fa9035fa045de903c2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 10:51:38 -0500 Subject: [PATCH 126/482] - Refactor modded quest logic --- worlds/stardew_valley/mods/logic/mod_logic.py | 2 +- .../stardew_valley/mods/logic/quests_logic.py | 82 +++++++++++-------- 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 07eb795d8f32..83b2002725a0 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -51,7 +51,7 @@ def __init__(self, player: int, skill_option: SkillProgression, elevator_option: time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): self.item = ModItemLogic(mods,combat, cooking, has, money, region, season, relationship, tool) self.magic = MagicLogic(player, mods, received, region) - self.quests = ModQuestLogic(mods, has, region, season, relationship, received, time) + self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) self.buildings = ModBuildingLogic(player, has, money, mods) self.special_orders = ModSpecialOrderLogic(player, action, artisan, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 238d0b8c1907..3f454ea74837 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -25,53 +25,69 @@ class ModQuestLogic: mods: Mods + received: ReceivedLogic has: HasLogic region: RegionLogic + time: TimeLogic season: SeasonLogic relationship: RelationshipLogic - received: ReceivedLogic - time: TimeLogic - def __init__(self, mods: Mods, has: HasLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, - received: ReceivedLogic, time: TimeLogic): + def __init__(self, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, season: SeasonLogic, + relationship: RelationshipLogic,): self.mods = mods + self.received = received self.has = has self.region = region + self.time = time self.season = season self.relationship = relationship - self.received = received - self.time = time def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = dict() - if ModNames.juna in self.mods: - quests.update({ - ModQuest.JunaCola: self.relationship.has_hearts(ModNPC.juna, 3) & self.has(Beverage.joja_cola), - ModQuest.JunaSpaghetti: self.relationship.has_hearts(ModNPC.juna, 6) & self.has(Meal.spaghetti) - }) + quests.update(self._get_juna_quest_rules()) + quests.update(self._get_mr_ginger_quest_rules()) + quests.update(self._get_ayeisha_quest_rules()) + quests.update(self._get_sve_quest_rules()) + return quests - if ModNames.ginger in self.mods: - quests.update({ - ModQuest.MrGinger: self.relationship.has_hearts(ModNPC.mr_ginger, 6) & self.has(Loot.void_essence) - }) + def _get_juna_quest_rules(self): + if ModNames.juna not in self.mods: + return {} - if ModNames.ayeisha in self.mods: - quests.update({ - ModQuest.AyeishaEnvelope: (self.season.has(Season.spring) | self.season.has(Season.fall)) & self.region.can_reach(Region.mountain), - ModQuest.AyeishaRing: self.season.has(Season.winter) & self.region.can_reach(Region.forest) - }) + return { + ModQuest.JunaCola: self.relationship.has_hearts(ModNPC.juna, 3) & self.has(Beverage.joja_cola), + ModQuest.JunaSpaghetti: self.relationship.has_hearts(ModNPC.juna, 6) & self.has(Meal.spaghetti) + } - if ModNames.sve in self.mods: - quests.update({ - ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has([Ore.iridium, Material.coal]) & - self.region.can_reach(Region.blacksmith) & self.region.can_reach(Region.railroad), - ModQuest.GrandpasShed: self.has([Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone]) & - self.region.can_reach(SVERegion.grandpas_shed_interior), - ModQuest.MarlonsBoat: self.has([Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat]) & - self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), - ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.has([ModLoot.monster_mushroom, ModLoot.slime_berry, ModLoot.monster_fruit, ModLoot.void_root]), - ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(SVEForage.void_soul), - }) + def _get_mr_ginger_quest_rules(self): + if ModNames.ginger not in self.mods: + return {} - return quests + return { + ModQuest.MrGinger: self.relationship.has_hearts(ModNPC.mr_ginger, 6) & self.has(Loot.void_essence) + } + + def _get_ayeisha_quest_rules(self): + if ModNames.ayeisha not in self.mods: + return {} + + return { + ModQuest.AyeishaEnvelope: (self.season.has(Season.spring) | self.season.has(Season.fall)) & self.region.can_reach(Region.mountain), + ModQuest.AyeishaRing: self.season.has(Season.winter) & self.region.can_reach(Region.forest) + } + + def _get_sve_quest_rules(self): + if ModNames.sve not in self.mods: + return {} + + return { + ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has([Ore.iridium, Material.coal]) & + self.region.can_reach(Region.blacksmith) & self.region.can_reach(Region.railroad), + ModQuest.GrandpasShed: self.has([Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone]) & + self.region.can_reach(SVERegion.grandpas_shed_interior), + ModQuest.MarlonsBoat: self.has([Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat]) & + self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), + ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), + ModQuest.MonsterCrops: self.has([ModLoot.monster_mushroom, ModLoot.slime_berry, ModLoot.monster_fruit, ModLoot.void_root]), + ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(SVEForage.void_soul), + } From 40604a1ec01a5b28eec4debca84ffe9fec40404f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 10:57:12 -0500 Subject: [PATCH 127/482] - Remove duplicated options --- worlds/stardew_valley/options.py | 54 -------------------------------- 1 file changed, 54 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 129e171e3ccc..4d6435756d3a 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -490,60 +490,6 @@ class FriendsanityHeartSize(Range): # step = 1 -class Monstersanity(Choice): - """Locations for slaying monsters? - None: There are no checks for slaying monsters - One per category: Every category visible at the adventure guild gives one check - One per Monster: Every unique monster gives one check - Monster Eradication Goals: The Monster Eradication Goals each contain one check - Short Monster Eradication Goals: The Monster Eradication Goals each contain one check, but are reduced by 60% - Very Short Monster Eradication Goals: The Monster Eradication Goals each contain one check, but are reduced by 90% - Progressive Eradication Goals: The Monster Eradication Goals each contain 5 checks, each 20% of the way - Split Eradication Goals: The Monster Eradication Goals are split by monsters, each monster has one check - """ - internal_name = "monstersanity" - display_name = "Monstersanity" - default = 1 - option_none = 0 - option_one_per_category = 1 - option_one_per_monster = 2 - option_goals = 3 - option_short_goals = 4 - option_very_short_goals = 5 - option_progressive_goals = 6 - option_split_goals = 7 - - -class Shipsanity(Choice): - """Locations for shipping items? - None: There are no checks for shipping items - Crops: Every crop being shipped is a check - Quality Crops: Every crop being shipped is a check, but only granted if it is gold-quality - Fish: Every fish being shipped is a check except legendaries - Quality Fish: Every fish being shipped is a check except legendaries, but only granted if it is gold-quality - Full Shipment: Every item in the Collections page is a check - Quality Full Shipment: Every item in the Collections page is a check, but only granted if it is gold-quality when applicable - Full Shipment With Fish: Every item in the Collections page and every fish is a check - Quality Full Shipment With Fish: Every item in the Collections page and every fish is a check, but only granted if it is gold-quality when applicable - Everything: Every item in the game that can be shipped is a check - Quality Everything: Every item in the game that can be shipped is a check, but only granted if it is gold-quality when applicable - """ - internal_name = "shipsanity" - display_name = "Shipsanity" - default = 0 - option_none = 0 - option_crops = 1 - option_quality_crops = 2 - option_fish = 3 - option_quality_fish = 4 - option_full_shipment = 5 - option_quality_full_shipment = 6 - option_full_shipment_with_fish = 7 - option_quality_full_shipment_with_fish = 8 - option_everything = 9 - option_quality_everything = 10 - - class NumberOfMovementBuffs(Range): """Number of movement speed buffs to the player that exist as items in the pool. Each movement speed buff is a +25% multiplier that stacks additively""" From 463936c2fb6311773cbe5c997ff13b169d6cb6da Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 11:19:08 -0500 Subject: [PATCH 128/482] - Fix fishing rules when playing unmodded and needing to catch any fish, so mod fish aren't valid targets --- worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/mods/mod_regions.py | 2 +- worlds/stardew_valley/regions.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index e4d7aedd8819..b20775cc6ef1 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -287,7 +287,7 @@ def __post_init__(self): Fertilizer.deluxe: False_(), Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), - Fish.any: Or([self.can_catch_fish(fish) for fish in all_fish]), + Fish.any: Or([self.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)]), Fish.crab: self.skill.can_crab_pot(Region.beach), Fish.crayfish: self.skill.can_crab_pot(Region.town), Fish.lobster: self.skill.can_crab_pot(Region.beach), diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index f272c520d027..7d0df7525008 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -242,7 +242,7 @@ ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.NON_PROGRESSION), ] -remove_vanilla_connections = { +vanilla_connections_to_remove_by_mod = { ModNames.sve: [ConnectionData(Entrance.mountain_to_the_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.mountain_to_adventurer_guild, Region.adventurer_guild, diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 6c420bc53ea6..d47dd1b4442b 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -6,7 +6,7 @@ from .strings.entrance_names import Entrance from .strings.region_names import Region from .region_classes import RegionData, ConnectionData, RandomizationFlag, ModificationFlag -from .mods.mod_regions import ModDataList, remove_vanilla_connections +from .mods.mod_regions import ModDataList, vanilla_connections_to_remove_by_mod class RegionFactory(Protocol): @@ -497,8 +497,8 @@ def create_final_connections(world_options) -> List[ConnectionData]: for mod in world_options.mods.value: if mod not in ModDataList: continue - if mod in remove_vanilla_connections: - for connection_data in remove_vanilla_connections[mod]: + if mod in vanilla_connections_to_remove_by_mod: + for connection_data in vanilla_connections_to_remove_by_mod[mod]: final_connections.remove(connection_data) final_connections.extend(ModDataList[mod].connections) return final_connections From 7983a7258b08715de90b0fea04f3f0105a718669 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 11:24:23 -0500 Subject: [PATCH 129/482] - Sort fish names --- worlds/stardew_valley/strings/fish_names.py | 50 ++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 58b771dc87e4..831c6343a06b 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -1,36 +1,16 @@ class Fish: - spook_fish = "Spook Fish" - midnight_squid = "Midnight Squid" - blob_fish = "Blobfish" - woodskip = "Woodskip" - walleye = "Walleye" - tilapia = "Tilapia" - tiger_trout = "Tiger Trout" - super_cucumber = "Super Cucumber" - stonefish = "Stonefish" - slimejack = "Slimejack" - shad = "Shad" - scorpion_carp = "Scorpion Carp" - sandfish = "Sandfish" - red_snapper = "Red Snapper" - red_mullet = "Red Mullet" - pike = "Pike" - perch = "Perch" - ice_pip = "Ice Pip" - herring = "Herring" - halibut = "Halibut" - ghostfish = "Ghostfish" - chub = "Chub" - bullhead = "Bullhead" - anchovy = "Anchovy" albacore = "Albacore" + anchovy = "Anchovy" angler = "Angler" any = "Any Fish" + blob_fish = "Blobfish" blobfish = "Blobfish" blue_discus = "Blue Discus" bream = "Bream" + bullhead = "Bullhead" carp = "Carp" catfish = "Catfish" + chub = "Chub" clam = "Clam" cockle = "Cockle" crab = "Crab" @@ -39,40 +19,60 @@ class Fish: dorado = "Dorado" eel = "Eel" flounder = "Flounder" + ghostfish = "Ghostfish" glacierfish = "Glacierfish" glacierfish_jr = "Glacierfish Jr." + halibut = "Halibut" + herring = "Herring" + ice_pip = "Ice Pip" largemouth_bass = "Largemouth Bass" lava_eel = "Lava Eel" legend = "Legend" legend_ii = "Legend II" - lionfish = "Lionfish" lingcod = "Lingcod" + lionfish = "Lionfish" lobster = "Lobster" midnight_carp = "Midnight Carp" + midnight_squid = "Midnight Squid" ms_angler = "Ms. Angler" mussel = "Mussel" mussel_node = "Mussel Node" mutant_carp = "Mutant Carp" octopus = "Octopus" oyster = "Oyster" + perch = "Perch" periwinkle = "Periwinkle" + pike = "Pike" pufferfish = "Pufferfish" radioactive_carp = "Radioactive Carp" rainbow_trout = "Rainbow Trout" + red_mullet = "Red Mullet" + red_snapper = "Red Snapper" salmon = "Salmon" + sandfish = "Sandfish" sardine = "Sardine" + scorpion_carp = "Scorpion Carp" sea_cucumber = "Sea Cucumber" + shad = "Shad" shrimp = "Shrimp" + slimejack = "Slimejack" smallmouth_bass = "Smallmouth Bass" snail = "Snail" son_of_crimsonfish = "Son of Crimsonfish" + spook_fish = "Spook Fish" spookfish = "Spook Fish" squid = "Squid" stingray = "Stingray" + stonefish = "Stonefish" sturgeon = "Sturgeon" sunfish = "Sunfish" + super_cucumber = "Super Cucumber" + tiger_trout = "Tiger Trout" + tilapia = "Tilapia" tuna = "Tuna" void_salmon = "Void Salmon" + walleye = "Walleye" + woodskip = "Woodskip" class WaterItem: From b37d7394191d78196f2d047800660a79104f7605 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 12 Nov 2023 11:04:08 -0600 Subject: [PATCH 130/482] Move Names --- .../stardew_valley/mods/logic/item_logic.py | 50 ++++++++----------- .../stardew_valley/mods/logic/quests_logic.py | 6 +-- worlds/stardew_valley/mods/logic/sve_logic.py | 7 --- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/strings/crop_names.py | 2 + worlds/stardew_valley/strings/food_names.py | 14 ++++++ .../strings/forageable_names.py | 17 +++++++ worlds/stardew_valley/strings/gift_names.py | 5 ++ .../strings/monster_drop_names.py | 11 ++-- worlds/stardew_valley/strings/seed_names.py | 7 +++ 10 files changed, 72 insertions(+), 49 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index af936bf67b74..90ae0f56153f 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -12,15 +12,13 @@ from ...options import Mods from ..mod_data import ModNames from ...strings.crop_names import SVEVegetable, SVEFruit -from ...strings.fish_names import Fish, SVEFish -from ...strings.ingredient_names import Ingredient +from ...strings.gift_names import SVEGift from ...strings.tool_names import Tool, ToolMaterial -from ...strings.villager_names import NPC -from ...strings.food_names import Meal from ...strings.forageable_names import SVEForage -from ...strings.monster_drop_names import Loot, ModLoot +from ...strings.monster_drop_names import ModLoot from ...strings.season_names import Season -from ...strings.region_names import Region, SVERegion +from ...strings.seed_names import SVESeed +from ...strings.region_names import SVERegion from ...stardew_rule import StardewRule @@ -56,27 +54,19 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: return items def _get_sve_item_rules(self): - return { - "Aged Blue Moon Wine": self.money.can_spend_at(SVERegion.sophias_house, 28000), - "Big Bark Burger": self.cooking.can_cook() & self.has([SVEFish.puppyfish, Meal.bread, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 5) & self.money.can_spend_at(Region.saloon, 5500), - "Blue Moon Wine": self.money.can_spend_at(SVERegion.sophias_house, 3000), - ModLoot.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - "Glazed Butterfish": self.cooking.can_cook() & self.has([SVEFish.butterfish, Ingredient.wheat_flour, Ingredient.oil]) & - self.relationship.has_hearts(NPC.gus, 10) & self.money.can_spend_at(Region.saloon, 4000), - "Green Mushroom": self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(ModLoot.stalk_seed), - SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(ModLoot.fungus_seed), - SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & - self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(ModLoot.slime_seed), - ModLoot.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - ModLoot.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), - "Void Delight": self.has(SVEFish.void_eel) & self.has(Loot.void_essence) & self.has(Loot.solar_essence), - SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon(), - SVEVegetable.void_root: self.season.has(Season.winter) & self.has(ModLoot.void_seed), - "Void Salmon Sushi": self.has(Fish.void_salmon) & self.has("Void Mayonnaise") & self.has("Seaweed"), - ModLoot.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & self.cooking.can_cook(), - } + return {SVEGift.aged_blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 28000), + SVEGift.blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 3000), + SVESeed.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + ModLoot.green_mushroom: self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(SVESeed.stalk_seed), + SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(SVESeed.fungus_seed), + SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & + self.tool.has_tool(Tool.axe,ToolMaterial.iron), + SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(SVESeed.slime_seed), + SVESeed.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + SVESeed.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), + SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), + SVEVegetable.void_root: self.season.has(Season.winter) & self.has(SVESeed.void_seed), + SVESeed.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & self.cooking.can_cook(), + } diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 3f454ea74837..1781b6bc744e 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -10,10 +10,10 @@ from ...strings.quest_names import ModQuest from ..mod_data import ModNames from ...strings.artisan_good_names import ArtisanGood -from ...strings.crop_names import Fruit +from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable from ...strings.food_names import Meal, Beverage from ...strings.forageable_names import SVEForage -from ...strings.monster_drop_names import Loot, ModLoot +from ...strings.monster_drop_names import Loot from ...strings.villager_names import ModNPC from ...strings.season_names import Season from ...strings.region_names import Region, SVERegion @@ -88,6 +88,6 @@ def _get_sve_quest_rules(self): ModQuest.MarlonsBoat: self.has([Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat]) & self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.has([ModLoot.monster_mushroom, ModLoot.slime_berry, ModLoot.monster_fruit, ModLoot.void_root]), + ModQuest.MonsterCrops: self.has([SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root]), ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(SVEForage.void_soul), } diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index d63373b4823a..88da42519b25 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -1,5 +1,4 @@ from typing import Dict -from dataclasses import field, dataclass from ...logic.action_logic import ActionLogic from ...logic.building_logic import BuildingLogic @@ -59,12 +58,6 @@ def __init__(self, player: int, skill_option: SkillProgression, received: Receiv def initialize_rules(self): self.sve_location_rules.update({ - "Bear: Baked Berry Oatmeal Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend( - 12500), - "Bear: Flower Cookie Recipe": self.quest.can_complete_quest("Strange Note") & self.money.can_spend(8750), - "Purple Junimo: Super Starfruit": self.relationship.has_hearts("Apples", 10) & - self.region.can_reach( - SVERegion.purple_junimo_shop) & self.money.can_spend(80000), "Alesia: Tempered Galaxy Dagger": self.region.can_reach( SVERegion.alesia_shop) & self.combat.has_galaxy_weapon() & self.money.can_spend(350000) & self.time.has_lived_months(3), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 9f8d1c1fa2a4..ac89e1d0cf02 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -940,7 +940,7 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), logic.relationship.has_hearts(ModNPC.apples, 10).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.to_grandpa_upstairs, player), - logic.quest.can_complete_quest("Grandpa's Shed").simplify()) + logic.quest.can_complete_quest(ModQuest.GrandpasShed).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron).simplify()) for location in logic.mod.sve.sve_location_rules: diff --git a/worlds/stardew_valley/strings/crop_names.py b/worlds/stardew_valley/strings/crop_names.py index a2668650bc36..2ae8eb2cbc62 100644 --- a/worlds/stardew_valley/strings/crop_names.py +++ b/worlds/stardew_valley/strings/crop_names.py @@ -63,9 +63,11 @@ class Vegetable: class SVEFruit: slime_berry = "Slime Berry" monster_fruit = "Monster Fruit" + salal_berry = "Salal Berry" class SVEVegetable: monster_mushroom = "Monster Mushroom" void_root = "Void Root" + ancient_fiber = "Ancient Fiber" diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index d05a9b8515a0..c7b110d19f7a 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -86,3 +86,17 @@ class Beverage: triple_shot_espresso = "Triple Shot Espresso" beer = "Beer" joja_cola = "Joja Cola" + + +class SVEMeal: + baked_berry_oatmeal = "Baked Berry Oatmeal" + big_bark_burger = "Big Bark Burger" + flower_cookie = "Flower Cookie" + frog_legs = "Frog Legs" + glazed_butterfish = "Glazed Butterfish" + mixed_berry_pie = "Mixed Berry Pie" + mushroom_berry_rice = "Mushroom Berry Rice" + seaweed_salad = "Seaweed Salad" + void_delight = "Void Delight" + void_salmon_sushi = "Void Salmon Sushi" + diff --git a/worlds/stardew_valley/strings/forageable_names.py b/worlds/stardew_valley/strings/forageable_names.py index 163ce7ab5d61..9e40e62cb7de 100644 --- a/worlds/stardew_valley/strings/forageable_names.py +++ b/worlds/stardew_valley/strings/forageable_names.py @@ -38,3 +38,20 @@ class SVEForage: swirl_stone = "Swirl Stone" void_pebble = "Void Pebble" void_soul = "Void Soul" + ferngill_primrose = "Ferngill Primrose" + goldenrod = "Goldenrod" + winter_star_rose = "Winter Star Rose" + bearberry = "Bearberry" + poison_mushroom = "Poison Mushroom" + red_baneberry = "Red Baneberry" + big_conch = "Big Conch" + dewdrop_berry = "Dewdrop Berry" + dried_sand_dollar = "Dried Sand Dollar" + golden_ocean_flower = "Golden Ocean Flower" + lucky_four_leaf_clover = "Lucky Four Leaf Clover" + mushroom_colony = "Mushroom Colony" + poison_mushroom = "Poison Mushroom" + rusty_blade = "Rusty Blade" + smelly_rafflesia = "Smelly Rafflesia" + thistle = "Thistle" + diff --git a/worlds/stardew_valley/strings/gift_names.py b/worlds/stardew_valley/strings/gift_names.py index 9988dbe96559..9362f453cfea 100644 --- a/worlds/stardew_valley/strings/gift_names.py +++ b/worlds/stardew_valley/strings/gift_names.py @@ -7,3 +7,8 @@ class Gift: tea_set = "Tea Set" void_ghost_pendant = "Void Ghost Pendant" wilted_bouquet = "Wilted Bouquet" + + +class SVEGift: + blue_moon_wine = "Blue Moon Wine" + aged_blue_moon_wine = "Aged Blue Moon Wine" diff --git a/worlds/stardew_valley/strings/monster_drop_names.py b/worlds/stardew_valley/strings/monster_drop_names.py index 9f370829afbe..5f1830d595a0 100644 --- a/worlds/stardew_valley/strings/monster_drop_names.py +++ b/worlds/stardew_valley/strings/monster_drop_names.py @@ -7,11 +7,6 @@ class Loot: class ModLoot: - void_root = "Void Root" - monster_fruit = "Monster Fruit" - slime_berry = "Slime Berry" - monster_mushroom = "Monster Mushroom" - stalk_seed = "Stalk Seed" - fungus_seed = "Fungus Seed" - slime_seed = "Slime Seed" - void_seed = "Void Seed" + void_shard = "Void Shard" + green_mushroom = "Green Mushroom" + diff --git a/worlds/stardew_valley/strings/seed_names.py b/worlds/stardew_valley/strings/seed_names.py index d29810ad26d6..444d3e258515 100644 --- a/worlds/stardew_valley/strings/seed_names.py +++ b/worlds/stardew_valley/strings/seed_names.py @@ -21,3 +21,10 @@ class TreeSeed: pine = "Pine Cone" mahogany = "Mahogany Seed" mushroom = "Mushroom Tree Seed" + + +class SVESeed: + stalk_seed = "Stalk Seed" + fungus_seed = "Fungus Seed" + slime_seed = "Slime Seed" + void_seed = "Void Seed" From f3fa5cfc9e3811d91d141507a85d9206c531b5ee Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 12 Nov 2023 11:04:54 -0600 Subject: [PATCH 131/482] Add SVE Recipes, fix rules --- worlds/stardew_valley/data/items.csv | 19 +++-- worlds/stardew_valley/data/locations.csv | 85 ++++++++++++++--------- worlds/stardew_valley/data/recipe_data.py | 48 +++++++++---- worlds/stardew_valley/items.py | 23 ++++-- worlds/stardew_valley/rules.py | 3 + 5 files changed, 121 insertions(+), 57 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 26934610f678..89cd08318f89 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -769,6 +769,16 @@ id,name,classification,groups,mod_name 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator +10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded 10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10503,Iridium Bomb,progression,,Stardew Valley Expanded @@ -780,8 +790,7 @@ id,name,classification,groups,mod_name 10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded 10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded 10511,Fable Reef Portal,progression,"GINGER_ISLAND",Stardew Valley Expanded -10512,Super Starfruit,useful,,Stardew Valley Expanded -10513,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10514,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10515,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10516,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded +10512,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10513,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10514,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10515,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 627182f7ac74..0b71acc3ebbe 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2442,37 +2442,54 @@ id,region,name,tags,mod_name 7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded 7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded 7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded -7601,Bear Shop,Bear: Baked Berry Oatmeal Recipe,MANDATORY,Stardew Valley Expanded -7602,Bear Shop,Bear: Flower Cookie Recipe,MANDATORY,Stardew Valley Expanded -7603,Purple Junimo Shop,Purple Junimo: Super Starfruit,MANDATORY,Stardew Valley Expanded -7604,Alesia Shop,Alesia: Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7605,Issac Shop,Issac: Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7606,Issac Shop,Issac: Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7607,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded -7501,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7502,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded -7503,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded -7504,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded -7505,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7506,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7507,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7508,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -8001,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded -8002,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded -8003,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded -8004,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -8005,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded -8006,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded -8007,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded -8008,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded -8009,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -8010,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -8011,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -8012,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded -8013,Beach,Fishsanity: Starfish,FISHSANITY,Stardew Valley Expanded -8014,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -8015,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded -8016,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded -8017,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded -8018,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded -8019,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded +7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded +7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded +7554,Kitchen,Cook Frog Legs,"COOKSANITY",Stardew Valley Expanded +7555,Kitchen,Cook Glazed Butterfish,"COOKSANITY",Stardew Valley Expanded +7556,Kitchen,Cook Mixed Berry Pie,"COOKSANITY",Stardew Valley Expanded +7557,Kitchen,Cook Mushroom Berry Rice,"COOKSANITY",Stardew Valley Expanded +7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded +7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded +7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded +7601,Bear Shop,Learn Recipe Baked Berry Oatmeal,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7602,Bear Shop,Learn Recipe Flower Cookie,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Learn Recipe Big Bark Burger,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7604,Adventurer's Guild,Learn Recipe Frog Legs,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Learn Recipe Glazed Butterfish,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7606,Saloon,Learn Recipe Mixed Berry Pie,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Learn Recipe Mushroom Berry Rice,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7608,Adventurer's Guild,Learn Recipe Seaweed Salad,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Learn Recipe Void Delight,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7610,Sewer,Learn Recipe Void Salmon Sushi,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7651,Alesia Shop,Purchase Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7652,Issac Shop,Purchase Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Issac Shop,Purchase Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded +7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded +7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded +7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7706,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded +7708,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded +7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded +7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded +7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded +7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded +7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded +7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded +7721,Beach,Fishsanity: Starfish,FISHSANITY,Stardew Valley Expanded +7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded +7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded +7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded +7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded +7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 7dc6e79809d5..8357b3ec8b65 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -1,16 +1,17 @@ -from typing import Dict, List - +from typing import Dict, List, Optional +from ..mods.mod_data import ModNames from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood -from ..strings.crop_names import Fruit, Vegetable -from ..strings.fish_names import Fish, WaterItem +from ..strings.crop_names import Fruit, Vegetable, SVEFruit +from ..strings.fish_names import Fish, SVEFish, WaterItem from ..strings.flower_names import Flower -from ..strings.forageable_names import Forageable +from ..strings.forageable_names import Forageable, SVEForage from ..strings.ingredient_names import Ingredient -from ..strings.food_names import Meal, Beverage +from ..strings.food_names import Meal, SVEMeal, Beverage from ..strings.metal_names import Fossil -from ..strings.region_names import Region +from ..strings.monster_drop_names import Loot +from ..strings.region_names import Region, SVERegion from ..strings.season_names import Season from ..strings.skill_names import Skill from ..strings.villager_names import NPC @@ -21,11 +22,13 @@ class CookingRecipe: meal: str ingredients: Dict[str, int] source: RecipeSource + mod_name: Optional[str] = None - def __init__(self, meal: str, ingredients: Dict[str, int], source: RecipeSource): + def __init__(self, meal: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None): self.meal = meal self.ingredients = ingredients self.source = source + self.mod_name = mod_name def __repr__(self): return f"{self.meal} (Source: {self.source} |" \ @@ -45,9 +48,9 @@ def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int]) return create_recipe(name, ingredients, source) -def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) -> CookingRecipe: +def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe: source = ShopSource(region, price) - return create_recipe(name, ingredients, source) + return create_recipe(name, ingredients, source, mod_name) def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int]) -> CookingRecipe: @@ -65,8 +68,8 @@ def starter_recipe(name: str, ingredients: Dict[str, int]) -> CookingRecipe: return create_recipe(name, ingredients, source) -def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) -> CookingRecipe: - recipe = CookingRecipe(name, ingredients, source) +def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None) -> CookingRecipe: + recipe = CookingRecipe(name, ingredients, source, mod_name) all_cooking_recipes.append(recipe) return recipe @@ -166,4 +169,23 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) trout_soup = queen_of_sauce_recipe(Meal.trout_soup, 1, Season.fall, 14, {Fish.rainbow_trout: 1, WaterItem.green_algae: 1}) vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Vegetable.tomato: 1, Vegetable.beet: 1}) -all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} \ No newline at end of file +baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 12500, {Forageable.salmonberry: 15, Forageable.blackberry: 15, + Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve) +big_bark_burger = shop_recipe(SVEMeal.big_bark_burger, Region.saloon, 5500, {SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, ModNames.sve) +flower_cookie = shop_recipe(SVEMeal.flower_cookie, SVERegion.bear_shop, 8750, {SVEForage.ferngill_primrose: 1, SVEForage.goldenrod: 1, + SVEForage.winter_star_rose: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, + AnimalProduct.large_egg: 1}, ModNames.sve) +frog_legs = shop_recipe(SVEMeal.frog_legs, Region.adventurer_guild, 2000, {SVEFish.frog: 1, Ingredient.oil: 1, Ingredient.wheat_flour: 1}, ModNames.sve) +glazed_butterfish = shop_recipe(SVEMeal.glazed_butterfish, Region.saloon, 4000, {SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, + ModNames.sve) +mixed_berry_pie = shop_recipe(SVEMeal.mixed_berry_pie, Region.saloon, 3500, {Fruit.strawberry: 6, SVEFruit.salal_berry: 6, Forageable.blackberry: 6, + SVEForage.bearberry: 6, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}, + ModNames.sve) +mushroom_berry_rice = shop_recipe(SVEMeal.mushroom_berry_rice, Region.adventurer_guild, 1500, {SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, + Ingredient.rice: 1, Ingredient.sugar: 2}, ModNames.sve) +seaweed_salad = shop_recipe(SVEMeal.seaweed_salad, Region.fish_shop, 1250, {SVEFish.dulse_seaweed: 2, WaterItem.seaweed: 2, Ingredient.oil: 1}, ModNames.sve) +void_delight = shop_recipe(SVEMeal.void_delight, Region.sewer, 5000, {SVEFish.void_eel: 1, Loot.void_essence: 50, Loot.solar_essence: 20}, ModNames.sve) +void_salmon_sushi = shop_recipe(SVEMeal.void_salmon_sushi, Region.sewer, 5000, {Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, + ModNames.sve) + +all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index e6bf8fd1d35a..784b9ae4a23c 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -637,11 +637,24 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options return items -def remove_excluded_items(packs, exclude_ginger_island: bool): - included_packs = [pack for pack in packs if Group.DEPRECATED not in pack.groups] - if exclude_ginger_island: - included_packs = [pack for pack in included_packs if Group.GINGER_ISLAND not in pack.groups] - return included_packs +def filter_deprecated_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: + return [item for item in items if Group.DEPRECATED not in item.groups] + + +def filter_ginger_island_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: + include_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false + return [item for item in items if include_island or Group.GINGER_ISLAND not in item.groups] + + +def filter_mod_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: + return [item for item in items if item.mod_name is None or item.mod_name in options.mods] + + +def remove_excluded_items(packs, options): + deprecated_filter = filter_deprecated_items(options, packs) + ginger_island_filter = filter_ginger_island_items(options, deprecated_filter) + mod_filter = filter_mod_items(options, ginger_island_filter) + return mod_filter def remove_limited_amount_packs(packs): diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index ac89e1d0cf02..46178c8e7acb 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -943,6 +943,9 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.quest.can_complete_quest(ModQuest.GrandpasShed).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), + (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe,ToolMaterial.basic) & + logic.tool.has_tool(Tool.pickaxe,ToolMaterial.basic)).simplify) for location in logic.mod.sve.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), logic.mod.sve.sve_location_rules[location].simplify()) From 93e0efb06888f6a29f6c6e24ea3a80f5b9c37da4 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 12:18:31 -0500 Subject: [PATCH 132/482] - Added filtering for gourmet chef recipes based on mod state # Conflicts: # worlds/stardew_valley/logic/logic.py --- worlds/stardew_valley/logic/cooking_logic.py | 20 +++++++++++++------- worlds/stardew_valley/logic/logic.py | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index b8871cec7bf0..c5995362e422 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -8,7 +8,7 @@ from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic -from ..options import ExcludeGingerIsland +from ..options import ExcludeGingerIsland, Mods from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe, \ all_cooking_recipes_by_name from ..data.recipe_source import CutsceneSource, ShopTradeSource @@ -22,6 +22,7 @@ class CookingLogic: player: int + mods: Mods chefsanity_option: Chefsanity exclude_ginger_island: ExcludeGingerIsland received: ReceivedLogic @@ -35,9 +36,10 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + def __init__(self, player: int, mods: Mods, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player + self.mods = mods self.chefsanity_option = chefsanity_option self.exclude_ginger_island = exclude_ginger_island self.received = received @@ -107,9 +109,13 @@ def received_recipe(self, meal_name: str): def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " - all_recipes_to_cook = [] - include_island = self.exclude_ginger_island == ExcludeGingerIsland.option_false + all_recipes_names = [] + exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true for location in locations_by_tag[LocationTags.COOKSANITY]: - if include_island or LocationTags.GINGER_ISLAND not in location.tags: - all_recipes_to_cook.append(location.name[len(cooksanity_prefix):]) - return And([self.can_cook(all_cooking_recipes_by_name[recipe_name]) for recipe_name in all_recipes_to_cook]) + if exclude_island and LocationTags.GINGER_ISLAND in location.tags: + continue + if location.mod_name and location.mod_name not in self.mods: + continue + all_recipes_names.append(location.name[len(cooksanity_prefix):]) + all_recipes = [all_cooking_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] + return And([self.can_cook(recipe) for recipe in all_recipes]) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index b20775cc6ef1..75e9c4d81d16 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -136,7 +136,7 @@ def __post_init__(self): self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.options.chefsanity, self.options.exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.cooking = CookingLogic(self.player, mods_option, self.options.chefsanity, self.options.exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, From 43f7ceb07086fc852353a2ff5bb7c4e4fa0139b3 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 12:35:56 -0500 Subject: [PATCH 133/482] - Fix syntax error --- worlds/stardew_valley/rules.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 46178c8e7acb..506b586d7f4e 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -911,8 +911,6 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.received("Abandoned House Outskirts Clean-up").simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), logic.received("Iridium Bomb").simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), - logic.quest.can_complete_quest(Quest.strange_note).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), logic.mod.sve.has_any_rune().simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), @@ -944,8 +942,8 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron).simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), - (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe,ToolMaterial.basic) & - logic.tool.has_tool(Tool.pickaxe,ToolMaterial.basic)).simplify) + (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic)).simplify()) for location in logic.mod.sve.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), logic.mod.sve.sve_location_rules[location].simplify()) From 573afa9c40a8d3ab3288fb21a85d5e687451b6bb Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 12 Nov 2023 12:00:21 -0600 Subject: [PATCH 134/482] Add Recipe Rules --- worlds/stardew_valley/mods/logic/item_logic.py | 17 ++++++++++++++--- worlds/stardew_valley/mods/logic/mod_logic.py | 2 +- worlds/stardew_valley/strings/seed_names.py | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 90ae0f56153f..c160816a8f13 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -2,6 +2,7 @@ from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic +from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogic from ...logic.money_logic import MoneyLogic from ...logic.region_logic import RegionLogic @@ -18,13 +19,14 @@ from ...strings.monster_drop_names import ModLoot from ...strings.season_names import Season from ...strings.seed_names import SVESeed -from ...strings.region_names import SVERegion +from ...strings.region_names import Region, SVERegion from ...stardew_rule import StardewRule class ModItemLogic: mods: Mods combat: CombatLogic + crop: CropLogic cooking: CookingLogic has: HasLogic money: MoneyLogic @@ -34,9 +36,10 @@ class ModItemLogic: received: ReceivedLogic tool: ToolLogic - def __init__(self, mods: Mods, combat: CombatLogic, cooking: CookingLogic, has: HasLogic, money: MoneyLogic, region: RegionLogic, + def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogic, money: MoneyLogic, region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, tool: ToolLogic): self.combat = combat + self.crop = crop self.cooking = cooking self.mods = mods self.has = has @@ -69,4 +72,12 @@ def _get_sve_item_rules(self): SVEVegetable.void_root: self.season.has(Season.winter) & self.has(SVESeed.void_seed), SVESeed.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & self.cooking.can_cook(), - } + SVEForage.winter_star_rose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.winter), + SVEForage.bearberry: self.region.can_reach(Region.secret_woods) & self.season.has(Season.winter), + SVEForage.poison_mushroom: self.region.can_reach(Region.secret_woods) & (self.season.has(Season.summer) | self.season.has(Season.fall)), + SVEForage.red_baneberry: self.region.can_reach(Region.secret_woods) & self.season.has(Season.summer), + SVEForage.ferngill_primrose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.spring), + SVEForage.goldenrod: self.region.can_reach(SVERegion.summit) & (self.season.has(Season.summer) | self.season.has(Season.fall)), + SVESeed.shrub_seed: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.hoe, ToolMaterial.basic), + SVEFruit.salal_berry: self.crop.can_plant_and_grow_item([Season.spring,Season.summer]) & self.has(SVESeed.shrub_seed), + } diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 83b2002725a0..12c236fa9fcb 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -49,7 +49,7 @@ def __init__(self, player: int, skill_option: SkillProgression, elevator_option: action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): - self.item = ModItemLogic(mods,combat, cooking, has, money, region, season, relationship, tool) + self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, tool) self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) self.buildings = ModBuildingLogic(player, has, money, mods) diff --git a/worlds/stardew_valley/strings/seed_names.py b/worlds/stardew_valley/strings/seed_names.py index 444d3e258515..2d5362c2337e 100644 --- a/worlds/stardew_valley/strings/seed_names.py +++ b/worlds/stardew_valley/strings/seed_names.py @@ -28,3 +28,5 @@ class SVESeed: fungus_seed = "Fungus Seed" slime_seed = "Slime Seed" void_seed = "Void Seed" + shrub_seed = "Shrub Seed" + ancient_fern_seed = "Ancient Fern Seed" From b5fb88c6ee4d12edaf8593c7d56adc376922d26d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 12 Nov 2023 22:19:24 -0500 Subject: [PATCH 135/482] Fix more conflicts related problems # Conflicts: # worlds/stardew_valley/test/__init__.py --- .../stardew_valley/mods/logic/quests_logic.py | 4 +- .../stardew_valley/mods/logic/skills_logic.py | 6 +- worlds/stardew_valley/test/__init__.py | 147 ++---------------- 3 files changed, 18 insertions(+), 139 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 1781b6bc744e..24dc9e014d2d 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -72,8 +72,8 @@ def _get_ayeisha_quest_rules(self): return {} return { - ModQuest.AyeishaEnvelope: (self.season.has(Season.spring) | self.season.has(Season.fall)) & self.region.can_reach(Region.mountain), - ModQuest.AyeishaRing: self.season.has(Season.winter) & self.region.can_reach(Region.forest) + ModQuest.AyeishaEnvelope: (self.season.has(Season.spring) | self.season.has(Season.fall)), + ModQuest.AyeishaRing: self.season.has(Season.winter) } def _get_sve_quest_rules(self): diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index ff973c31fe83..252c52d5b16f 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -91,7 +91,7 @@ def can_earn_magic_skill_level(self, level: int) -> StardewRule: self.received(MagicSpell.shockwave), self.received(MagicSpell.meteor), self.received(MagicSpell.spirit)] - return self.magic.can_use_altar() & Count(level, spell_count) + return Count(level, spell_count) def can_earn_socializing_skill_level(self, level: int) -> StardewRule: villager_count = [] @@ -115,6 +115,6 @@ def can_earn_cooking_skill_level(self, level: int) -> StardewRule: def can_earn_binning_skill_level(self, level: int) -> StardewRule: if level >= 6: - return self.region.can_reach(Region.town) & self.has(Machine.recycling_machine) + return self.has(Machine.recycling_machine) else: - return self.region.can_reach(Region.town) | self.has(Machine.recycling_machine) + return True_() # You can always earn levels 1-5 with trash cans diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index d4346372152a..f8a81d538ce8 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -8,7 +8,7 @@ from test.TestBase import WorldTestBase from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld from .. import StardewValleyWorld -from ..mods.mod_data import ModNames +from ..mods.mod_data import ModNames, all_mods from worlds.AutoWorld import call_all from ..options import Cropsanity, SkillProgression, SpecialOrderLocations, Friendsanity, NumberOfLuckBuffs, SeasonRandomization, ToolProgression, \ ElevatorProgression, Museumsanity, BackpackProgression, BuildingProgression, ArcadeMachineLocations, HelpWantedLocations, Fishsanity, NumberOfMovementBuffs, \ @@ -16,6 +16,13 @@ Cooksanity, Chefsanity, Craftsanity +@cache_argsless +def default_options(): + default = {} + return default + + +@cache_argsless def get_minsanity_options(): minsanity = { Goal.internal_name: Goal.option_bottom_of_the_mines, @@ -50,6 +57,7 @@ def get_minsanity_options(): return minsanity +@cache_argsless def minimal_locations_maximal_items(): min_max_options = { Goal.internal_name: Goal.option_bottom_of_the_mines, @@ -81,6 +89,7 @@ def minimal_locations_maximal_items(): return min_max_options +@cache_argsless def allsanity_options_without_mods(): allsanity = { Goal.internal_name: Goal.option_perfection, @@ -114,23 +123,15 @@ def allsanity_options_without_mods(): return allsanity +@cache_argsless def allsanity_options_with_mods(): allsanity = {} allsanity.update(allsanity_options_without_mods()) - all_mods = ( - ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, - ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, - ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, - ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, - ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, - ModNames.sve - ) allsanity.update({Mods.internal_name: all_mods}) return allsanity -class SVTestBase(WorldTestBase): +class SVTestCase(WorldTestBase): game = "Stardew Valley" world: StardewValleyWorld player: ClassVar[int] = 1 @@ -154,8 +155,6 @@ def setUp(self) -> None: class SVTestBase(WorldTestBase, SVTestCase): - game = "Stardew Valley" - world: StardewValleyWorld def world_setup(self, *args, **kwargs): super().world_setup(*args, **kwargs) @@ -172,126 +171,6 @@ def run_default_tests(self) -> bool: return should_run_default_tests -@cache_argsless -def minimal_locations_maximal_items(): - min_max_options = { - Goal.internal_name: Goal.option_bottom_of_the_mines, - BundleRandomization.internal_name: BundleRandomization.option_vanilla, - BundlePrice.internal_name: BundlePrice.option_very_cheap, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_vanilla, - ToolProgression.internal_name: ToolProgression.option_vanilla, - SkillProgression.internal_name: SkillProgression.option_vanilla, - BuildingProgression.internal_name: BuildingProgression.option_vanilla, - FestivalLocations.internal_name: FestivalLocations.option_disabled, - ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: 0, - Fishsanity.internal_name: Fishsanity.option_none, - Museumsanity.internal_name: Museumsanity.option_none, - Monstersanity.internal_name: Monstersanity.option_none, - Shipsanity.internal_name: Shipsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_none, - FriendsanityHeartSize.internal_name: 8, - NumberOfMovementBuffs.internal_name: 12, - NumberOfLuckBuffs.internal_name: 12, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - TrapItems.internal_name: TrapItems.option_nightmare, - Mods.internal_name: (), - } - return min_max_options - - -@cache_argsless -def minsanity_options(): - minsanity = { - Goal.internal_name: Goal.option_bottom_of_the_mines, - BundleRandomization.internal_name: BundleRandomization.option_vanilla, - BundlePrice.internal_name: BundlePrice.option_very_cheap, - SeasonRandomization.internal_name: SeasonRandomization.option_disabled, - Cropsanity.internal_name: Cropsanity.option_disabled, - BackpackProgression.internal_name: BackpackProgression.option_vanilla, - ToolProgression.internal_name: ToolProgression.option_vanilla, - SkillProgression.internal_name: SkillProgression.option_vanilla, - BuildingProgression.internal_name: BuildingProgression.option_vanilla, - FestivalLocations.internal_name: FestivalLocations.option_disabled, - ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: 0, - Fishsanity.internal_name: Fishsanity.option_none, - Museumsanity.internal_name: Museumsanity.option_none, - Monstersanity.internal_name: Monstersanity.option_none, - Shipsanity.internal_name: Shipsanity.option_none, - Friendsanity.internal_name: Friendsanity.option_none, - FriendsanityHeartSize.internal_name: 8, - NumberOfMovementBuffs.internal_name: 0, - NumberOfLuckBuffs.internal_name: 0, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, - TrapItems.internal_name: TrapItems.option_no_traps, - Mods.internal_name: (), - } - return minsanity - - -@cache_argsless -def default_options(): - default = {} - return default - - -@cache_argsless -def allsanity_options_without_mods(): - allsanity = { - Goal.internal_name: Goal.option_perfection, - BundleRandomization.internal_name: BundleRandomization.option_thematic, - BundlePrice.internal_name: BundlePrice.option_expensive, - SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, - BackpackProgression.internal_name: BackpackProgression.option_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, - SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive, - FestivalLocations.internal_name: FestivalLocations.option_hard, - ElevatorProgression.internal_name: ElevatorProgression.option_progressive, - ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, - SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - HelpWantedLocations.internal_name: 56, - Fishsanity.internal_name: Fishsanity.option_all, - Museumsanity.internal_name: Museumsanity.option_all, - Monstersanity.internal_name: Monstersanity.option_progressive_goals, - Shipsanity.internal_name: Shipsanity.option_everything, - Cooksanity.internal_name: Cooksanity.option_all, - Chefsanity.internal_name: Chefsanity.option_all, - Craftsanity.internal_name: Craftsanity.option_all, - Friendsanity.internal_name: Friendsanity.option_all_with_marriage, - FriendsanityHeartSize.internal_name: 1, - NumberOfMovementBuffs.internal_name: 12, - NumberOfLuckBuffs.internal_name: 12, - ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, - TrapItems.internal_name: TrapItems.option_nightmare, - } - return allsanity - - -@cache_argsless -def allsanity_options_with_mods(): - allsanity = {} - allsanity.update(allsanity_options_without_mods()) - all_mods = ( - ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, - ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, - ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, - ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, - ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator - ) - allsanity.update({Mods.internal_name: all_mods}) - return allsanity - - pre_generated_worlds = {} @@ -330,9 +209,9 @@ def setup_multiworld(test_options: Iterable[Dict[str, int]] = None, seed=None) - multiworld.set_seed(seed) multiworld.state = CollectionState(multiworld) for i in range(1, len(test_options) + 1): - args = Namespace() multiworld.game[i] = StardewValleyWorld.game multiworld.player_name.update({i: f"Tester{i}"}) + args = Namespace() for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): options = {} for i in range(1, len(test_options) + 1): From e79dc69d1d7e00ba1eff06def27690929f474a2a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 17:26:54 -0500 Subject: [PATCH 136/482] - Added caching everywhere with a decorator # Conflicts: # worlds/stardew_valley/logic/logic.py --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/data/locations.csv | 1244 ++++++++--------- worlds/stardew_valley/items.py | 9 +- worlds/stardew_valley/logic/action_logic.py | 10 +- worlds/stardew_valley/logic/building_logic.py | 8 +- worlds/stardew_valley/logic/cached_logic.py | 29 + worlds/stardew_valley/logic/combat_logic.py | 53 +- worlds/stardew_valley/logic/cooking_logic.py | 15 +- worlds/stardew_valley/logic/crop_logic.py | 46 +- worlds/stardew_valley/logic/fishing_logic.py | 51 +- worlds/stardew_valley/logic/gift_logic.py | 12 +- worlds/stardew_valley/logic/has_logic.py | 12 +- worlds/stardew_valley/logic/logic.py | 117 +- worlds/stardew_valley/logic/logic_cache.py | 41 + worlds/stardew_valley/logic/mine_logic.py | 57 +- worlds/stardew_valley/logic/money_logic.py | 14 +- worlds/stardew_valley/logic/museum_logic.py | 16 +- worlds/stardew_valley/logic/pet_logic.py | 11 +- worlds/stardew_valley/logic/quest_logic.py | 44 +- worlds/stardew_valley/logic/received_logic.py | 10 +- worlds/stardew_valley/logic/region_logic.py | 46 +- .../logic/relationship_logic.py | 30 +- worlds/stardew_valley/logic/season_logic.py | 45 +- worlds/stardew_valley/logic/skill_logic.py | 32 +- .../logic/special_order_logic.py | 32 +- worlds/stardew_valley/logic/time_logic.py | 10 +- worlds/stardew_valley/logic/tool_logic.py | 14 +- .../logic/traveling_merchant_logic.py | 20 + worlds/stardew_valley/logic/wallet_logic.py | 2 +- worlds/stardew_valley/regions.py | 5 +- worlds/stardew_valley/rules.py | 77 +- worlds/stardew_valley/stardew_rule.py | 3 +- .../strings/wallet_item_names.py | 1 + worlds/stardew_valley/test/TestGeneration.py | 87 +- worlds/stardew_valley/test/TestRules.py | 2 +- worlds/stardew_valley/test/__init__.py | 4 +- .../test/checks/option_checks.py | 2 +- .../test/long/TestOptionsLong.py | 2 +- .../test/long/TestRandomWorlds.py | 2 +- worlds/stardew_valley/test/mods/TestMods.py | 4 +- 40 files changed, 1187 insertions(+), 1034 deletions(-) create mode 100644 worlds/stardew_valley/logic/cached_logic.py create mode 100644 worlds/stardew_valley/logic/logic_cache.py create mode 100644 worlds/stardew_valley/logic/traveling_merchant_logic.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 3ab556bd9975..c7ac15e2c9db 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -196,7 +196,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_bottom_of_the_mines: self.create_event_location(location_table[GoalName.bottom_of_the_mines], - self.logic.mine.can_mine_to_floor(120).simplify(), + True_(), Event.victory) elif self.options.goal == Goal.option_cryptic_note: self.create_event_location(location_table[GoalName.cryptic_note], diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 0b71acc3ebbe..f4197d1dd6b1 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -38,26 +38,26 @@ id,region,name,tags,mod_name 37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", 101,Pierre's General Store,Large Pack,BACKPACK, 102,Pierre's General Store,Deluxe Pack,BACKPACK, -103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", 123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", 124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", 125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", @@ -100,56 +100,56 @@ id,region,name,tags,mod_name 236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, 237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, 251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", -301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", -302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", -303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", -304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", -305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", -306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", -307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", -308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", -309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", -310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", -311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", -332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", -333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", -334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", -335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", -336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", -337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", -338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", -339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", -340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", -341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", +302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", +303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", +304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", +305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", +306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", +307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", +308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", +309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", +310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", +311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", +332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", +333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", +334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", +335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", +336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", +337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", +338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", +339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", +340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", +341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", 401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, 402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, 403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, @@ -175,45 +175,45 @@ id,region,name,tags,mod_name 505,Farm,Advancement,"MANDATORY,QUEST", 506,Museum,Archaeology,"MANDATORY,QUEST", 507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", -508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", -509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", -510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", +508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", +509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", +510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", 511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", 512,Sam's House,Jodi's Request,"MANDATORY,QUEST", 513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", 514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", 515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", -516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", +516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", 517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", 518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", 519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", -520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", -521,Alex's House,Knee Therapy,"MANDATORY,QUEST", -522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", -523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", +520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", +521,Alex's House,Knee Therapy,"MANDATORY,QUEST", +522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", 524,Desert,The Mysterious Qi,"MANDATORY,QUEST", -525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", +525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", 526,Town,A Winter Mystery,"MANDATORY,QUEST", 527,Secret Woods,Strange Note,"MANDATORY,QUEST", -528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", -529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", -530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", -531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", -532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", +529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", +530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", +531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", +532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", 533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", -534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", +534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", 535,Sam's House,Fish Casserole,"MANDATORY,QUEST", -536,Fishing,Catch A Squid,"MANDATORY,QUEST", +536,Fishing,Catch A Squid,"MANDATORY,QUEST", 537,Saloon,Fish Stew,"MANDATORY,QUEST", -538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", -539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", -540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", +538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", +539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", +540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", 541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", -542,Alex's House,Granny's Gift,"MANDATORY,QUEST", -543,Desert,Exotic Spirits,"MANDATORY,QUEST", -544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", +542,Alex's House,Granny's Gift,"MANDATORY,QUEST", +543,Desert,Exotic Spirits,"MANDATORY,QUEST", +544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", 545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Railroad,Dark Talisman,"MANDATORY,QUEST", +546,Mutant Bug Lair,Dark Talisman,"MANDATORY,QUEST", 547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", 548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", 601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", @@ -242,30 +242,30 @@ id,region,name,tags,mod_name 703,Desert,Galaxy Sword Shrine,MANDATORY, 704,Farmhouse,Have a Baby,MANDATORY, 705,Farmhouse,Have Another Baby,MANDATORY, -801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, -802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, -803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, -804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, -805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, -806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, -807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, -808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, -811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, -821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, -822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, -823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, -824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, -825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, -826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, -827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, -828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, +801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, +802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, +803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, +804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, +805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, +806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, +807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, +808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, +811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, +812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, +821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, +822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, +823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, +824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, +825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, +826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, +827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, +828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, 841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, 842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, 843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, @@ -298,82 +298,82 @@ id,region,name,tags,mod_name 870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, 871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, 872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, -901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", -902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", -903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", -911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", -912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", -913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", -921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", -942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", -943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", -951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", -952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", -953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", -961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", -962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", -963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", -1001,Fishing,Fishsanity: Carp,FISHSANITY, -1002,Fishing,Fishsanity: Herring,FISHSANITY, -1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, -1004,Fishing,Fishsanity: Anchovy,FISHSANITY, -1005,Fishing,Fishsanity: Sardine,FISHSANITY, -1006,Fishing,Fishsanity: Sunfish,FISHSANITY, -1007,Fishing,Fishsanity: Perch,FISHSANITY, -1008,Fishing,Fishsanity: Chub,FISHSANITY, -1009,Fishing,Fishsanity: Bream,FISHSANITY, -1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, -1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, -1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, -1013,Fishing,Fishsanity: Walleye,FISHSANITY, -1014,Fishing,Fishsanity: Shad,FISHSANITY, -1015,Fishing,Fishsanity: Bullhead,FISHSANITY, -1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, -1017,Fishing,Fishsanity: Salmon,FISHSANITY, -1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, -1019,Fishing,Fishsanity: Tilapia,FISHSANITY, -1020,Fishing,Fishsanity: Woodskip,FISHSANITY, -1021,Fishing,Fishsanity: Flounder,FISHSANITY, -1022,Fishing,Fishsanity: Halibut,FISHSANITY, -1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", -1024,Fishing,Fishsanity: Slimejack,FISHSANITY, -1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, -1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, -1027,Fishing,Fishsanity: Pike,FISHSANITY, -1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, -1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", -1030,Fishing,Fishsanity: Albacore,FISHSANITY, -1031,Fishing,Fishsanity: Sandfish,FISHSANITY, -1032,Fishing,Fishsanity: Stonefish,FISHSANITY, -1033,Fishing,Fishsanity: Tuna,FISHSANITY, -1034,Fishing,Fishsanity: Eel,FISHSANITY, -1035,Fishing,Fishsanity: Catfish,FISHSANITY, -1036,Fishing,Fishsanity: Squid,FISHSANITY, -1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, -1038,Fishing,Fishsanity: Dorado,FISHSANITY, -1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, -1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, -1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, -1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", -1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, -1044,Fishing,Fishsanity: Lingcod,FISHSANITY, +901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", +902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", +903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", +911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", +912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", +913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", +921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", +942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", +943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", +951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", +952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", +953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", +961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", +962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", +963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", +1001,Fishing,Fishsanity: Carp,FISHSANITY, +1002,Fishing,Fishsanity: Herring,FISHSANITY, +1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, +1004,Fishing,Fishsanity: Anchovy,FISHSANITY, +1005,Fishing,Fishsanity: Sardine,FISHSANITY, +1006,Fishing,Fishsanity: Sunfish,FISHSANITY, +1007,Fishing,Fishsanity: Perch,FISHSANITY, +1008,Fishing,Fishsanity: Chub,FISHSANITY, +1009,Fishing,Fishsanity: Bream,FISHSANITY, +1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, +1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, +1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, +1013,Fishing,Fishsanity: Walleye,FISHSANITY, +1014,Fishing,Fishsanity: Shad,FISHSANITY, +1015,Fishing,Fishsanity: Bullhead,FISHSANITY, +1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, +1017,Fishing,Fishsanity: Salmon,FISHSANITY, +1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, +1019,Fishing,Fishsanity: Tilapia,FISHSANITY, +1020,Fishing,Fishsanity: Woodskip,FISHSANITY, +1021,Fishing,Fishsanity: Flounder,FISHSANITY, +1022,Fishing,Fishsanity: Halibut,FISHSANITY, +1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", +1024,Fishing,Fishsanity: Slimejack,FISHSANITY, +1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, +1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, +1027,Fishing,Fishsanity: Pike,FISHSANITY, +1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, +1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", +1030,Fishing,Fishsanity: Albacore,FISHSANITY, +1031,Fishing,Fishsanity: Sandfish,FISHSANITY, +1032,Fishing,Fishsanity: Stonefish,FISHSANITY, +1033,Fishing,Fishsanity: Tuna,FISHSANITY, +1034,Fishing,Fishsanity: Eel,FISHSANITY, +1035,Fishing,Fishsanity: Catfish,FISHSANITY, +1036,Fishing,Fishsanity: Squid,FISHSANITY, +1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, +1038,Fishing,Fishsanity: Dorado,FISHSANITY, +1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, +1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, +1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, +1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", +1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, +1044,Fishing,Fishsanity: Lingcod,FISHSANITY, 1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, -1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, -1047,Fishing,Fishsanity: Octopus,FISHSANITY, -1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, -1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, -1050,Fishing,Fishsanity: Blobfish,FISHSANITY, -1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, -1052,Fishing,Fishsanity: Angler,FISHSANITY, -1053,Fishing,Fishsanity: Legend,FISHSANITY, -1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, -1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, +1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, +1047,Fishing,Fishsanity: Octopus,FISHSANITY, +1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, +1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, +1050,Fishing,Fishsanity: Blobfish,FISHSANITY, +1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, +1052,Fishing,Fishsanity: Angler,FISHSANITY, +1053,Fishing,Fishsanity: Legend,FISHSANITY, +1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, +1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, 1056,Town,Fishsanity: Crayfish,FISHSANITY, 1057,Town,Fishsanity: Snail,FISHSANITY, 1058,Town,Fishsanity: Periwinkle,FISHSANITY, @@ -597,62 +597,62 @@ id,region,name,tags,mod_name 1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, 1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, 1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, -1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, -1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, -1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, -1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, -1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, -1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, -1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, -1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, -1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, -1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, -1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, -1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, -1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, -1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, -1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, -1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, -1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, -1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, -1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, -1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, -1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, -1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, -1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, -1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, -1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, -1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, -1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, -1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, -1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, -1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, -1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, -1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, -1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, -1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, -1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, -1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, -1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, -1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, -1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, -1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, -1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, -1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, -1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, -1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, -1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, -1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, -1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, -1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, -1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, -1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, -1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, -1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, -1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, -1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, -1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, -1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, +1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, +1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, +1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, +1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, +1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, +1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, +1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, +1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, +1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, +1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, +1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, +1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, +1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, +1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, +1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, +1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, +1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, +1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, +1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, +1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, +1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, +1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, +1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, +1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, +1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, +1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, +1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, +1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, +1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, +1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, +1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, +1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, +1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, +1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, +1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, +1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, +1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, +1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, +1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, +1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, +1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, +1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, +1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, +1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, +1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, +1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, +1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, +1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, +1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, +1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, +1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, +1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, +1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, +1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, +1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, +1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, 1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, 1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, 1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, @@ -667,40 +667,40 @@ id,region,name,tags,mod_name 1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, 1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, 1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, -1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, -1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, -1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, -1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, -1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, -1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, -1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, -1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, -1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, -1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, -1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, -1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, -1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, -1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, -1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, -1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, -1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, -1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, -1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, -1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, -1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, -1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, -1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, -1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, -1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, -1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, -1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, -1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, -1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, -1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, -1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, -1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, -1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, -1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, +1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, +1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, +1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, +1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, +1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, +1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, +1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, +1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, +1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, +1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, +1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, +1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, +1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, +1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, +1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, +1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, +1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, +1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, +1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, +1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, +1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, +1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, +1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, +1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, +1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, +1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, +1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, +1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, +1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, +1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, +1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, +1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, +1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, +1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, 1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, 1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, 1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, @@ -711,46 +711,46 @@ id,region,name,tags,mod_name 1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, 1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, 1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, -1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, -1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, -1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, -1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, -1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, -1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, -1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, -1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, -1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, -1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, -1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, -1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, -1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, -1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, -1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, -1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, -1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, -1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, -1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, -1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, -1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, -1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, -1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, -1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, -1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, -1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, -1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, -1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, -1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, -1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, -1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, -1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, -1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, -1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, -1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, -1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, -1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, -1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, -1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, -1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, +1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, +1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, +1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, +1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, +1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, +1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, +1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, +1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, +1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, +1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, +1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, +1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, +1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, +1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, +1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, +1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, +1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, +1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, +1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, +1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, +1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, +1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, +1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, +1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, +1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, +1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, +1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, +1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, +1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, +1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, +1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, +1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, +1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, +1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, +1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, +1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, +1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, +1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, +1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, +1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, 1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, 1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, 1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, @@ -761,26 +761,26 @@ id,region,name,tags,mod_name 1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, 1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, 1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, -1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, -1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, -1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, -1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, -1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, -1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, -1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, -1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, -1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, -1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, -1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, -1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, -1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, -1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, -1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, -1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, -1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, -1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, -1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, -1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, +1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, +1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, +1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, +1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, +1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, +1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, +1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, +1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, +1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, +1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, +1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, +1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, +1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, +1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, +1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, +1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, +1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, +1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, +1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, +1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, 1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY", 1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY", 1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY", @@ -801,26 +801,26 @@ id,region,name,tags,mod_name 1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", 1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", 1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", -1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, -1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, -1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, -1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, -1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, -1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, -1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, -1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, -1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, -1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, -1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, -1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, -1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, -1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, -1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, -1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, -1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, -1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, -1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, -1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, +1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, +1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, +1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, +1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, +1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, +1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, +1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, +1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, +1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, +1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, +1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, +1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, +1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, +1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, +1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, +1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, +1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, +1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, +1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, +1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, 1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, 1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, 1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, @@ -831,26 +831,26 @@ id,region,name,tags,mod_name 1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, 1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, 1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, -1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, -1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, -1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, -1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, -1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, -1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, -1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, -1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, -1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, -1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, -1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, -1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, -1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, -1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, -1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, -1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, -1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, -1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, -1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, -1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, +1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, +1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, +1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, +1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, +1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, +1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, +1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, +1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, +1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, +1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, +1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, +1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, +1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, +1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, +1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, +1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, +1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, +1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, +1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, +1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, 1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, 1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, 1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, @@ -871,36 +871,36 @@ id,region,name,tags,mod_name 1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, 1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, 1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, -1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, -1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, -1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, -1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, -1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, -1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, -1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, -1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, -1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, -1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, -1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, -1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, -1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, -1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, -1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, -1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, -1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, -1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, -1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, -1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, -1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, -1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, -1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, -1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, -1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, -1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, -1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, -1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, -1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, -1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, +1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, +1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, +1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, +1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, +1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, +1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, +1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, +1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, +1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, +1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, +1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, +1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, +1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, +1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, +1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, +1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, +1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, +1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, +1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, +1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, +1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, +1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, +1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, +1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, +1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, +1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, +1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, +1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, +1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, +1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, 1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, 1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, 1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, @@ -956,23 +956,23 @@ id,region,name,tags,mod_name 2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, 2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, -2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, -2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, -2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, -2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, -2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, -2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, -2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, -2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, -2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, -2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, -2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, -2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, +2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, +2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, +2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, +2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, +2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, +2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, +2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, +2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, +2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, +2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, +2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, +2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, +2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, 2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, -2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, +2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, +2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, 2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", 2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", 2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", @@ -999,53 +999,53 @@ id,region,name,tags,mod_name 2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", 2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, 2216,Field Office,Complete Island Field Office,GINGER_ISLAND, -2301,Farming,Harvest Amaranth,"CROPSANITY", -2302,Farming,Harvest Artichoke,"CROPSANITY", -2303,Farming,Harvest Beet,"CROPSANITY", -2304,Farming,Harvest Blue Jazz,"CROPSANITY", -2305,Farming,Harvest Blueberry,"CROPSANITY", -2306,Farming,Harvest Bok Choy,"CROPSANITY", -2307,Farming,Harvest Cauliflower,"CROPSANITY", -2308,Farming,Harvest Corn,"CROPSANITY", -2309,Farming,Harvest Cranberries,"CROPSANITY", -2310,Farming,Harvest Eggplant,"CROPSANITY", -2311,Farming,Harvest Fairy Rose,"CROPSANITY", -2312,Farming,Harvest Garlic,"CROPSANITY", -2313,Farming,Harvest Grape,"CROPSANITY", -2314,Farming,Harvest Green Bean,"CROPSANITY", -2315,Farming,Harvest Hops,"CROPSANITY", -2316,Farming,Harvest Hot Pepper,"CROPSANITY", -2317,Farming,Harvest Kale,"CROPSANITY", -2318,Farming,Harvest Melon,"CROPSANITY", -2319,Farming,Harvest Parsnip,"CROPSANITY", -2320,Farming,Harvest Poppy,"CROPSANITY", -2321,Farming,Harvest Potato,"CROPSANITY", -2322,Farming,Harvest Pumpkin,"CROPSANITY", -2323,Farming,Harvest Radish,"CROPSANITY", -2324,Farming,Harvest Red Cabbage,"CROPSANITY", -2325,Farming,Harvest Rhubarb,"CROPSANITY", -2326,Farming,Harvest Starfruit,"CROPSANITY", -2327,Farming,Harvest Strawberry,"CROPSANITY", -2328,Farming,Harvest Summer Spangle,"CROPSANITY", -2329,Farming,Harvest Sunflower,"CROPSANITY", -2330,Farming,Harvest Tomato,"CROPSANITY", -2331,Farming,Harvest Tulip,"CROPSANITY", -2332,Farming,Harvest Unmilled Rice,"CROPSANITY", -2333,Farming,Harvest Wheat,"CROPSANITY", -2334,Farming,Harvest Yam,"CROPSANITY", -2335,Farming,Harvest Cactus Fruit,"CROPSANITY", -2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", -2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farming,Harvest Sweet Gem Berry,"CROPSANITY", -2339,Farming,Harvest Apple,"CROPSANITY", -2340,Farming,Harvest Apricot,"CROPSANITY", -2341,Farming,Harvest Cherry,"CROPSANITY", -2342,Farming,Harvest Orange,"CROPSANITY", -2343,Farming,Harvest Pomegranate,"CROPSANITY", -2344,Farming,Harvest Peach,"CROPSANITY", -2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", -2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farming,Harvest Coffee Bean,"CROPSANITY", +2301,Farming,Harvest Amaranth,"CROPSANITY", +2302,Farming,Harvest Artichoke,"CROPSANITY", +2303,Farming,Harvest Beet,"CROPSANITY", +2304,Farming,Harvest Blue Jazz,"CROPSANITY", +2305,Farming,Harvest Blueberry,"CROPSANITY", +2306,Farming,Harvest Bok Choy,"CROPSANITY", +2307,Farming,Harvest Cauliflower,"CROPSANITY", +2308,Farming,Harvest Corn,"CROPSANITY", +2309,Farming,Harvest Cranberries,"CROPSANITY", +2310,Farming,Harvest Eggplant,"CROPSANITY", +2311,Farming,Harvest Fairy Rose,"CROPSANITY", +2312,Farming,Harvest Garlic,"CROPSANITY", +2313,Farming,Harvest Grape,"CROPSANITY", +2314,Farming,Harvest Green Bean,"CROPSANITY", +2315,Farming,Harvest Hops,"CROPSANITY", +2316,Farming,Harvest Hot Pepper,"CROPSANITY", +2317,Farming,Harvest Kale,"CROPSANITY", +2318,Farming,Harvest Melon,"CROPSANITY", +2319,Farming,Harvest Parsnip,"CROPSANITY", +2320,Farming,Harvest Poppy,"CROPSANITY", +2321,Farming,Harvest Potato,"CROPSANITY", +2322,Farming,Harvest Pumpkin,"CROPSANITY", +2323,Farming,Harvest Radish,"CROPSANITY", +2324,Farming,Harvest Red Cabbage,"CROPSANITY", +2325,Farming,Harvest Rhubarb,"CROPSANITY", +2326,Farming,Harvest Starfruit,"CROPSANITY", +2327,Farming,Harvest Strawberry,"CROPSANITY", +2328,Farming,Harvest Summer Spangle,"CROPSANITY", +2329,Farming,Harvest Sunflower,"CROPSANITY", +2330,Farming,Harvest Tomato,"CROPSANITY", +2331,Farming,Harvest Tulip,"CROPSANITY", +2332,Farming,Harvest Unmilled Rice,"CROPSANITY", +2333,Farming,Harvest Wheat,"CROPSANITY", +2334,Farming,Harvest Yam,"CROPSANITY", +2335,Farming,Harvest Cactus Fruit,"CROPSANITY", +2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", +2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", +2338,Farming,Harvest Sweet Gem Berry,"CROPSANITY", +2339,Farming,Harvest Apple,"CROPSANITY", +2340,Farming,Harvest Apricot,"CROPSANITY", +2341,Farming,Harvest Cherry,"CROPSANITY", +2342,Farming,Harvest Orange,"CROPSANITY", +2343,Farming,Harvest Pomegranate,"CROPSANITY", +2344,Farming,Harvest Peach,"CROPSANITY", +2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", +2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", +2347,Farming,Harvest Coffee Bean,"CROPSANITY", 2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", @@ -2040,26 +2040,26 @@ id,region,name,tags,mod_name 5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill 5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill 5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill 5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology 5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology 5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology @@ -2080,61 +2080,61 @@ id,region,name,tags,mod_name 5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill 5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill 5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic -5502,Magic Altar,Analyze: Till,MANDATORY,Magic -5503,Magic Altar,Analyze: Water,MANDATORY,Magic -5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic -5505,Magic Altar,Analyze: Evac,MANDATORY,Magic -5506,Magic Altar,Analyze: Haste,MANDATORY,Magic -5507,Magic Altar,Analyze: Heal,MANDATORY,Magic -5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic -5509,Magic Altar,Analyze: Descend,MANDATORY,Magic -5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic -5511,Magic Altar,Analyze: Frostbite,MANDATORY,Magic -5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic -5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic -5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic -5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic -5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic -5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic -5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic -5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic -5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic -5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic -6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas -6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas -6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas -6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas -6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas -6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas -6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas -6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas -6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas -6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas -6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas -6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas -6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas -6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas -6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba -6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba -6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba -6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba -6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba -6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba -6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba -6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba -6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba -6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba -6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) -6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) -6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) -6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) -6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) -6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) -6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) -6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) -6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) -6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) +5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic +5502,Magic Altar,Analyze: Till,MANDATORY,Magic +5503,Magic Altar,Analyze: Water,MANDATORY,Magic +5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic +5505,Magic Altar,Analyze: Evac,MANDATORY,Magic +5506,Magic Altar,Analyze: Haste,MANDATORY,Magic +5507,Magic Altar,Analyze: Heal,MANDATORY,Magic +5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic +5509,Magic Altar,Analyze: Descend,MANDATORY,Magic +5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbite,MANDATORY,Magic +5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic +5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic +5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic +5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic +5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic +5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic +5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic +5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic +5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic +5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic +6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas +6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas +6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas +6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas +6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas +6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas +6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas +6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas +6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas +6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas +6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas +6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas +6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas +6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas +6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba +6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba +6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba +6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba +6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba +6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba +6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba +6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba +6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba +6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba +6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) +6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) +6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) +6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) +6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) +6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) +6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) +6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) +6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) +6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) 6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) @@ -2145,34 +2145,34 @@ id,region,name,tags,mod_name 6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) 6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC -6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC -6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC -6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC -6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC -6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC -6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC -6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC -6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC -6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC -6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC -6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC -6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC -6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC -6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick -6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick -6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick -6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick -6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick -6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick -6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick -6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick -6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick -6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick -6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick -6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick -6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick -6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick +6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC +6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC +6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC +6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC +6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC +6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC +6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC +6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC +6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC +6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC +6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC +6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC +6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC +6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC +6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick +6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick +6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick +6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick +6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick +6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick +6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick +6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick +6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick +6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick +6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick +6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick +6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick +6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick 6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC 6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC 6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC @@ -2187,34 +2187,34 @@ id,region,name,tags,mod_name 6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC 6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC 6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC -6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited -6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited -6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited -6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited -6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited -6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited -6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited -6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited -6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited -6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited -6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited -6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited -6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited -6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited -6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene -6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene -6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene -6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene -6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene -6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene -6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene -6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene -6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene -6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene -6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene -6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene -6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene -6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene +6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited +6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited +6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited +6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited +6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited +6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited +6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited +6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited +6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited +6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited +6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited +6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited +6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited +6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited +6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene +6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene +6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene +6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene +6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene +6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene +6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene +6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene +6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene +6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene +6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene +6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene +6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene +6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene 6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC 6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC 6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC @@ -2225,20 +2225,20 @@ id,region,name,tags,mod_name 6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC 6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC 6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC -6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley -6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley -6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley -6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley -6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley -6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley -6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley -6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley -6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley -6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley -6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley -6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley -6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley -6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley +6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley +6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley +6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley +6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley +6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley +6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley +6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley +6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley +6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley +6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley +6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley +6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley +6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley 6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded 6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded 6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2430,8 +2430,8 @@ id,region,name,tags,mod_name 7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator 7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator 7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) 7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC 7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 784b9ae4a23c..5d44cceef889 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -18,6 +18,7 @@ from .strings.ap_names.buff_names import Buff from .strings.ap_names.event_names import Event from .strings.villager_names import NPC, ModNPC +from .strings.wallet_item_names import Wallet ITEM_CODE_OFFSET = 717000 @@ -342,8 +343,8 @@ def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOpt def create_museum_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - items.append(item_factory("Rusty Key")) - items.append(item_factory("Dwarvish Translation Guide")) + items.append(item_factory(Wallet.rusty_key)) + items.append(item_factory(Wallet.dwarvish_translation_guide)) items.append(item_factory("Ancient Seeds Recipe")) if options.museumsanity == Museumsanity.option_none: return @@ -412,8 +413,8 @@ def create_arcade_machine_items(item_factory: StardewItemFactory, options: Stard def create_player_buffs(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - movement_buffs: int = options.number_of_movement_buffs.value - luck_buffs: int = options.number_of_luck_buffs.value + movement_buffs: int = options.movement_buff_number.value + luck_buffs: int = options.luck_buff_number.value need_all_buffs = options.special_order_locations == SpecialOrderLocations.option_board_qi need_half_buffs = options.festival_locations == FestivalLocations.option_easy create_player_buff(item_factory, Buff.movement, movement_buffs, need_all_buffs, need_half_buffs, items) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index f74316f69393..33a07606e492 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,4 +1,6 @@ +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..stardew_rule import StardewRule, True_, Or @@ -7,14 +9,13 @@ from ..strings.region_names import Region -class ActionLogic: - player: int +class ActionLogic(CachedLogic): received: ReceivedLogic has: HasLogic region: RegionLogic - def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, has: HasLogic, region: RegionLogic): + super().__init__(player, cached_rules) self.received = received self.has = has self.region = region @@ -31,6 +32,7 @@ def can_pan(self) -> StardewRule: def can_pan_at(self, region: str) -> StardewRule: return self.region.can_reach(region) & self.can_pan() + @cache_rule def can_open_geode(self, geode: str) -> StardewRule: blacksmith_access = self.region.can_reach(Region.blacksmith) geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index b8bf3f3752ca..5ea239ad6c6d 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,6 +1,8 @@ from typing import Dict +from .cached_logic import cache_rule, CachedLogic from .has_logic import HasLogic +from .logic_cache import CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -15,7 +17,7 @@ from ..strings.region_names import Region -class BuildingLogic: +class BuildingLogic(CachedLogic): player: int building_option: BuildingProgression received: ReceivedLogic @@ -24,7 +26,8 @@ class BuildingLogic: money: MoneyLogic building_rules: Dict[str, StardewRule] - def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + def __init__(self, player: int, cached_rules: CachedRules, building_option: BuildingProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + super().__init__(player, cached_rules) self.player = player self.building_option = building_option self.received = received @@ -74,6 +77,7 @@ def has_building(self, building: str) -> StardewRule: building = " ".join(["Progressive", *building.split(" ")[1:]]) return self.received(f"{building}", count) & carpenter_rule + @cache_rule def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level < 1: return True_() diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py new file mode 100644 index 000000000000..672ed75563c2 --- /dev/null +++ b/worlds/stardew_valley/logic/cached_logic.py @@ -0,0 +1,29 @@ +import functools +from typing import Union, Callable + +from .logic_cache import CachedRules + + +class CachedLogic: + player: int + cached_rules: CachedRules + + def __init__(self, player: int, cached_rules: CachedRules): + self.player = player + self.cached_rules = cached_rules + + def get_cache_key(self, method: Union[str, Callable], *parameters) -> str: + if isinstance(method, Callable): + method = method.__name__ + if parameters is None: + return f"{type(self).__name__} {method}" + return f"{type(self).__name__} {method} {' '.join(map(str, parameters))}" + + +def cache_rule(func): + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + key = self.get_cache_key(func, *args) + return self.cached_rules.try_get_rule(key, lambda: func(self, *args, **kwargs)) + return wrapper + diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index b48e9986465a..09cf397b1517 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,33 +1,29 @@ +from .cached_logic import CachedLogic, cache_rule +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..mods.logic.magic_logic import MagicLogic -from ..stardew_rule import StardewRule, Or +from ..stardew_rule import StardewRule, Or, False_ from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.performance_names import Performance -from ..strings.region_names import Region valid_weapons = [APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger] -class CombatLogic: - player: int +class CombatLogic(CachedLogic): received: ReceivedLogic region: RegionLogic magic: MagicLogic - def __init__(self, player: int, received: ReceivedLogic, region: RegionLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, region: RegionLogic): + super().__init__(player, cached_rules) self.region = region self.received = received - self.has_any_weapon_rule = self.can_buy_weapon(self.has_received_any_weapon()) - self.has_decent_weapon_rule = self.can_buy_weapon(self.has_received_decent_weapon()) - self.has_good_weapon_rule = self.can_buy_weapon(self.has_received_good_weapon()) - self.has_great_weapon_rule = self.can_buy_weapon(self.has_received_great_weapon()) - self.has_galaxy_weapon_rule = self.can_buy_weapon(self.has_received_galaxy_weapon()) def set_magic(self, magic: MagicLogic): self.magic = magic + @cache_rule def can_fight_at_level(self, level: str) -> StardewRule: if level == Performance.basic: return self.has_any_weapon() | self.magic.has_any_spell() @@ -41,39 +37,24 @@ def can_fight_at_level(self, level: str) -> StardewRule: return self.has_galaxy_weapon() | self.magic.has_amazing_spells() if level == Performance.maximum: return self.has_galaxy_weapon() | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP + return False_() + @cache_rule def has_any_weapon(self) -> StardewRule: - return self.has_any_weapon_rule - - def has_decent_weapon(self) -> StardewRule: - return self.has_decent_weapon_rule - - def has_good_weapon(self) -> StardewRule: - return self.has_good_weapon_rule - - def has_great_weapon(self) -> StardewRule: - return self.has_great_weapon_rule - - def has_galaxy_weapon(self) -> StardewRule: - return self.has_galaxy_weapon_rule - - def has_received_any_weapon(self) -> StardewRule: return self.received(valid_weapons, 1) - def has_received_decent_weapon(self) -> StardewRule: + @cache_rule + def has_decent_weapon(self) -> StardewRule: return Or(self.received(weapon, 2) for weapon in valid_weapons) - def has_received_good_weapon(self) -> StardewRule: + @cache_rule + def has_good_weapon(self) -> StardewRule: return Or(self.received(weapon, 3) for weapon in valid_weapons) - def has_received_great_weapon(self) -> StardewRule: + @cache_rule + def has_great_weapon(self) -> StardewRule: return Or(self.received(weapon, 4) for weapon in valid_weapons) - def has_received_galaxy_weapon(self) -> StardewRule: + @cache_rule + def has_galaxy_weapon(self) -> StardewRule: return Or(self.received(weapon, 5) for weapon in valid_weapons) - - def can_buy_weapon(self, weapon_rule: StardewRule = None) -> StardewRule: - adventure_guild_rule = self.region.can_reach(Region.adventurer_guild) - if weapon_rule is None: - return adventure_guild_rule - return adventure_guild_rule & weapon_rule diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index c5995362e422..2a173ecc2209 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,6 +1,8 @@ from .action_logic import ActionLogic from .building_logic import BuildingLogic +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -20,8 +22,7 @@ from ..strings.tv_channel_names import Channel -class CookingLogic: - player: int +class CookingLogic(CachedLogic): mods: Mods chefsanity_option: Chefsanity exclude_ginger_island: ExcludeGingerIsland @@ -36,9 +37,10 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, mods: Mods, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, - action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, + relationship: RelationshipLogic, skill: SkillLogic): + super().__init__(player, cached_rules) self.mods = mods self.chefsanity_option = chefsanity_option self.exclude_ginger_island = exclude_ginger_island @@ -56,6 +58,7 @@ def __init__(self, player: int, mods: Mods, chefsanity_option: Chefsanity, exclu def can_cook_in_kitchen(self) -> StardewRule: return self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) + @cache_rule def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: cook_rule = self.region.can_reach(Region.kitchen) if recipe is None: @@ -67,6 +70,7 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: time_rule = self.time.has_lived_months(number_ingredients) return cook_rule & recipe_rule & ingredients_rule & time_rule + @cache_rule def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: if self.chefsanity_option == Chefsanity.option_none: return self.can_learn_recipe(source) @@ -86,6 +90,7 @@ def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: return self.received_recipe(meal_name) return self.can_learn_recipe(source) + @cache_rule def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 661ba845b4ac..a77d710aca96 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,29 +1,48 @@ from typing import Union, Iterable +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules +from .money_logic import MoneyLogic +from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic from .tool_logic import ToolLogic -from ..data import CropItem -from ..stardew_rule import StardewRule +from .traveling_merchant_logic import TravelingMerchantLogic +from ..data import CropItem, SeedItem +from ..options import Cropsanity +from ..stardew_rule import StardewRule, True_ +from ..strings.forageable_names import Forageable +from ..strings.metal_names import Fossil from ..strings.region_names import Region +from ..strings.seed_names import Seed from ..strings.tool_names import Tool -class CropLogic: +class CropLogic(CachedLogic): player: int + cropsanity_option: Cropsanity + received: ReceivedLogic has: HasLogic region: RegionLogic + traveling_merchant: TravelingMerchantLogic season: SeasonLogic + money: MoneyLogic tool: ToolLogic - def __init__(self, player: int, has: HasLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, cropsanity_option: Cropsanity, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): + super().__init__(player, cached_rules) + self.cropsanity_option = cropsanity_option + self.received = received self.has = has self.region = region + self.traveling_merchant = traveling_merchant self.season = season + self.money = money self.tool = tool + @cache_rule def can_grow(self, crop: CropItem) -> StardewRule: season_rule = self.season.has_any(crop.farm_growth_seasons) seed_rule = self.has(crop.seed.name) @@ -42,3 +61,20 @@ def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> Stardew def has_island_farm(self) -> StardewRule: return self.region.can_reach(Region.island_south) + + @cache_rule + def can_buy_seed(self, seed: SeedItem) -> StardewRule: + if self.cropsanity_option == Cropsanity.option_disabled or seed.name == Seed.qi_bean: + item_rule = True_() + else: + item_rule = self.received(seed.name) + if seed.name == Seed.coffee: + item_rule = item_rule & self.traveling_merchant.has_days(3) + season_rule = self.season.has_any(seed.seasons) + region_rule = self.region.can_reach_all(seed.regions) + currency_rule = self.money.can_spend(1000) + if seed.name == Seed.pineapple: + currency_rule = self.has(Forageable.magma_cap) + if seed.name == Seed.taro: + currency_rule = self.has(Fossil.bone_fragment) + return season_rule & region_rule & item_rule & currency_rule diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 8d0764e8dbbf..0d1625d4b56f 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,20 +1,37 @@ +from .cached_logic import cache_rule, CachedLogic +from .logic_cache import CachedRules +from .received_logic import ReceivedLogic from .region_logic import RegionLogic +from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .tool_logic import ToolLogic -from ..stardew_rule import StardewRule +from ..options import ExcludeGingerIsland +from ..data import FishItem +from ..data.fish_data import legendary_fish +from ..options import SpecialOrderLocations +from ..stardew_rule import StardewRule, True_, False_, And +from ..strings.fish_names import SVEFish from ..strings.region_names import Region from ..strings.skill_names import Skill -class FishingLogic: - player: int +class FishingLogic(CachedLogic): + exclude_ginger_island: ExcludeGingerIsland + special_order_locations: SpecialOrderLocations + received: ReceivedLogic region: RegionLogic + season: SeasonLogic tool: ToolLogic skill: SkillLogic - def __init__(self, player: int, region: RegionLogic, tool: ToolLogic, skill: SkillLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, + received: ReceivedLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): + super().__init__(player, cached_rules) + self.exclude_ginger_island = exclude_ginger_island + self.special_order_locations = special_order_locations + self.received = received self.region = region + self.season = season self.tool = tool self.skill = skill @@ -31,3 +48,27 @@ def can_fish_chests(self) -> StardewRule: def can_fish_at(self, region: str) -> StardewRule: return self.skill.can_fish() & self.region.can_reach(region) + + @cache_rule + def can_catch_fish(self, fish: FishItem) -> StardewRule: + quest_rule = True_() + if fish.extended_family: + quest_rule = self.can_start_extended_family_quest() + region_rule = self.region.can_reach_any(fish.locations) + season_rule = self.season.has_any(fish.seasons) + if fish.difficulty == -1: + difficulty_rule = self.skill.can_crab_pot() + else: + difficulty_rule = self.skill.can_fish([], 120 if fish.legendary else fish.difficulty) + if fish.name == SVEFish.kittyfish: + item_rule = self.received("Kittyfish Spell") + else: + item_rule = True_() + return quest_rule & region_rule & season_rule & difficulty_rule & item_rule + + def can_start_extended_family_quest(self) -> StardewRule: + if self.exclude_ginger_island == ExcludeGingerIsland.option_true: + return False_() + if self.special_order_locations != SpecialOrderLocations.option_board_qi: + return False_() + return self.region.can_reach(Region.qi_walnut_room) & And([self.can_catch_fish(fish) for fish in legendary_fish]) diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index b883f60a0711..c82f0bd134f1 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,17 +1,19 @@ +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct from ..strings.gift_names import Gift -class GiftLogic: - player: int +class GiftLogic(CachedLogic): has: HasLogic - def __init__(self, player: int, has: HasLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic): + super().__init__(player, cached_rules) self.has = has + @cache_rule def has_any_universal_love(self) -> StardewRule: - return self.has(Gift.golden_pumpkin) | self.has("Magic Rock Candy") | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) + return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 76e452a5d124..d852ad3c386c 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,14 +1,15 @@ -from typing import Dict, Union, Optional, Iterable, Sized, List +from typing import Dict, Union, Optional, List +from .cached_logic import CachedLogic, cache_rule +from .logic_cache import CachedRules from ..stardew_rule import StardewRule, True_, And, Or, Has, Count -class HasLogic: - player: int +class HasLogic(CachedLogic): item_rules: Dict[str, StardewRule] - def __init__(self, player: int, item_rules: Dict[str, StardewRule]): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, item_rules: Dict[str, StardewRule]): + super().__init__(player, cached_rules) self.item_rules = item_rules def __call__(self, *args, **kwargs) -> StardewRule: @@ -17,6 +18,7 @@ def __call__(self, *args, **kwargs) -> StardewRule: count = args[1] return self.has(args[0], count) + @cache_rule def has(self, items: Union[str, List[str]], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): return Has(items, self.item_rules) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 75e9c4d81d16..47452e7bcb56 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -16,6 +16,7 @@ from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic from .gift_logic import GiftLogic +from .logic_cache import CachedRules from .mine_logic import MineLogic from .money_logic import MoneyLogic from .monster_logic import MonsterLogic @@ -32,18 +33,19 @@ from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogic from .tool_logic import ToolLogic +from .traveling_merchant_logic import TravelingMerchantLogic from .wallet_logic import WalletLogic from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..mods.logic.mod_logic import ModLogic -from ..data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops -from ..data.fish_data import island_fish, legendary_fish, extended_family, get_fish_for_mods +from ..data import all_fish, all_purchasable_seeds, all_crops +from ..data.fish_data import island_fish, extended_family, get_fish_for_mods from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions from ..regions import vanilla_regions -from ..stardew_rule import False_, Or, True_, Count, And, Has, StardewRule +from ..stardew_rule import False_, Or, True_, Count, And, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.ap_weapon_names import APWeapon @@ -51,14 +53,13 @@ from ..strings.ap_names.community_upgrade_names import CommunityUpgrade from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building -from ..strings.calendar_names import Weekday from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.decoration_names import Decoration from ..strings.fertilizer_names import Fertilizer from ..strings.festival_check_names import FestivalCheck -from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest, SVEFish +from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest from ..strings.flower_names import Flower from ..strings.forageable_names import Forageable from ..strings.fruit_tree_names import Sapling @@ -102,41 +103,45 @@ class StardewLogic: festival_rules: Dict[str, StardewRule] = field(default_factory=dict) def __post_init__(self): - self.received = ReceivedLogic(self.player) - self.has = HasLogic(self.player, self.item_rules) - self.region = RegionLogic(self.player) - self.time = TimeLogic(self.player, self.received) - self.season = SeasonLogic(self.player, self.options.season_randomization, self.received, self.time) - self.money = MoneyLogic(self.player, self.options.starting_money, self.received, self.has, self.region, self.time) - self.action = ActionLogic(self.player, self.received, self.has, self.region) + self.cached_rules = CachedRules() + self.received = ReceivedLogic(self.player, self.cached_rules) + self.has = HasLogic(self.player, self.cached_rules, self.item_rules) + self.region = RegionLogic(self.player, self.cached_rules) + self.traveling_merchant = TravelingMerchantLogic(self.player, self.received) + self.time = TimeLogic(self.player, self.cached_rules, self.received) + self.season = SeasonLogic(self.player, self.cached_rules, self.options.season_randomization, self.received, self.time) + self.money = MoneyLogic(self.player, self.cached_rules, self.options.starting_money, self.received, self.has, self.region, self.time) + self.action = ActionLogic(self.player, self.cached_rules, self.received, self.has, self.region) self.arcade = ArcadeLogic(self.player, self.options.arcade_machine_locations, self.received, self.region) self.artisan = ArtisanLogic(self.player, self.has, self.time) - self.gifts = GiftLogic(self.player, self.has) + self.gifts = GiftLogic(self.player, self.cached_rules, self.has) tool_option = self.options.tool_progression skill_option = self.options.skill_progression elevator_option = self.options.elevator_progression friendsanity_option = self.options.friendsanity heart_size_option = self.options.friendsanity_heart_size + special_order_locations = self.options.special_order_locations mods_option = self.options.mods - self.buildings = BuildingLogic(self.player, self.options.building_progression, self.received, self.has, self.region, self.money) - self.shipping = ShippingLogic(self.player, self.options.exclude_ginger_island, self.options.special_order_locations, self.has, + exclude_ginger_island = self.options.exclude_ginger_island + self.buildings = BuildingLogic(self.player, self.cached_rules, self.options.building_progression, self.received, self.has, self.region, self.money) + self.shipping = ShippingLogic(self.player, exclude_ginger_island, special_order_locations, self.has, self.region, self.buildings) - self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, + self.relationship = RelationshipLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) - self.museum = MuseumLogic(self.player, self.options.museumsanity, self.received, self.has, self.region, self.action) + self.museum = MuseumLogic(self.player, self.cached_rules, self.options.museumsanity, self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) - self.combat = CombatLogic(self.player, self.received, self.region) + self.combat = CombatLogic(self.player, self.cached_rules, self.received, self.region) self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) - self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) - self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) - self.crop = CropLogic(self.player, self.has, self.region, self.season, self.tool) - self.skill = SkillLogic(self.player, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) + self.tool = ToolLogic(self.player, self.cached_rules, tool_option, self.received, self.has, self.region, self.season, self.money) + self.pet = PetLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) + self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, self.received, self.has, self.region, self.traveling_merchant, self.season, self.money, self.tool) + self.skill = SkillLogic(self.player, self.cached_rules, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) self.farming = FarmingLogic(self.player, self.has, self.skill) self.bundle = BundleLogic(self.player, self.has, self.region, self.money, self.farming) - self.fishing = FishingLogic(self.player, self.region, self.tool, self.skill) - self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, + self.fishing = FishingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, self.tool, self.skill) + self.mine = MineLogic(self.player, self.cached_rules, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, mods_option, self.options.chefsanity, self.options.exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.cooking = CookingLogic(self.player, self.cached_rules, mods_option, self.options.chefsanity, exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, @@ -144,13 +149,13 @@ def __post_init__(self): self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, self.time, self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, self.wallet, mods_option) self.crafting = CraftingLogic(self.player, self.options.craftsanity, self.options.festival_locations, - self.options.special_order_locations, self.received, self.has, self.region, self.time, self.money, + special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) - self.fish_rules.update({fish.name: self.can_catch_fish(fish) for fish in all_fish}) + self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in all_fish}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) for recipe in all_cooking_recipes: @@ -192,10 +197,10 @@ def __post_init__(self): sapling = f"{tree_fruit} Sapling" self.tree_fruit_rules[tree_fruit] = existing_rules & self.has(sapling) & self.time.has_lived_months(1) - self.seed_rules.update({seed.name: self.can_buy_seed(seed) for seed in all_purchasable_seeds}) + self.seed_rules.update({seed.name: self.crop.can_buy_seed(seed) for seed in all_purchasable_seeds}) self.crop_rules.update({crop.name: self.crop.can_grow(crop) for crop in all_crops}) self.crop_rules.update({ - Seed.coffee: (self.season.has(Season.spring) | self.season.has(Season.summer)) & self.can_buy_seed(crops_by_name[Seed.coffee].seed), + Seed.coffee: (self.season.has(Season.spring) | self.season.has(Season.summer)) & self.crop.can_buy_seed(crops_by_name[Seed.coffee].seed), Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), }) @@ -287,7 +292,7 @@ def __post_init__(self): Fertilizer.deluxe: False_(), Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), - Fish.any: Or([self.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)]), + Fish.any: Or([self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)]), Fish.crab: self.skill.can_crab_pot(Region.beach), Fish.crayfish: self.skill.can_crab_pot(Region.town), Fish.lobster: self.skill.can_crab_pot(Region.beach), @@ -335,7 +340,7 @@ def __post_init__(self): Fossil.fossilized_leg: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), Fossil.fossilized_ribs: self.region.can_reach(Region.island_south) & self.tool.has_tool(Tool.hoe), Fossil.fossilized_skull: self.action.can_open_geode(Geode.golden_coconut), - Fossil.fossilized_spine: self.fishing.can_fish_at(Region.dig_site), + Fossil.fossilized_spine: self.skill.can_fish(Region.dig_site), Fossil.fossilized_tail: self.action.can_pan_at(Region.dig_site), Fossil.mummified_bat: self.region.can_reach(Region.volcano_floor_10), Fossil.mummified_frog: self.region.can_reach(Region.island_east) & self.tool.has_tool(Tool.scythe), @@ -500,22 +505,6 @@ def __post_init__(self): self.special_order.initialize_rules() self.special_order.update_rules(self.mod.special_orders.get_modded_special_orders_rules(self.special_order.special_order_rules)) - def can_buy_seed(self, seed: SeedItem) -> StardewRule: - if self.options.cropsanity == Cropsanity.option_disabled or seed.name == Seed.qi_bean: - item_rule = True_() - else: - item_rule = self.received(seed.name) - if seed.name == Seed.coffee: - item_rule = item_rule & self.has_traveling_merchant(3) - season_rule = self.season.has_any(seed.seasons) - region_rule = self.region.can_reach_all(seed.regions) - currency_rule = self.money.can_spend(1000) - if seed.name == Seed.pineapple: - currency_rule = self.has(Forageable.magma_cap) - if seed.name == Seed.taro: - currency_rule = self.has(Fossil.bone_fragment) - return season_rule & region_rule & item_rule & currency_rule - def can_buy_sapling(self, fruit: str) -> StardewRule: sapling_prices = {Fruit.apple: 4000, Fruit.apricot: 2000, Fruit.cherry: 3400, Fruit.orange: 4000, Fruit.peach: 6000, @@ -533,22 +522,6 @@ def can_buy_sapling(self, fruit: str) -> StardewRule: return allowed_buy_sapling & can_buy_sapling - def can_catch_fish(self, fish: FishItem) -> StardewRule: - quest_rule = True_() - if fish.extended_family: - quest_rule = self.can_start_extended_family_quest() - region_rule = self.region.can_reach_any(fish.locations) - season_rule = self.season.has_any(fish.seasons) - if fish.difficulty == -1: - difficulty_rule = self.skill.can_crab_pot() - else: - difficulty_rule = self.skill.can_fish([], 120 if fish.legendary else fish.difficulty) - if fish.name == SVEFish.kittyfish: - item_rule = self.received("Kittyfish Spell") - else: - item_rule = True_() - return quest_rule & region_rule & season_rule & difficulty_rule & item_rule - def can_catch_every_fish(self) -> StardewRule: rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true @@ -558,26 +531,12 @@ def can_catch_every_fish(self) -> StardewRule: continue if exclude_extended_family and fish in extended_family: continue - rules.append(self.can_catch_fish(fish)) + rules.append(self.fishing.can_catch_fish(fish)) return And(rules) - def can_start_extended_family_quest(self) -> StardewRule: - if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: - return False_() - if self.options.special_order_locations != SpecialOrderLocations.option_board_qi: - return False_() - return self.region.can_reach(Region.qi_walnut_room) & And([self.can_catch_fish(fish) for fish in legendary_fish]) - def can_smelt(self, item: str) -> StardewRule: return self.has(Machine.furnace) & self.has(item) - def has_traveling_merchant(self, tier: int = 1): - if tier <= 0: - return True_() - tier = min(7, max(1, tier)) - traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] - return self.received(traveling_merchant_days, tier) - def can_complete_field_office(self) -> StardewRule: field_office = self.region.can_reach(Region.field_office) professor_snail = self.received("Open Professor Snail Cave") @@ -629,7 +588,7 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: return And(rules) def can_win_egg_hunt(self) -> StardewRule: - number_of_movement_buffs = self.options.luck_buff_number + number_of_movement_buffs = self.options.movement_buff_number if self.options.festival_locations == FestivalLocations.option_hard or number_of_movement_buffs < 2: return True_() return self.received(Buff.movement, number_of_movement_buffs // 2) diff --git a/worlds/stardew_valley/logic/logic_cache.py b/worlds/stardew_valley/logic/logic_cache.py new file mode 100644 index 000000000000..90fb00a5b55c --- /dev/null +++ b/worlds/stardew_valley/logic/logic_cache.py @@ -0,0 +1,41 @@ +import time +from typing import Dict, Callable + +from ..stardew_rule import StardewRule + +rule_calls = 0 +rule_creations = 0 +time_creating_rules = 0 + + +class CachedRules: + cached_rules: Dict[str, StardewRule] + + def __init__(self): + self.cached_rules = dict() + + def try_get_rule(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + if key not in self.cached_rules: + self.cached_rules[key] = create_rule() + return self.cached_rules[key] + + def try_get_rule_without_cache(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + return create_rule() + + def try_get_rule_with_stats(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + global rule_calls, rule_creations, time_creating_rules + rule_calls += 1 + if key not in self.cached_rules: + rule_creations += 1 + time_before = time.time() + self.cached_rules[key] = create_rule() + time_after = time.time() + time_creating_rules += (time_after - time_before) + if rule_calls % 100000 == 0: + cached_calls = rule_calls - rule_creations + percent_cached_calls = round((cached_calls / rule_calls) * 100) + percent_real_calls = 100 - percent_cached_calls + time_saved = (time_creating_rules / percent_real_calls) * 100 + print(f"Rule Creations/Calls: {rule_creations}/{rule_calls} ({cached_calls} cached calls [{percent_cached_calls}%] saving {time_saved}s" + f" for a total of {time_creating_rules}s creating rules)") + return self.cached_rules[key] diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index cb5f2a5f2b43..c3b19989c50a 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,4 +1,6 @@ +from .cached_logic import CachedLogic, cache_rule from .combat_logic import CombatLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .skill_logic import SkillLogic @@ -13,8 +15,7 @@ from ..strings.tool_names import Tool, ToolMaterial -class MineLogic: - player: int +class MineLogic(CachedLogic): tool_option: ToolProgression skill_option: SkillProgression elevator_option: ElevatorProgression @@ -25,9 +26,9 @@ class MineLogic: skill: SkillLogic mod_elevator: ModElevatorLogic - def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, region: RegionLogic, + def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, region: RegionLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): - self.player = player + super().__init__(player, cached_rules) self.tool_option = tool_option self.skill_option = skill_option self.elevator_option = elevator_option @@ -65,45 +66,29 @@ def get_weapon_rule_for_floor_tier(self, tier: int): return self.combat.can_fight_at_level(Performance.decent) return self.combat.can_fight_at_level(Performance.basic) + @cache_rule def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: - tier = int(floor / 40) + tier = floor // 40 rules = [] weapon_rule = self.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) if self.tool_option & ToolProgression.option_progressive: rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) if self.skill_option == options.SkillProgression.option_progressive: - combat_tier = min(10, max(0, tier * 2)) - rules.append(self.skill.has_level(Skill.combat, combat_tier)) - rules.append(self.skill.has_level(Skill.mining, combat_tier)) - return And(rules) - - def can_progress_easily_in_the_mines_from_floor(self, floor: int) -> StardewRule: - tier = int(floor / 40) + 1 - rules = [] - weapon_rule = self.get_weapon_rule_for_floor_tier(tier) - rules.append(weapon_rule) - if self.tool_option & ToolProgression.option_progressive: - rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) - if self.skill_option == options.SkillProgression.option_progressive: - combat_tier = min(10, max(0, tier * 2)) - rules.append(self.skill.has_level(Skill.combat, combat_tier)) - rules.append(self.skill.has_level(Skill.mining, combat_tier)) + skill_tier = min(10, max(0, tier * 2)) + rules.append(self.skill.has_level(Skill.combat, skill_tier)) + rules.append(self.skill.has_level(Skill.mining, skill_tier)) return And(rules) + @cache_rule def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: + if floor < 0: + floor = 0 if self.elevator_option != options.ElevatorProgression.option_vanilla: - return self.received("Progressive Mine Elevator", int(floor / 5)) + return self.received("Progressive Mine Elevator", floor // 5) return True_() - def can_mine_to_floor(self, floor: int) -> StardewRule: - previous_elevator = max(floor - 5, 0) - previous_previous_elevator = max(floor - 10, 0) - return ((self.has_mine_elevator_to_floor(previous_elevator) & - self.can_progress_in_the_mines_from_floor(previous_elevator)) | - (self.has_mine_elevator_to_floor(previous_previous_elevator) & - self.can_progress_easily_in_the_mines_from_floor(previous_previous_elevator))) - + @cache_rule def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: tier = floor // 50 rules = [] @@ -117,15 +102,3 @@ def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule self.skill.has_level(Skill.mining, skill_tier)}) return And(rules) - def can_progress_easily_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: - return self.can_progress_in_the_skull_cavern_from_floor(floor + 50) - - def can_mine_to_skull_cavern_floor(self, floor: int) -> StardewRule: - previous_elevator = max(floor - 25, 0) - previous_previous_elevator = max(floor - 50, 0) - has_mine_elevator = self.has_mine_elevator_to_floor(5) # Skull Cavern Elevator menu needs a normal elevator... - return ((self.mod_elevator.has_skull_cavern_elevator_to_floor(previous_elevator) & - self.can_progress_in_the_skull_cavern_from_floor(previous_elevator)) | - (self.mod_elevator.has_skull_cavern_elevator_to_floor(previous_previous_elevator) & - self.can_progress_easily_in_the_skull_cavern_from_floor(previous_previous_elevator))) & has_mine_elevator - diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 7e997877f4c6..464ad63a5fd6 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,4 +1,6 @@ +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic @@ -12,35 +14,39 @@ qi_gem_rewards = ["100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", "25 Qi Gems", "20 Qi Gems", "10 Qi Gems"] -class MoneyLogic: - player: int +class MoneyLogic(CachedLogic): starting_money_option: StartingMoney received: ReceivedLogic has: HasLogic region: RegionLogic time: TimeLogic - def __init__(self, player: int, starting_money_option: StartingMoney, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, starting_money_option: StartingMoney, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, time: TimeLogic): + super().__init__(player, cached_rules) self.starting_money_option = starting_money_option self.received = received self.has = has self.region = region self.time = time + @cache_rule def can_have_earned_total(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() return self.time.has_lived_months(amount // MONEY_PER_MONTH) + @cache_rule def can_spend(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() return self.time.has_lived_months(amount // (MONEY_PER_MONTH // DISPOSABLE_INCOME_DIVISOR)) + @cache_rule def can_spend_at(self, region: str, amount: int) -> StardewRule: return self.region.can_reach(region) & self.can_spend(amount) + @cache_rule def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index dde104c94e99..7eaf516fd54f 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -1,7 +1,9 @@ from typing import List from .action_logic import ActionLogic +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals from ..options import Museumsanity @@ -11,7 +13,7 @@ from ..strings.region_names import Region -class MuseumLogic: +class MuseumLogic(CachedLogic): player: int museum_option: Museumsanity received = ReceivedLogic @@ -19,26 +21,22 @@ class MuseumLogic: region: RegionLogic action: ActionLogic - def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, museum_option: Museumsanity, received: ReceivedLogic, has: HasLogic, + region: RegionLogic, action: ActionLogic): + super().__init__(player, cached_rules) self.museum_option = museum_option self.received = received self.has = has self.region = region self.action = action - def can_donate_museum_item(self, item: MuseumItem) -> StardewRule: - return self.region.can_reach(Region.museum) & self.can_find_museum_item(item) - def can_donate_museum_items(self, number: int) -> StardewRule: return self.region.can_reach(Region.museum) & self.can_find_museum_items(number) def can_donate_museum_artifacts(self, number: int) -> StardewRule: return self.region.can_reach(Region.museum) & self.can_find_museum_artifacts(number) - def can_donate_museum_minerals(self, number: int) -> StardewRule: - return self.region.can_reach(Region.museum) & self.can_find_museum_minerals(number) - + @cache_rule def can_find_museum_item(self, item: MuseumItem) -> StardewRule: region_rule = self.region.can_reach_all_except_one(item.locations) geodes_rule = And([self.action.can_open_geode(geode) for geode in item.geodes]) diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 7dcbaa07f5e4..450160bc5f65 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -2,6 +2,8 @@ from typing import Union +from .cached_logic import CachedLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic @@ -14,8 +16,7 @@ from ..strings.villager_names import NPC -class PetLogic: - player: int +class PetLogic(CachedLogic): friendsanity_option: Friendsanity heart_size_option: FriendsanityHeartSize received: ReceivedLogic @@ -23,9 +24,9 @@ class PetLogic: time: TimeLogic tool: ToolLogic - def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, region: RegionLogic, - time: TimeLogic, tool: ToolLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, + received_logic: ReceivedLogic, region: RegionLogic, time: TimeLogic, tool: ToolLogic): + super().__init__(player, cached_rules) self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option self.received = received_logic diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 82b067374fac..9907411f4eef 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -35,7 +35,7 @@ from ..strings.quest_names import Quest from ..strings.villager_names import NPC from ..strings.wallet_item_names import Wallet -from ..stardew_rule import StardewRule, Has +from ..stardew_rule import StardewRule, Has, True_ class QuestLogic: @@ -81,43 +81,45 @@ def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogic, has: def initialize_rules(self): self.quest_rules.update({ - Quest.introductions: self.region.can_reach(Region.town), + Quest.introductions: True_(), Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), - Quest.getting_started: self.has(Vegetable.parsnip) & self.tool.has_tool(Tool.hoe) & self.tool.can_water(0), + Quest.getting_started: self.has(Vegetable.parsnip), Quest.to_the_beach: self.region.can_reach(Region.beach), Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.building.has_building(Building.coop), Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), - Quest.archaeology: (self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish()) & self.region.can_reach(Region.museum), - Quest.meet_the_wizard: self.region.can_reach(Region.town) & self.region.can_reach(Region.community_center) & self.region.can_reach(Region.wizard_tower), + Quest.archaeology: self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish(), + Quest.rat_problem: self.region.can_reach_all([Region.town, Region.community_center]), + Quest.meet_the_wizard: self.can_complete_quest(Quest.rat_problem), Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), Quest.smelting: self.has(MetalBar.copper), Quest.initiation: self.mine.can_mine_in_the_mines_floor_1_40(), - Quest.robins_lost_axe: self.season.has(Season.spring) & self.region.can_reach(Region.forest) & self.relationship.can_meet(NPC.robin), + Quest.robins_lost_axe: self.season.has(Season.spring) & self.relationship.can_meet(NPC.robin), Quest.jodis_request: self.season.has(Season.spring) & self.has(Vegetable.cauliflower) & self.relationship.can_meet(NPC.jodi), - Quest.mayors_shorts: self.season.has(Season.summer) & self.region.can_reach(Region.ranch) & - self.relationship.has_hearts(NPC.marnie, 2) & self.relationship.can_meet(NPC.lewis), + Quest.mayors_shorts: self.season.has(Season.summer) & self.relationship.has_hearts(NPC.marnie, 2) & self.relationship.can_meet(NPC.lewis), Quest.blackberry_basket: self.season.has(Season.fall) & self.relationship.can_meet(NPC.linus), - Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot) & self.region.can_reach(Region.ranch), + Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot), Quest.pam_is_thirsty: self.season.has(Season.summer) & self.has(ArtisanGood.pale_ale) & self.relationship.can_meet(NPC.pam), Quest.a_dark_reagent: self.season.has(Season.winter) & self.has(Loot.void_essence) & self.relationship.can_meet(NPC.wizard), Quest.cows_delight: self.season.has(Season.fall) & self.has(Vegetable.amaranth) & self.relationship.can_meet(NPC.marnie), - Quest.the_skull_key: self.received(Wallet.skull_key) & self.region.can_reach(Region.skull_cavern_entrance), + Quest.the_skull_key: self.received(Wallet.skull_key), Quest.crop_research: self.season.has(Season.summer) & self.has(Fruit.melon) & self.relationship.can_meet(NPC.demetrius), Quest.knee_therapy: self.season.has(Season.summer) & self.has(Fruit.hot_pepper) & self.relationship.can_meet(NPC.george), Quest.robins_request: self.season.has(Season.winter) & self.has(Material.hardwood) & self.relationship.can_meet(NPC.robin), - Quest.qis_challenge: self.mine.can_mine_in_the_skull_cavern(), - Quest.the_mysterious_qi: self.region.can_reach(Region.bus_tunnel) & self.has(ArtisanGood.battery_pack) & self.region.can_reach(Region.desert) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), + Quest.qis_challenge: True_(), # The skull cavern floor 25 already has rules + Quest.the_mysterious_qi: self.region.can_reach_all([Region.bus_tunnel, Region.railroad, Region.mayor_house]) & + self.has(ArtisanGood.battery_pack) & self.has(Forageable.rainbow_shell) & + self.has(Vegetable.beet) & self.has(Loot.solar_essence), Quest.carving_pumpkins: self.season.has(Season.fall) & self.has(Vegetable.pumpkin) & self.relationship.can_meet(NPC.caroline), - Quest.a_winter_mystery: self.season.has(Season.winter) & self.region.can_reach(Region.town), - Quest.strange_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.secret_woods) & self.has(ArtisanGood.maple_syrup), - Quest.cryptic_note: self.has(Forageable.secret_note) & self.region.can_reach(Region.skull_cavern_100), + Quest.a_winter_mystery: self.season.has(Season.winter), + Quest.strange_note: self.has(Forageable.secret_note) & self.has(ArtisanGood.maple_syrup), + Quest.cryptic_note: self.has(Forageable.secret_note), Quest.fresh_fruit: self.season.has(Season.spring) & self.has(Fruit.apricot) & self.relationship.can_meet(NPC.emily), Quest.aquatic_research: self.season.has(Season.summer) & self.has(Fish.pufferfish) & self.relationship.can_meet(NPC.demetrius), Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two() & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), Quest.mayors_need: self.season.has(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.relationship.can_meet(NPC.lewis), Quest.wanted_lobster: self.season.has(Season.fall) & self.season.has(Season.fall) & self.has(Fish.lobster) & self.relationship.can_meet(NPC.gus), Quest.pam_needs_juice: self.season.has(Season.fall) & self.has(ArtisanGood.battery_pack) & self.relationship.can_meet(NPC.pam), - Quest.fish_casserole: self.relationship.has_hearts(NPC.jodi, 4) & self.has(Fish.largemouth_bass) & self.region.can_reach(Region.sam_house), + Quest.fish_casserole: self.relationship.has_hearts(NPC.jodi, 4) & self.has(Fish.largemouth_bass), Quest.catch_a_squid: self.season.has(Season.winter) & self.has(Fish.squid) & self.relationship.can_meet(NPC.willy), Quest.fish_stew: self.season.has(Season.winter) & self.has(Fish.albacore) & self.relationship.can_meet(NPC.gus), Quest.pierres_notice: self.season.has(Season.spring) & self.has(Meal.sashimi) & self.relationship.can_meet(NPC.pierre), @@ -127,11 +129,11 @@ def initialize_rules(self): Quest.grannys_gift: self.season.has(Season.spring) & self.has(Forageable.leek) & self.relationship.can_meet(NPC.evelyn), Quest.exotic_spirits: self.season.has(Season.winter) & self.has(Forageable.coconut) & self.relationship.can_meet(NPC.gus), Quest.catch_a_lingcod: self.season.has(Season.winter) & self.has(Fish.lingcod) & self.relationship.can_meet(NPC.willy), - Quest.dark_talisman: self.wallet.has_rusty_key() & self.region.can_reach(Region.railroad) & self.relationship.can_meet(NPC.krobus) & self.region.can_reach(Region.mutant_bug_lair), - Quest.goblin_problem: self.region.can_reach(Region.witch_swamp) & self.has(ArtisanGood.void_mayonnaise), - Quest.magic_ink: self.region.can_reach(Region.witch_hut) & self.relationship.can_meet(NPC.wizard), - Quest.the_pirates_wife: self.region.can_reach(Region.island_west) & self.relationship.can_meet(NPC.kent) & - self.relationship.can_meet(NPC.gus) & self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & + Quest.dark_talisman: self.region.can_reach(Region.railroad) & self.wallet.has_rusty_key() & self.relationship.can_meet(NPC.krobus), + Quest.goblin_problem: self.region.can_reach(Region.witch_swamp), + Quest.magic_ink: self.relationship.can_meet(NPC.wizard), + Quest.the_pirates_wife: self.relationship.can_meet(NPC.kent) & self.relationship.can_meet(NPC.gus) & + self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & self.relationship.can_meet(NPC.wizard) & self.relationship.can_meet(NPC.willy), }) diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 71c81edf0137..e01db08f5624 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,13 +1,14 @@ from typing import Iterable, Union, Optional +from .cached_logic import CachedLogic, cache_rule +from .logic_cache import CachedRules from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived -class ReceivedLogic: - player: int +class ReceivedLogic(CachedLogic): - def __init__(self, player: int): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules): + super().__init__(player, cached_rules) def __call__(self, *args, **kwargs) -> StardewRule: count = 1 @@ -15,6 +16,7 @@ def __call__(self, *args, **kwargs) -> StardewRule: count = args[1] return self.received(args[0], count) + @cache_rule def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: if count <= 0 or not items: return True_() diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 938563e8575e..1552eb0a3585 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,32 +1,40 @@ -from typing import Iterable +from typing import Iterable, List +from .cached_logic import CachedLogic, cache_rule +from .logic_cache import CachedRules from ..stardew_rule import StardewRule, And, Or, Reach, Count -class RegionLogic: - player: int +class RegionLogic(CachedLogic): - def __init__(self, player: int): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules): + super().__init__(player, cached_rules) - def can_reach(self, spot: str) -> StardewRule: - return Reach(spot, "Region", self.player) + @cache_rule + def can_reach(self, region_name: str) -> StardewRule: + return Reach(region_name, "Region", self.player) - def can_reach_any(self, spots: Iterable[str]) -> StardewRule: - return Or(self.can_reach(spot) for spot in spots) + @cache_rule + def can_reach_any(self, region_names: Iterable[str]) -> StardewRule: + return Or(self.can_reach(spot) for spot in region_names) - def can_reach_all(self, spots: Iterable[str]) -> StardewRule: - return And(self.can_reach(spot) for spot in spots) + @cache_rule + def can_reach_all(self, region_names: Iterable[str]) -> StardewRule: + return And(self.can_reach(spot) for spot in region_names) - def can_reach_all_except_one(self, spots: Iterable[str]) -> StardewRule: - num_required = len(list(spots)) - 1 + @cache_rule + def can_reach_all_except_one(self, region_names: Iterable[str]) -> StardewRule: + region_names = list(region_names) + num_required = len(region_names) - 1 if num_required <= 0: - num_required = len(list(spots)) - return Count(num_required, [self.can_reach(spot) for spot in spots]) + num_required = len(region_names) + return Count(num_required, [self.can_reach(spot) for spot in region_names]) - def can_reach_location(self, spot: str) -> StardewRule: - return Reach(spot, "Location", self.player) + @cache_rule + def can_reach_location(self, location_names: str) -> StardewRule: + return Reach(location_names, "Location", self.player) - def can_reach_entrance(self, spot: str) -> StardewRule: - return Reach(spot, "Entrance", self.player) + @cache_rule + def can_reach_entrance(self, entrance_name: str) -> StardewRule: + return Reach(entrance_name, "Entrance", self.player) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 7c9a82c1ddb5..82bf54b6696a 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -3,8 +3,10 @@ from typing import Iterable, Union from .building_logic import BuildingLogic +from .cached_logic import CachedLogic, cache_rule from .gift_logic import GiftLogic from .has_logic import HasLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic @@ -19,8 +21,7 @@ from ..strings.region_names import Region -class RelationshipLogic: - player: int +class RelationshipLogic(CachedLogic): friendsanity_option: Friendsanity heart_size_option: FriendsanityHeartSize received: ReceivedLogic @@ -32,9 +33,10 @@ class RelationshipLogic: buildings: BuildingLogic mods_option: Mods - def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, cached_rules: CachedRules, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, + received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): - self.player = player + super().__init__(player, cached_rules) self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option self.received = received_logic @@ -67,6 +69,7 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule: baby_rules = [self.can_get_married(), self.buildings.has_house(2), self.has_hearts(Generic.bachelor, 12), self.has_children(number_children - 1)] return And(baby_rules) + @cache_rule def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() @@ -106,14 +109,14 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: return self.can_earn_relationship(npc, hearts) is_capped_at_8 = villager.bachelor and self.friendsanity_option != Friendsanity.option_all_with_marriage if is_capped_at_8 and hearts > 8: - return self.received_hearts(villager, 8) & self.can_earn_relationship(npc, hearts) - return self.received_hearts(villager, hearts) + return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) + return self.received_hearts(villager.name, hearts) - def received_hearts(self, npc: Union[str, Villager], hearts: int) -> StardewRule: - if isinstance(npc, Villager): - return self.received_hearts(npc.name, hearts) + @cache_rule + def received_hearts(self, npc: str, hearts: int) -> StardewRule: return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) + @cache_rule def can_meet(self, npc: str) -> StardewRule: if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): return True_() @@ -130,16 +133,15 @@ def can_meet(self, npc: str) -> StardewRule: def can_give_loved_gifts_to_everyone(self) -> StardewRule: rules = [] - gift_rule = self.gifts.has_any_universal_love() for npc in all_villagers_by_name: if not self.npc_is_in_current_slot(npc): continue meet_rule = self.can_meet(npc) - rules.append(meet_rule & gift_rule) - loved_gifts_rules = And(rules) - simplified_rules = loved_gifts_rules.simplify() - return simplified_rules + rules.append(meet_rule) + loved_gifts_rules = And(rules) & self.gifts.has_any_universal_love() + return loved_gifts_rules + @cache_rule def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: if hearts <= 0: return True_() diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 40229b9ef71a..37889fb2f6fe 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,5 +1,7 @@ from typing import Iterable +from .cached_logic import cache_rule, CachedLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .time_logic import TimeLogic from ..options import SeasonRandomization @@ -8,55 +10,40 @@ from ..strings.season_names import Season -class SeasonLogic: - player: int +class SeasonLogic(CachedLogic): season_option: SeasonRandomization received: ReceivedLogic time: TimeLogic - def __init__(self, player: int, season_option: SeasonRandomization, received_logic: ReceivedLogic, time: TimeLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, season_option: SeasonRandomization, received_logic: ReceivedLogic, time: TimeLogic): + super().__init__(player, cached_rules) self.season_option = season_option self.received = received_logic self.time = time - self.has_season_rules = { - Generic.any: True_() - } - self.has_any_season_rules = {} - self.has_all_season_rules = {} - self.has_any_not_winter_rule = self.has_any([Season.spring, Season.summer, Season.fall]) + @cache_rule def has(self, season: str) -> StardewRule: - if season in self.has_season_rules: - return self.has_season_rules[season] + if season == Generic.any: + return True_() seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] if self.season_option == SeasonRandomization.option_progressive: - self.has_season_rules[season] = self.received(Season.progressive, seasons_order.index(season)) - elif self.season_option == SeasonRandomization.option_disabled: + return self.received(Season.progressive, seasons_order.index(season)) + if self.season_option == SeasonRandomization.option_disabled: if season == Season.spring: - self.has_season_rules[season] = True_() - else: - self.has_season_rules[season] = self.time.has_lived_months(1) - else: - self.has_season_rules[season] = self.received(season) - return self.has_season_rules[season] + return True_() + return self.time.has_lived_months(1) + return self.received(season) def has_any(self, seasons: Iterable[str]): if not seasons: return True_() - key = ",".join(seasons) - if key not in self.has_any_season_rules: - self.has_any_season_rules[key] = Or([self.has(season) for season in seasons]) - return self.has_any_season_rules[key] + return Or([self.has(season) for season in seasons]) def has_any_not_winter(self): - return self.has_any_not_winter_rule + return self.has_any([Season.spring, Season.summer, Season.fall]) def has_all(self, seasons: Iterable[str]): if not seasons: return True_() - key = ",".join(seasons) - if key not in self.has_all_season_rules: - self.has_all_season_rules[key] = And([self.has(season) for season in seasons]) - return self.has_all_season_rules[key] + return And([self.has(season) for season in seasons]) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index db56de5a57de..13588bc0f241 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -1,8 +1,10 @@ from typing import Iterable, List, Union +from .cached_logic import CachedLogic, cache_rule from .combat_logic import CombatLogic from .crop_logic import CropLogic from .has_logic import HasLogic +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic @@ -25,8 +27,7 @@ fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] -class SkillLogic: - player: int +class SkillLogic(CachedLogic): skill_option: SkillProgression received: ReceivedLogic has: HasLogic @@ -39,9 +40,9 @@ class SkillLogic: magic: MagicLogic mods: Mods - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, + def __init__(self, player: int, cached_rules: CachedRules, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): - self.player = player + super().__init__(player, cached_rules) self.skill_option = skill_option self.received = received self.has = has @@ -56,6 +57,7 @@ def set_mod_logic(self, magic: MagicLogic, mods: Mods): self.magic = magic self.mods = mods + @cache_rule def can_earn_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -67,23 +69,22 @@ def can_earn_level(self, skill: str, level: int) -> StardewRule: previous_level_rule = self.has_level(skill, level - 1) if skill == Skill.fishing: - xp_rule = self.can_get_fishing_xp() & self.tool.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) + xp_rule = self.tool.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) elif skill == Skill.farming: - xp_rule = self.can_get_farming_xp() & self.tool.has_tool(Tool.hoe, tool_material) & self.tool.can_water(tool_level) + xp_rule = self.tool.has_tool(Tool.hoe, tool_material) & self.tool.can_water(tool_level) elif skill == Skill.foraging: - xp_rule = self.can_get_foraging_xp() & \ - (self.tool.has_tool(Tool.axe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level)) + xp_rule = self.tool.has_tool(Tool.axe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level) elif skill == Skill.mining: - xp_rule = self.can_get_mining_xp() & \ - (self.tool.has_tool(Tool.pickaxe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level)) + xp_rule = self.tool.has_tool(Tool.pickaxe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level) elif skill == Skill.combat: combat_tier = Performance.tiers[tool_level] - xp_rule = self.can_get_combat_xp() & self.combat.can_fight_at_level(combat_tier) + xp_rule = self.combat.can_fight_at_level(combat_tier) else: raise Exception(f"Unknown skill: {skill}") return previous_level_rule & months_rule & xp_rule + @cache_rule def has_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -93,9 +94,11 @@ def has_level(self, skill: str, level: int) -> StardewRule: return self.can_earn_level(skill, level) + @cache_rule def has_farming_level(self, level: int) -> StardewRule: return self.has_level(Skill.farming, level) + @cache_rule def has_total_level(self, level: int, allow_modded_skills: bool = False) -> StardewRule: if level <= 0: return True_() @@ -114,34 +117,40 @@ def has_total_level(self, level: int, allow_modded_skills: bool = False) -> Star return rule_with_fishing return self.time.has_lived_months(months_with_4_skills) | rule_with_fishing + @cache_rule def can_get_farming_xp(self) -> StardewRule: crop_rules = [] for crop in all_crops: crop_rules.append(self.crop.can_grow(crop)) return Or(crop_rules) + @cache_rule def can_get_foraging_xp(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.axe) tree_rule = self.region.can_reach(Region.forest) & self.season.has_any_not_winter() stump_rule = self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.copper) return tool_rule & (tree_rule | stump_rule) + @cache_rule def can_get_mining_xp(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.pickaxe) stone_rule = self.region.can_reach_any([Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5]) return tool_rule & stone_rule + @cache_rule def can_get_combat_xp(self) -> StardewRule: tool_rule = self.combat.has_any_weapon() enemy_rule = self.region.can_reach_any([Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5]) return tool_rule & enemy_rule + @cache_rule def can_get_fishing_xp(self) -> StardewRule: if self.skill_option == options.SkillProgression.option_progressive: return self.can_fish() | self.can_crab_pot() return self.can_fish() + @cache_rule def can_fish(self, regions: Union[str, List[str]] = None, difficulty: int = 0) -> StardewRule: if isinstance(regions, str): regions = [regions] @@ -155,6 +164,7 @@ def can_fish(self, regions: Union[str, List[str]] = None, difficulty: int = 0) - number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule + @cache_rule def can_crab_pot(self, region: str = Generic.any) -> StardewRule: crab_pot_rule = self.has(Fishing.bait) if self.skill_option == options.SkillProgression.option_progressive: diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index ce9b10d6f342..aa2ec6de1ae7 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -77,28 +77,28 @@ def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: def initialize_rules(self): self.special_order_rules.update({ SpecialOrder.island_ingredients: self.relationship.can_meet(NPC.caroline) & self.has_island_transport() & self.ability.can_farm_perfectly() & - self.shipping.can_ship(Vegetable.taro_root) & self.shipping.can_ship(Fruit.pineapple) & self.shipping.can_ship(Forageable.ginger), - SpecialOrder.cave_patrol: self.relationship.can_meet(NPC.clint) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(120), + self.shipping.can_ship(Vegetable.taro_root) & self.shipping.can_ship(Fruit.pineapple) & self.shipping.can_ship( + Forageable.ginger), + SpecialOrder.cave_patrol: self.relationship.can_meet(NPC.clint), SpecialOrder.aquatic_overpopulation: self.relationship.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), SpecialOrder.biome_balance: self.relationship.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), SpecialOrder.rock_rejuivenation: self.relationship.has_hearts(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & - self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & - self.has(ArtisanGood.cloth) & self.region.can_reach(Region.haley_house), - SpecialOrder.gifts_for_george: self.region.can_reach(Region.alex_house) & self.season.has(Season.spring) & self.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.museum) & self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), - SpecialOrder.gus_famous_omelet: self.region.can_reach(Region.saloon) & self.has(AnimalProduct.any_egg), + self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & self.has(ArtisanGood.cloth), + SpecialOrder.gifts_for_george: self.season.has(Season.spring) & self.has(Forageable.leek), + SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), + SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.shipping.can_ship(), - SpecialOrder.community_cleanup: self.region.can_reach(Region.railroad) & self.skill.can_crab_pot(), - SpecialOrder.the_strong_stuff: self.region.can_reach(Region.trailer) & self.artisan.can_keg(Vegetable.potato), - SpecialOrder.pierres_prime_produce: self.region.can_reach(Region.pierre_store) & self.ability.can_farm_perfectly(), - SpecialOrder.robins_project: self.relationship.can_meet(NPC.robin) & self.region.can_reach(Region.carpenter) & - self.ability.can_chop_perfectly() & self.has(Material.hardwood), - SpecialOrder.robins_resource_rush: self.relationship.can_meet(NPC.robin) & self.region.can_reach(Region.carpenter) & self.ability.can_chop_perfectly() & self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted: self.region.can_reach(Region.beach) & self.has(Loot.bug_meat), + SpecialOrder.community_cleanup: self.skill.can_crab_pot(), + SpecialOrder.the_strong_stuff: self.artisan.can_keg(Vegetable.potato), + SpecialOrder.pierres_prime_produce: self.ability.can_farm_perfectly(), + SpecialOrder.robins_project: self.relationship.can_meet(NPC.robin) & self.ability.can_chop_perfectly() & self.has(Material.hardwood), + SpecialOrder.robins_resource_rush: self.relationship.can_meet(NPC.robin) & self.ability.can_chop_perfectly() & + self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), + SpecialOrder.juicy_bugs_wanted: self.has(Loot.bug_meat), SpecialOrder.tropical_fish: self.relationship.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), - SpecialOrder.a_curious_substance: self.region.can_reach(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(80), - SpecialOrder.prismatic_jelly: self.region.can_reach(Region.wizard_tower) & self.ability.can_mine_perfectly() & self.mine.can_mine_to_floor(40), + SpecialOrder.a_curious_substance: self.region.can_reach(Region.wizard_tower), + SpecialOrder.prismatic_jelly: self.region.can_reach(Region.wizard_tower), SpecialOrder.qis_crop: self.ability.can_farm_perfectly() & self.region.can_reach(Region.greenhouse) & self.region.can_reach(Region.island_west) & self.skill.has_total_level(50) & self.has(Machine.seed_maker) & self.shipping.can_ship(), diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index e7b1d378f97d..3ea19f25bce0 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,3 +1,5 @@ +from .cached_logic import CachedLogic, cache_rule +from .logic_cache import CachedRules from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule from ..strings.ap_names.event_names import Event @@ -5,14 +7,14 @@ MAX_MONTHS = 12 -class TimeLogic: - player: int +class TimeLogic(CachedLogic): received: ReceivedLogic - def __init__(self, player: int, received_logic: ReceivedLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, received_logic: ReceivedLogic): + super().__init__(player, cached_rules) self.received = received_logic + @cache_rule def has_lived_months(self, number: int) -> StardewRule: number = max(0, min(number, MAX_MONTHS)) return self.received(Event.month_end, number) diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 979a625f04c1..b1320b0ccd09 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,9 +1,10 @@ +from .cached_logic import CachedLogic, cache_rule from .has_logic import HasLogic +from .logic_cache import CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic -from .. import options from ..mods.logic.magic_logic import MagicLogic from ..options import ToolProgression from ..stardew_rule import StardewRule, True_ @@ -28,8 +29,7 @@ } -class ToolLogic: - player: int +class ToolLogic(CachedLogic): tool_option = ToolProgression received: ReceivedLogic has: HasLogic @@ -38,9 +38,9 @@ class ToolLogic: money: MoneyLogic magic: MagicLogic - def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, money: MoneyLogic): - self.player = player + super().__init__(player, cached_rules) self.tool_option = tool_option self.received = received self.has = has @@ -51,6 +51,7 @@ def __init__(self, player: int, tool_option: ToolProgression, received: Received def set_magic(self, magic: MagicLogic): self.magic = magic + @cache_rule def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: if material == ToolMaterial.basic or tool == Tool.scythe: return True_() @@ -60,6 +61,7 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) + @cache_rule def has_fishing_rod(self, level: int) -> StardewRule: if self.tool_option & ToolProgression.option_progressive: return self.received(f"Progressive {Tool.fishing_rod}", level) @@ -70,6 +72,7 @@ def has_fishing_rod(self, level: int) -> StardewRule: level = min(level, 4) return self.money.can_spend_at(Region.fish_shop, prices[level]) + @cache_rule def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: season_rule = self.season.has(season) region_rule = self.region.can_reach(region) @@ -77,6 +80,7 @@ def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = return season_rule & region_rule & self.has_tool(Tool.hoe) return season_rule & region_rule + @cache_rule def can_water(self, level: int) -> StardewRule: tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) spell_rule = self.received(MagicSpell.water) & self.magic.can_use_altar() & self.received(f"{ModSkill.magic} Level", level) diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py new file mode 100644 index 000000000000..bf74d9e1c6ca --- /dev/null +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -0,0 +1,20 @@ +from .received_logic import ReceivedLogic +from ..stardew_rule import True_ +from ..strings.calendar_names import Weekday + + +class TravelingMerchantLogic: + player: int + received: ReceivedLogic + + def __init__(self, player: int, received_logic: ReceivedLogic): + self.player = player + self.received = received_logic + + def has_days(self, number_days: int = 1): + if number_days <= 0: + return True_() + tier = min(7, max(1, number_days)) + traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] + return self.received(traveling_merchant_days, tier) + diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index 98c3f461d479..753c3aa5dd31 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -15,7 +15,7 @@ def __init__(self, player: int, received: ReceivedLogic, museum: MuseumLogic): self.museum = museum def can_speak_dwarf(self) -> StardewRule: - return self.received("Dwarvish Translation Guide") + return self.received(Wallet.dwarvish_translation_guide) def has_rusty_key(self) -> StardewRule: return self.received(Wallet.rusty_key) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index d47dd1b4442b..58846d0fe21a 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -28,6 +28,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: Entrance.enter_coop, Entrance.enter_barn, Entrance.enter_shed, Entrance.enter_slime_hutch, Entrance.farming, Entrance.shipping]), + RegionData(Region.farming), RegionData(Region.shipping), RegionData(Region.backwoods, [Entrance.backwoods_to_mountain]), RegionData(Region.bus_stop, @@ -603,8 +604,7 @@ def randomize_chosen_connections(connections_to_randomize: List[ConnectionData], return randomized_connections -def create_connections_for_generation(randomized_connections: Dict[ConnectionData, ConnectionData]) -> List[ - ConnectionData]: +def create_connections_for_generation(randomized_connections: Dict[ConnectionData, ConnectionData]) -> List[ConnectionData]: connections = [] for connection in randomized_connections: destination = randomized_connections[connection] @@ -622,6 +622,7 @@ def create_data_for_mod(randomized_connections: Dict[ConnectionData, ConnectionD add_to_mod_data(connection, destination, randomized_data_for_mod) return randomized_data_for_mod + def add_to_mod_data(connection: ConnectionData, destination: ConnectionData, randomized_data_for_mod: Dict[str, str]): randomized_data_for_mod[connection.name] = destination.name randomized_data_for_mod[destination.reverse] = connection.reverse diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 506b586d7f4e..cfdc44d6bdb2 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -44,27 +44,20 @@ def set_rules(world): current_bundles = world.modified_bundles all_location_names = list(location.name for location in multiworld.get_locations(player)) - # 22.756 - 23.789 + set_entrance_rules(logic, multiworld, player, world_options) - # 34.761 - 35.568 set_ginger_island_rules(logic, multiworld, player, world_options) - # 36.281 - 38.453 set_tool_rules(logic, multiworld, player, world_options) - # 36.980 - 37.228 - set_skills_rules(logic, multiworld, player, world_options) set_bundle_rules(current_bundles, logic, multiworld, player) set_building_rules(logic, multiworld, player, world_options) set_cropsanity_rules(all_location_names, logic, multiworld, player, world_options) set_story_quests_rules(all_location_names, logic, multiworld, player, world_options) - # 1min09 - 1min14 - set_special_order_rules(all_location_names, logic, multiworld, player, world_options) set_help_wanted_quests_rules(logic, multiworld, player, world_options) set_fishsanity_rules(all_location_names, logic, multiworld, player) set_museumsanity_rules(all_location_names, logic, multiworld, player, world_options) - # 1min34 - 1min46 set_friendsanity_rules(all_location_names, logic, multiworld, player) set_backpack_rules(logic, multiworld, player, world_options) @@ -75,20 +68,12 @@ def set_rules(world): set_chefsanity_rules(all_location_names, logic, multiworld, player, world_options) set_craftsanity_rules(all_location_names, logic, multiworld, player, world_options) set_isolated_locations_rules(logic, multiworld, player) - set_traveling_merchant_rules(logic, multiworld, player) + set_traveling_merchant_day_rules(logic, multiworld, player) set_arcade_machine_rules(logic, multiworld, player, world_options) set_deepwoods_rules(logic, multiworld, player, world_options) set_magic_spell_rules(logic, multiworld, player, world_options) set_sve_rules(logic, multiworld, player, world_options) - # 1min52 - 1min53 # These times are for TestOptions - # 1min36 - 1min38 # After the combat not duplicating a bunch of stuff - # 1min28 - 1min30 # with the caching of combat rules - # 1min25 - 1min26 # after caching seasons - # 1min19 - 1min25 # moved some progression items to useful - # 1min30 - 1min32 # with the flattening - # 1min25 - 1min36 # with zero flattening - # 1min36 - 1min40 # with complex flattening only in simplify def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): @@ -117,7 +102,7 @@ def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: Stard if previous is None: continue tool_upgrade_location = multiworld.get_location(f"{material} {tool} Upgrade", player) - MultiWorldRules.set_rule(tool_upgrade_location, logic.has_tool(tool, previous).simplify()) + MultiWorldRules.set_rule(tool_upgrade_location, logic.tool.has_tool(tool, previous).simplify()) def set_building_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -246,7 +231,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), - logic.has_traveling_merchant()) + logic.traveling_merchant.has_days()) set_farm_buildings_entrance_rules(logic, multiworld, player) @@ -263,12 +248,12 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), logic.received("Club Card")) - set_bedroom_entrance_rules(logic, multi_world, player, world_options) + set_bedroom_entrance_rules(logic, multiworld, player, world_options) set_festival_entrance_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin().simplify()) - MultiWorldRules.set_rule(multi_world.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin().simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce).simplify()) def set_adventure_guild_entrance_rules(logic, multiworld, player, world_options): @@ -305,18 +290,18 @@ def set_bedroom_entrance_rules(logic, multiworld, player, world_options: Stardew def set_mines_floor_entrance_rules(logic, multiworld, player): for floor in range(5, 120 + 5, 5): - rule = logic.has_mine_elevator_to_floor(floor - 10) + rule = logic.mine.has_mine_elevator_to_floor(floor - 10) if floor == 5 or floor == 45 or floor == 85: - rule = rule & logic.can_progress_in_the_mines_from_floor(floor) + rule = rule & logic.mine.can_progress_in_the_mines_from_floor(floor) entrance = multiworld.get_entrance(dig_to_mines_floor(floor), player) MultiWorldRules.set_rule(entrance, rule.simplify()) def set_skull_cavern_floor_entrance_rules(logic, multiworld, player): for floor in range(25, 200 + 25, 25): - rule = has_skull_cavern_elevator_to_floor(logic, floor - 25) - if floor == 5 or floor == 45 or floor == 85: - rule = rule & logic.can_progress_in_the_skull_cavern_from_floor(floor) + rule = logic.mod.elevator.has_skull_cavern_elevator_to_floor(floor - 25) + if floor == 25 or floor == 75 or floor == 125: + rule = rule & logic.mine.can_progress_in_the_skull_cavern_from_floor(floor) entrance = multiworld.get_entrance(dig_to_skull_floor(floor), player) MultiWorldRules.set_rule(entrance, rule.simplify()) @@ -330,30 +315,30 @@ def set_blacksmith_entrance_rules(logic, multiworld, player): def set_skill_entrance_rules(logic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), - logic.can_get_farming_xp().simplify()) + logic.skill.can_get_farming_xp().simplify()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fishing, player), - logic.can_get_fishing_xp().simplify()) + logic.skill.can_get_fishing_xp().simplify()) def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, item_name: str, tool_material: str): material_entrance = multiworld.get_entrance(entrance_name, player) - upgrade_rule = logic.has(item_name) & logic.can_spend_money(tool_upgrade_prices[tool_material]) + upgrade_rule = logic.has(item_name) & logic.money.can_spend(tool_upgrade_prices[tool_material]) MultiWorldRules.set_rule(material_entrance, upgrade_rule.simplify()) def set_festival_entrance_rules(logic, multiworld, player): - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_egg_festival, player), logic.has_season(Season.spring)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_flower_dance, player), logic.has_season(Season.spring)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_egg_festival, player), logic.season.has(Season.spring)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_flower_dance, player), logic.season.has(Season.spring)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_luau, player), logic.has_season(Season.summer)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_moonlight_jellies, player), logic.has_season(Season.summer)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_luau, player), logic.season.has(Season.summer)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_moonlight_jellies, player), logic.season.has(Season.summer)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_fair, player), logic.has_season(Season.fall)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_spirit_eve, player), logic.has_season(Season.fall)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_fair, player), logic.season.has(Season.fall)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_spirit_eve, player), logic.season.has(Season.fall)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_festival_of_ice, player), logic.has_season(Season.winter)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_night_market, player), logic.has_season(Season.winter)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_winter_star, player), logic.has_season(Season.winter)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_festival_of_ice, player), logic.season.has(Season.winter)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_night_market, player), logic.season.has(Season.winter)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_winter_star, player), logic.season.has(Season.winter)) def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -873,9 +858,9 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), logic.has("Fire Quartz").simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(85)).simplify()) + (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), - (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(85)).simplify()) + (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85)).simplify()) # MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player),) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Tendrils", player), logic.region.can_reach(Region.farm).simplify()) @@ -884,7 +869,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze All Nature School Locations", player), (logic.has("Earth Crystal") & logic.region.can_reach("Farm")).simplify()), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Meteor", player), - (logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()), + (logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)).simplify()), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lucksteal", player), logic.region.can_reach(Region.witch_hut).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Bloodmana", player), @@ -892,7 +877,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze All Eldritch School Locations", player), (logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & - logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()) + logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze Every Magic School Location", player), (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & @@ -901,7 +886,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i logic.has("Fire Quartz") & logic.skill.can_fish([], 85) & logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & - logic.region.can_reach(Region.farm) & logic.has_lived_months(12)).simplify()) + logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)).simplify()) def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 016791cae7ab..5af20e679401 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -377,5 +377,4 @@ def __hash__(self): return hash(self.item) def simplify(self) -> StardewRule: - return self - # return self.other_rules[self.item].simplify() + return self.other_rules[self.item].simplify() diff --git a/worlds/stardew_valley/strings/wallet_item_names.py b/worlds/stardew_valley/strings/wallet_item_names.py index 31026ebbaeae..e7c4eb9cb3c1 100644 --- a/worlds/stardew_valley/strings/wallet_item_names.py +++ b/worlds/stardew_valley/strings/wallet_item_names.py @@ -1,4 +1,5 @@ class Wallet: + dwarvish_translation_guide = "Dwarvish Translation Guide" magnifying_glass = "Magnifying Glass" rusty_key = "Rusty Key" skull_key = "Skull Key" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index ab3eab44474d..6deadf176ff8 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -1,8 +1,9 @@ +import typing from typing import List from BaseClasses import ItemClassification, MultiWorld, Item from . import setup_solo_multiworld, SVTestBase, get_minsanity_options, allsanity_options_without_mods, \ - allsanity_options_with_mods, minimal_locations_maximal_items + allsanity_options_with_mods, minimal_locations_maximal_items, SVTestCase from .. import locations, items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name from ..items import Group, item_table @@ -10,6 +11,7 @@ from ..mods.mod_data import ModNames from ..options import Friendsanity, SpecialOrderLocations, Shipsanity, Chefsanity, SeasonRandomization, Craftsanity, ExcludeGingerIsland, ToolProgression, \ FriendsanityHeartSize +from ..strings.region_names import Region def get_real_locations(tester: typing.Union[SVTestBase, SVTestCase], multiworld: MultiWorld): @@ -237,24 +239,6 @@ def test_given_elevator_to_floor_105_when_find_another_elevator_then_has_access_ self.assertTrue(floor_120.can_reach(self.multiworld.state)) - - def test_given_access_to_floor_115_when_find_another_pickaxe_and_dagger_then_does_not_have_access_to_floor_120(self): - items_for_115 = self.generate_items_for_mine_115() - items_for_120 = self.generate_items_for_extra_mine_levels("Progressive Dagger") - self.collect(items_for_115) - - can_reach = self.multiworld.get_region("The Mines - Floor 115", self.player).can_reach(self.multiworld.state) - self.assertTrue(can_reach) - self.assertFalse(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) - - self.collect(items_for_120) - - self.assertTrue(self.multiworld.get_region("The Mines - Floor 115", self.player).can_reach(self.multiworld.state)) - self.assertFalse(self.multiworld.get_region("The Mines - Floor 120", self.player).can_reach(self.multiworld.state)) - - self.remove(items_for_115) - self.remove(items_for_120) - def generate_items_for_mine_115(self) -> List[Item]: pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 2 elevators = [self.get_item_by_name("Progressive Mine Elevator")] * 21 @@ -274,6 +258,71 @@ def generate_items_for_extra_mine_levels(self, weapon_name: str) -> List[Item]: return [last_pickaxe, last_weapon, second_last_combat_level, last_combat_level, second_last_mining_level, last_mining_level] +class TestSkullCavernLogic(SVTestBase): + options = { + options.ElevatorProgression.internal_name: options.ElevatorProgression.option_vanilla, + ToolProgression.internal_name: ToolProgression.option_progressive, + options.SkillProgression.internal_name: options.SkillProgression.option_progressive, + } + + def test_given_access_to_floor_115_when_find_more_tools_then_has_access_to_skull_cavern_25(self): + items_for_115 = self.generate_items_for_mine_115() + items_for_skull_50 = self.generate_items_for_skull_50() + items_for_skull_100 = self.generate_items_for_skull_100() + self.collect(items_for_115) + floor_115 = self.multiworld.get_region(Region.mines_floor_115, self.player) + skull_25 = self.multiworld.get_region(Region.skull_cavern_25, self.player) + skull_75 = self.multiworld.get_region(Region.skull_cavern_75, self.player) + + self.assertTrue(floor_115.can_reach(self.multiworld.state)) + self.assertFalse(skull_25.can_reach(self.multiworld.state)) + self.assertFalse(skull_75.can_reach(self.multiworld.state)) + + self.remove(items_for_115) + self.collect(items_for_skull_50) + + self.assertTrue(floor_115.can_reach(self.multiworld.state)) + self.assertTrue(skull_25.can_reach(self.multiworld.state)) + self.assertFalse(skull_75.can_reach(self.multiworld.state)) + + self.remove(items_for_skull_50) + self.collect(items_for_skull_100) + + self.assertTrue(floor_115.can_reach(self.multiworld.state)) + self.assertTrue(skull_25.can_reach(self.multiworld.state)) + self.assertTrue(skull_75.can_reach(self.multiworld.state)) + + def generate_items_for_mine_115(self) -> List[Item]: + pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 2 + swords = [self.get_item_by_name("Progressive Sword")] * 3 + combat_levels = [self.get_item_by_name("Combat Level")] * 4 + mining_levels = [self.get_item_by_name("Mining Level")] * 4 + guild = self.get_item_by_name("Adventurer's Guild") + bus = self.get_item_by_name("Bus Repair") + skull_key = self.get_item_by_name("Skull Key") + return [*combat_levels, *mining_levels, guild, *pickaxes, *swords, bus, skull_key] + + def generate_items_for_skull_50(self) -> List[Item]: + pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 3 + swords = [self.get_item_by_name("Progressive Sword")] * 4 + combat_levels = [self.get_item_by_name("Combat Level")] * 6 + mining_levels = [self.get_item_by_name("Mining Level")] * 6 + guild = self.get_item_by_name("Adventurer's Guild") + bus = self.get_item_by_name("Bus Repair") + skull_key = self.get_item_by_name("Skull Key") + return [*combat_levels, *mining_levels, guild, *pickaxes, *swords, bus, skull_key] + + def generate_items_for_skull_100(self) -> List[Item]: + pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 4 + swords = [self.get_item_by_name("Progressive Sword")] * 5 + combat_levels = [self.get_item_by_name("Combat Level")] * 8 + mining_levels = [self.get_item_by_name("Mining Level")] * 8 + guild = self.get_item_by_name("Adventurer's Guild") + bus = self.get_item_by_name("Bus Repair") + skull_key = self.get_item_by_name("Skull Key") + return [*combat_levels, *mining_levels, guild, *pickaxes, *swords, bus, skull_key] + + class TestLocationGeneration(SVTestBase): def test_all_location_created_are_in_location_table(self): diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index ded1f37e2e60..d88ad335d1d3 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -53,7 +53,7 @@ def test_sturgeon(self): self.assertFalse(sturgeon_rule(self.multiworld.state)) def test_old_master_cannoli(self): - self.multiworld.state.prog_items = Counter() + 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) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index f8a81d538ce8..37c08ba2e167 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -8,7 +8,7 @@ from test.TestBase import WorldTestBase from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld from .. import StardewValleyWorld -from ..mods.mod_data import ModNames, all_mods +from ..mods.mod_data import all_mods from worlds.AutoWorld import call_all from ..options import Cropsanity, SkillProgression, SpecialOrderLocations, Friendsanity, NumberOfLuckBuffs, SeasonRandomization, ToolProgression, \ ElevatorProgression, Museumsanity, BackpackProgression, BuildingProgression, ArcadeMachineLocations, HelpWantedLocations, Fishsanity, NumberOfMovementBuffs, \ @@ -131,7 +131,7 @@ def allsanity_options_with_mods(): return allsanity -class SVTestCase(WorldTestBase): +class SVTestCase(unittest.TestCase): game = "Stardew Valley" world: StardewValleyWorld player: ClassVar[int] = 1 diff --git a/worlds/stardew_valley/test/checks/option_checks.py b/worlds/stardew_valley/test/checks/option_checks.py index ec17337c71fa..7a014747c256 100644 --- a/worlds/stardew_valley/test/checks/option_checks.py +++ b/worlds/stardew_valley/test/checks/option_checks.py @@ -1,7 +1,7 @@ from BaseClasses import MultiWorld from .world_checks import get_all_item_names, get_all_location_names from .. import SVTestBase -from ... import StardewValleyWorld, options, item_table, Group, location_table +from ... import StardewValleyWorld, options, item_table, Group, location_table, ExcludeGingerIsland from ...locations import LocationTags from ...strings.ap_names.transport_names import Transportation diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index 4e46cf2e0207..3edf4616f43f 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -5,7 +5,7 @@ from Options import NamedRange from .option_names import options_to_include from worlds.stardew_valley.test.checks.world_checks import assert_can_win, assert_same_number_items_locations -from .. import setup_solo_multiworld, SVTestCase +from .. import setup_solo_multiworld, SVTestCase, SVTestBase def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): diff --git a/worlds/stardew_valley/test/long/TestRandomWorlds.py b/worlds/stardew_valley/test/long/TestRandomWorlds.py index 35e4fec22c9d..502f2ad51a0e 100644 --- a/worlds/stardew_valley/test/long/TestRandomWorlds.py +++ b/worlds/stardew_valley/test/long/TestRandomWorlds.py @@ -57,7 +57,7 @@ def get_number_log_steps(number_worlds: int) -> int: return 100 -def generate_and_check_many_worlds(tester: SVTestBase, number_worlds: int, start_index: int) -> Dict[int, MultiWorld]: +def generate_and_check_many_worlds(tester: SVTestCase, number_worlds: int, start_index: int) -> Dict[int, MultiWorld]: num_steps = get_number_log_steps(number_worlds) log_step = number_worlds / num_steps multiworlds = dict() diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 8a57fd3e93b4..93a97b41ab5b 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -44,8 +44,8 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi multiworld = setup_solo_multiworld({EntranceRandomization.internal_name: option, Mods: mod}) basic_checks(self, multiworld) check_stray_mod_items(mod, self, multiworld) - if self.skip_extra_tests: - return # assume the rest will work as well + # if self.skip_extra_tests: + # return # assume the rest will work as well class TestBaseItemGeneration(SVTestBase): From 336a8029d69476c7b0f1f982e2bbd96ff4931994 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 18:22:56 -0500 Subject: [PATCH 137/482] - Created a profiling thing --- worlds/stardew_valley/__init__.py | 10 ++ worlds/stardew_valley/logic/ability_logic.py | 8 ++ worlds/stardew_valley/logic/action_logic.py | 8 +- worlds/stardew_valley/logic/building_logic.py | 3 +- worlds/stardew_valley/logic/cached_logic.py | 108 ++++++++++++++++-- worlds/stardew_valley/logic/combat_logic.py | 3 +- worlds/stardew_valley/logic/cooking_logic.py | 3 +- worlds/stardew_valley/logic/crop_logic.py | 3 +- worlds/stardew_valley/logic/fishing_logic.py | 3 +- worlds/stardew_valley/logic/gift_logic.py | 3 +- worlds/stardew_valley/logic/has_logic.py | 3 +- worlds/stardew_valley/logic/logic.py | 3 +- worlds/stardew_valley/logic/logic_cache.py | 41 ------- worlds/stardew_valley/logic/mine_logic.py | 3 +- worlds/stardew_valley/logic/money_logic.py | 3 +- worlds/stardew_valley/logic/museum_logic.py | 3 +- worlds/stardew_valley/logic/pet_logic.py | 3 +- worlds/stardew_valley/logic/received_logic.py | 3 +- worlds/stardew_valley/logic/region_logic.py | 3 +- .../logic/relationship_logic.py | 3 +- worlds/stardew_valley/logic/season_logic.py | 3 +- worlds/stardew_valley/logic/skill_logic.py | 3 +- worlds/stardew_valley/logic/time_logic.py | 3 +- worlds/stardew_valley/logic/tool_logic.py | 3 +- 24 files changed, 142 insertions(+), 90 deletions(-) delete mode 100644 worlds/stardew_valley/logic/logic_cache.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index c7ac15e2c9db..e9d63f58ea5a 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -8,6 +8,7 @@ from .bundles import get_all_bundles, Bundle from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData +from .logic.cached_logic import function_total_times, function_call_numbers from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS from .logic.bundle_logic import BundleLogic @@ -297,6 +298,15 @@ def first_month_require_all_early_items(state: CollectionState) -> bool: set_rule(first_month_end, first_month_require_all_early_items) def generate_basic(self): + function_call_numbers_sorted = sorted(function_call_numbers, key=lambda x: function_call_numbers[x], reverse=True) + function_total_times_sorted = sorted(function_total_times, key=lambda x: function_total_times[x], reverse=True) + + for function_call_number in function_call_numbers_sorted: + print(f"{function_call_number}: {function_call_numbers[function_call_number]}") + print("\n\n\n\n") + for function_total_time in function_total_times_sorted: + print(f"{function_total_time}: {function_total_times[function_total_time]}") + pass def get_filler_item_name(self) -> str: diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index 0e2cdb03a70e..58197f4d7097 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -1,3 +1,4 @@ +from .cached_logic import profile_rule from .mine_logic import MineLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -40,24 +41,30 @@ def set_magic(self, magic: MagicLogic, mod_skill: ModSkillLogic): self.magic = magic self.mod_skill = mod_skill + @profile_rule def can_mine_perfectly(self) -> StardewRule: return self.mine.can_progress_in_the_mines_from_floor(160) + @profile_rule def can_mine_perfectly_in_the_skull_cavern(self) -> StardewRule: return (self.can_mine_perfectly() & self.region.can_reach(Region.skull_cavern)) + @profile_rule def can_farm_perfectly(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.tool.can_water(4) return tool_rule & self.skill.has_farming_level(10) + @profile_rule def can_fish_perfectly(self) -> StardewRule: skill_rule = self.skill.has_level(Skill.fishing, 10) return skill_rule & self.tool.has_fishing_rod(4) + @profile_rule def can_chop_trees(self) -> StardewRule: return self.tool.has_tool(Tool.axe) & self.region.can_reach(Region.forest) + @profile_rule def can_chop_perfectly(self) -> StardewRule: magic_rule = (self.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.mod_skill.has_mod_level(ModSkill.magic, 10) tool_rule = self.tool.has_tool(Tool.axe, ToolMaterial.iridium) @@ -65,5 +72,6 @@ def can_chop_perfectly(self) -> StardewRule: region_rule = self.region.can_reach(Region.forest) return region_rule & ((tool_rule & foraging_rule) | magic_rule) + @profile_rule def has_max_buffs(self) -> StardewRule: return self.received(Buff.movement, self.movement_buff_option.value) & self.received(Buff.luck, self.luck_buff_option.value) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 33a07606e492..79afad2f1bc8 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,6 +1,5 @@ -from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, cache_rule, profile_rule +from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..stardew_rule import StardewRule, True_, Or @@ -20,15 +19,18 @@ def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLog self.has = has self.region = region + @profile_rule def can_watch(self, channel: str = None): tv_rule = True_() if channel is None: return tv_rule return self.received(channel) & tv_rule + @profile_rule def can_pan(self) -> StardewRule: return self.received("Glittering Boulder Removed") & self.region.can_reach(Region.mountain) + @profile_rule def can_pan_at(self, region: str) -> StardewRule: return self.region.can_reach(region) & self.can_pan() diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 5ea239ad6c6d..e8cca6f68ea3 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,8 +1,7 @@ from typing import Dict from .cached_logic import cache_rule, CachedLogic -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py index 672ed75563c2..40b312aaf722 100644 --- a/worlds/stardew_valley/logic/cached_logic.py +++ b/worlds/stardew_valley/logic/cached_logic.py @@ -1,7 +1,46 @@ import functools -from typing import Union, Callable +import random +import time +from typing import Dict, Callable -from .logic_cache import CachedRules +from ..stardew_rule import StardewRule + +rule_calls = 0 +rule_creations = 0 +time_creating_rules = 0 + + +class CachedRules: + cached_rules: Dict[str, StardewRule] + + def __init__(self): + self.cached_rules = dict() + + def try_get_rule(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + if key not in self.cached_rules: + self.cached_rules[key] = create_rule() + return self.cached_rules[key] + + def try_get_rule_without_cache(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + return create_rule() + + def try_get_rule_with_stats(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + global rule_calls, rule_creations, time_creating_rules + rule_calls += 1 + if key not in self.cached_rules: + rule_creations += 1 + time_before = time.time() + self.cached_rules[key] = create_rule() + time_after = time.time() + time_creating_rules += (time_after - time_before) + if rule_calls % 100000 == 0: + cached_calls = rule_calls - rule_creations + percent_cached_calls = round((cached_calls / rule_calls) * 100) + percent_real_calls = 100 - percent_cached_calls + time_saved = (time_creating_rules / percent_real_calls) * 100 + print(f"Rule Creations/Calls: {rule_creations}/{rule_calls} ({cached_calls} cached calls [{percent_cached_calls}%] saving {time_saved}s" + f" for a total of {time_creating_rules}s creating rules)") + return self.cached_rules[key] class CachedLogic: @@ -11,13 +50,11 @@ class CachedLogic: def __init__(self, player: int, cached_rules: CachedRules): self.player = player self.cached_rules = cached_rules + self.name = type(self).__name__ - def get_cache_key(self, method: Union[str, Callable], *parameters) -> str: - if isinstance(method, Callable): - method = method.__name__ - if parameters is None: - return f"{type(self).__name__} {method}" - return f"{type(self).__name__} {method} {' '.join(map(str, parameters))}" + def get_cache_key(self, method: Callable, *parameters) -> str: + return f"{self.name} {method.__name__} {parameters}" + # return f"{type(self).__name__} {method.__name__} {' '.join(map(str, parameters))}" def cache_rule(func): @@ -27,3 +64,58 @@ def wrapper(self, *args, **kwargs): return self.cached_rules.try_get_rule(key, lambda: func(self, *args, **kwargs)) return wrapper + +time_getting_keys = 0 +time_getting_rules = 0 + + +def cache_rule_with_profiling(func): + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + global time_getting_keys, time_getting_rules + time_before_key = time.time() + key = self.get_cache_key(func, *args) + time_between = time.time() + rule = self.cached_rules.try_get_rule(key, lambda: func(self, *args, **kwargs)) + time_after_rule = time.time() + time_getting_keys += (time_between - time_before_key) + time_getting_rules += (time_after_rule - time_between) + if random.random() < 0.0001: + print(f"Time Getting Keys: {time_getting_keys} seconds") + print(f"Time Getting Rules: {time_getting_rules} seconds") + return rule + return wrapper + + +function_call_numbers = dict() +function_total_times = dict() + + +def profile_rule(func): + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + key = f"{self.__class__.__name__} {func.__name__}" + key_params = f"{self.__class__.__name__} {func.__name__} {args}" + + if key not in function_call_numbers: + function_call_numbers[key] = 0 + if key_params not in function_call_numbers: + function_call_numbers[key_params] = 0 + if key not in function_total_times: + function_total_times[key] = 0 + if key_params not in function_total_times: + function_total_times[key_params] = 0 + + time_before = time.time() + result = func(self, *args, **kwargs) + time_after = time.time() + time_used = time_after - time_before + + function_call_numbers[key] += 1 + function_call_numbers[key_params] += 1 + function_total_times[key] += time_used + function_total_times[key_params] += time_used + + return result + return wrapper + diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 09cf397b1517..8b101f465803 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,5 +1,4 @@ -from .cached_logic import CachedLogic, cache_rule -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, cache_rule, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..mods.logic.magic_logic import MagicLogic diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 2a173ecc2209..4101d5cc1523 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,8 +1,7 @@ from .action_logic import ActionLogic from .building_logic import BuildingLogic from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index a77d710aca96..95f02c5a82af 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,8 +1,7 @@ from typing import Union, Iterable from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 0d1625d4b56f..af5f03e02ab9 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,5 +1,4 @@ -from .cached_logic import cache_rule, CachedLogic -from .logic_cache import CachedRules +from .cached_logic import cache_rule, CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index c82f0bd134f1..2eeff874a647 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,6 +1,5 @@ from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct from ..strings.gift_names import Gift diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index d852ad3c386c..9d24c0ddc2ae 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,7 +1,6 @@ from typing import Dict, Union, Optional, List -from .cached_logic import CachedLogic, cache_rule -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, cache_rule, CachedRules from ..stardew_rule import StardewRule, True_, And, Or, Has, Count diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 47452e7bcb56..9d07e47e46d5 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -15,8 +15,7 @@ from .crop_logic import CropLogic from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic -from .gift_logic import GiftLogic -from .logic_cache import CachedRules +from .gift_logic import GiftLogic, CachedRules from .mine_logic import MineLogic from .money_logic import MoneyLogic from .monster_logic import MonsterLogic diff --git a/worlds/stardew_valley/logic/logic_cache.py b/worlds/stardew_valley/logic/logic_cache.py deleted file mode 100644 index 90fb00a5b55c..000000000000 --- a/worlds/stardew_valley/logic/logic_cache.py +++ /dev/null @@ -1,41 +0,0 @@ -import time -from typing import Dict, Callable - -from ..stardew_rule import StardewRule - -rule_calls = 0 -rule_creations = 0 -time_creating_rules = 0 - - -class CachedRules: - cached_rules: Dict[str, StardewRule] - - def __init__(self): - self.cached_rules = dict() - - def try_get_rule(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: - if key not in self.cached_rules: - self.cached_rules[key] = create_rule() - return self.cached_rules[key] - - def try_get_rule_without_cache(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: - return create_rule() - - def try_get_rule_with_stats(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: - global rule_calls, rule_creations, time_creating_rules - rule_calls += 1 - if key not in self.cached_rules: - rule_creations += 1 - time_before = time.time() - self.cached_rules[key] = create_rule() - time_after = time.time() - time_creating_rules += (time_after - time_before) - if rule_calls % 100000 == 0: - cached_calls = rule_calls - rule_creations - percent_cached_calls = round((cached_calls / rule_calls) * 100) - percent_real_calls = 100 - percent_cached_calls - time_saved = (time_creating_rules / percent_real_calls) * 100 - print(f"Rule Creations/Calls: {rule_creations}/{rule_calls} ({cached_calls} cached calls [{percent_cached_calls}%] saving {time_saved}s" - f" for a total of {time_creating_rules}s creating rules)") - return self.cached_rules[key] diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index c3b19989c50a..c91227a46f3a 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,6 +1,5 @@ from .cached_logic import CachedLogic, cache_rule -from .combat_logic import CombatLogic -from .logic_cache import CachedRules +from .combat_logic import CombatLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .skill_logic import SkillLogic diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 464ad63a5fd6..14f9f8aa5cc2 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,6 +1,5 @@ from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 7eaf516fd54f..ae68792fefbf 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -2,8 +2,7 @@ from .action_logic import ActionLogic from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals from ..options import Museumsanity diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 450160bc5f65..72042d0c0d81 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -2,8 +2,7 @@ from typing import Union -from .cached_logic import CachedLogic -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index e01db08f5624..96938b48f33c 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,7 +1,6 @@ from typing import Iterable, Union, Optional -from .cached_logic import CachedLogic, cache_rule -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, cache_rule, CachedRules from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 1552eb0a3585..d6a1e1faa4e4 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,7 +1,6 @@ from typing import Iterable, List -from .cached_logic import CachedLogic, cache_rule -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, cache_rule, CachedRules from ..stardew_rule import StardewRule, And, Or, Reach, Count diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 82bf54b6696a..3a2b987434e8 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -5,8 +5,7 @@ from .building_logic import BuildingLogic from .cached_logic import CachedLogic, cache_rule from .gift_logic import GiftLogic -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 37889fb2f6fe..3b494e9df5f0 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,7 +1,6 @@ from typing import Iterable -from .cached_logic import cache_rule, CachedLogic -from .logic_cache import CachedRules +from .cached_logic import cache_rule, CachedLogic, CachedRules from .received_logic import ReceivedLogic from .time_logic import TimeLogic from ..options import SeasonRandomization diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 13588bc0f241..e9b85c427da1 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -3,8 +3,7 @@ from .cached_logic import CachedLogic, cache_rule from .combat_logic import CombatLogic from .crop_logic import CropLogic -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 3ea19f25bce0..1b7450b7d226 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,5 +1,4 @@ -from .cached_logic import CachedLogic, cache_rule -from .logic_cache import CachedRules +from .cached_logic import CachedLogic, cache_rule, CachedRules from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule from ..strings.ap_names.event_names import Event diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index b1320b0ccd09..0fcc0cc76649 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,6 +1,5 @@ from .cached_logic import CachedLogic, cache_rule -from .has_logic import HasLogic -from .logic_cache import CachedRules +from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic From 9a480e7e562925dd31efa76f54c5e584f322351f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 19:07:43 -0500 Subject: [PATCH 138/482] - profiling stuff removed --- worlds/stardew_valley/__init__.py | 9 --------- worlds/stardew_valley/data/bundle_data.py | 2 +- worlds/stardew_valley/data/recipe_source.py | 9 ++++----- worlds/stardew_valley/logic/ability_logic.py | 7 ------- worlds/stardew_valley/logic/action_logic.py | 3 --- worlds/stardew_valley/logic/arcade_logic.py | 1 + worlds/stardew_valley/logic/artisan_logic.py | 13 +------------ worlds/stardew_valley/logic/building_logic.py | 2 +- worlds/stardew_valley/logic/bundle_logic.py | 10 ++++++---- worlds/stardew_valley/logic/cooking_logic.py | 5 ++++- worlds/stardew_valley/logic/crafting_logic.py | 15 ++++++++++----- worlds/stardew_valley/logic/crop_logic.py | 2 +- worlds/stardew_valley/logic/farming_logic.py | 1 + worlds/stardew_valley/logic/fishing_logic.py | 2 +- worlds/stardew_valley/logic/logic.py | 10 +++++----- worlds/stardew_valley/logic/mine_logic.py | 2 +- worlds/stardew_valley/logic/monster_logic.py | 12 ++++++++---- worlds/stardew_valley/logic/museum_logic.py | 2 +- worlds/stardew_valley/logic/pet_logic.py | 2 +- worlds/stardew_valley/logic/quest_logic.py | 1 + worlds/stardew_valley/logic/relationship_logic.py | 2 +- worlds/stardew_valley/logic/shipping_logic.py | 10 ++++++---- .../stardew_valley/logic/special_order_logic.py | 1 + worlds/stardew_valley/logic/time_logic.py | 2 +- .../logic/traveling_merchant_logic.py | 1 + worlds/stardew_valley/logic/wallet_logic.py | 1 + 26 files changed, 59 insertions(+), 68 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index e9d63f58ea5a..e1a4ae56405f 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -298,15 +298,6 @@ def first_month_require_all_early_items(state: CollectionState) -> bool: set_rule(first_month_end, first_month_require_all_early_items) def generate_basic(self): - function_call_numbers_sorted = sorted(function_call_numbers, key=lambda x: function_call_numbers[x], reverse=True) - function_total_times_sorted = sorted(function_total_times, key=lambda x: function_total_times[x], reverse=True) - - for function_call_number in function_call_numbers_sorted: - print(f"{function_call_number}: {function_call_numbers[function_call_number]}") - print("\n\n\n\n") - for function_total_time in function_total_times_sorted: - print(f"{function_total_time}: {function_total_times[function_total_time]}") - pass def get_filler_item_name(self) -> str: diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 817ebc64c81b..03910b836c9c 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -23,7 +23,7 @@ def item_bundle(name: str, item_id: int, amount: int = 1, quality: int = 0): @staticmethod def money_bundle(amount: int): - return BundleItem.item_bundle("Money", -1, amount, amount) + return BundleItem.item_bundle("Money", -1, amount, 0) def as_amount(self, amount: int): return BundleItem.item_bundle(self.item.name, self.item.item_id, amount, self.quality) diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index 5db2fab17c11..0e259a4134d6 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -22,7 +22,7 @@ def __init__(self, ap_item: Union[str, List[str]]): self.ap_item = ap_item def __repr__(self): - return f"ArchipelagoSource {ap_item}" + return f"ArchipelagoSource {self.ap_item}" class LogicSource(RecipeSource): @@ -32,7 +32,7 @@ def __init__(self, logic_rule: str): self.logic_rule = logic_rule def __repr__(self): - return f"LogicSource {logic_rule}" + return f"LogicSource {self.logic_rule}" class QueenOfSauceSource(RecipeSource): @@ -69,7 +69,7 @@ def __init__(self, region: str, friend: str, hearts: int): self.region = region def __repr__(self): - return f"CutsceneSource at {region}" + return f"CutsceneSource at {self.region}" class SkillSource(RecipeSource): @@ -113,7 +113,6 @@ def __repr__(self): return f"ShopTradeSource at {self.region} costing {self.price} {self.currency}" - class SpecialOrderSource(RecipeSource): special_order: str @@ -122,4 +121,4 @@ def __init__(self, special_order: str): def __repr__(self): - return f"SpecialOrderSource from {special_order}" + return f"SpecialOrderSource from {self.special_order}" diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index 58197f4d7097..e2403a126148 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -41,30 +41,24 @@ def set_magic(self, magic: MagicLogic, mod_skill: ModSkillLogic): self.magic = magic self.mod_skill = mod_skill - @profile_rule def can_mine_perfectly(self) -> StardewRule: return self.mine.can_progress_in_the_mines_from_floor(160) - @profile_rule def can_mine_perfectly_in_the_skull_cavern(self) -> StardewRule: return (self.can_mine_perfectly() & self.region.can_reach(Region.skull_cavern)) - @profile_rule def can_farm_perfectly(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.tool.can_water(4) return tool_rule & self.skill.has_farming_level(10) - @profile_rule def can_fish_perfectly(self) -> StardewRule: skill_rule = self.skill.has_level(Skill.fishing, 10) return skill_rule & self.tool.has_fishing_rod(4) - @profile_rule def can_chop_trees(self) -> StardewRule: return self.tool.has_tool(Tool.axe) & self.region.can_reach(Region.forest) - @profile_rule def can_chop_perfectly(self) -> StardewRule: magic_rule = (self.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.mod_skill.has_mod_level(ModSkill.magic, 10) tool_rule = self.tool.has_tool(Tool.axe, ToolMaterial.iridium) @@ -72,6 +66,5 @@ def can_chop_perfectly(self) -> StardewRule: region_rule = self.region.can_reach(Region.forest) return region_rule & ((tool_rule & foraging_rule) | magic_rule) - @profile_rule def has_max_buffs(self) -> StardewRule: return self.received(Buff.movement, self.movement_buff_option.value) & self.received(Buff.luck, self.luck_buff_option.value) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 79afad2f1bc8..a005dfe850d5 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -19,18 +19,15 @@ def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLog self.has = has self.region = region - @profile_rule def can_watch(self, channel: str = None): tv_rule = True_() if channel is None: return tv_rule return self.received(channel) & tv_rule - @profile_rule def can_pan(self) -> StardewRule: return self.received("Glittering Boulder Removed") & self.region.can_reach(Region.mountain) - @profile_rule def can_pan_at(self, region: str) -> StardewRule: return self.region.can_reach(region) & self.can_pan() diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index 336bd82809a0..aed6498eaba0 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,3 +1,4 @@ +from .cached_logic import profile_rule from .. import options from ..options import ArcadeMachineLocations from ..stardew_rule import StardewRule, True_ diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 388a8bc7fbef..32821990a020 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -1,5 +1,6 @@ from typing import Union +from .cached_logic import profile_rule from .has_logic import HasLogic from .time_logic import TimeLogic from ..stardew_rule import StardewRule @@ -50,17 +51,5 @@ def can_keg(self, item: str) -> StardewRule: return machine_rule & self.has(all_vegetables, 1) return machine_rule & self.has(item) - def can_age(self, item: Union[str, StardewRule], quality: str) -> StardewRule: - months = 1 - if quality == "Gold": - months = 2 - elif quality == "Iridium": - months = 3 - if isinstance(item, str): - rule = self.has(item) - else: - rule: StardewRule = item - return self.has(Machine.cask) & self.time.has_lived_months(months) & rule - def can_mayonnaise(self, item: str) -> StardewRule: return self.has(Machine.mayonnaise_machine) & self.has(item) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index e8cca6f68ea3..c11065d6b74b 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,6 +1,6 @@ from typing import Dict -from .cached_logic import cache_rule, CachedLogic +from .cached_logic import cache_rule, CachedLogic, profile_rule from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 54fdb1555489..1f6fb0eb4066 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,5 +1,6 @@ from typing import List +from .cached_logic import profile_rule, cache_rule, CachedLogic, CachedRules from ..data.bundle_data import BundleItem from .farming_logic import FarmingLogic from .has_logic import HasLogic @@ -9,20 +10,20 @@ from ..strings.region_names import Region -class BundleLogic: - player: int +class BundleLogic(CachedLogic): has: HasLogic region: RegionLogic money: MoneyLogic farming: FarmingLogic - def __init__(self, player: int, has: HasLogic, region: RegionLogic, money: MoneyLogic, farming: FarmingLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic, region: RegionLogic, money: MoneyLogic, farming: FarmingLogic): + super().__init__(player, cached_rules) self.has = has self.region = region self.money = money self.farming = farming + @cache_rule def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: item_rules = [] highest_quality_yet = 0 @@ -36,6 +37,7 @@ def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_requ highest_quality_yet = bundle_item.quality return can_speak_junimo & self.has(item_rules, number_required) & self.farming.can_grow_crop_quality(highest_quality_yet) + @cache_rule def can_complete_community_center(self) -> StardewRule: return (self.region.can_reach_location("Complete Crafts Room") & self.region.can_reach_location("Complete Pantry") & diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 4101d5cc1523..7f5eaeb331c7 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,6 +1,6 @@ from .action_logic import ActionLogic from .building_logic import BuildingLogic -from .cached_logic import CachedLogic, cache_rule +from .cached_logic import CachedLogic, cache_rule, profile_rule from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -54,6 +54,7 @@ def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanit self.relationship = relationship self.skill = skill + @cache_rule def can_cook_in_kitchen(self) -> StardewRule: return self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) @@ -108,9 +109,11 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule return False_() + @cache_rule def received_recipe(self, meal_name: str): return self.received(f"{meal_name} Recipe") + @cache_rule def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " all_recipes_names = [] diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 05df8a8290a3..709a8d2a2cb1 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,3 +1,4 @@ +from .cached_logic import profile_rule, cache_rule, CachedLogic, CachedRules from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -15,8 +16,7 @@ from ..strings.region_names import Region -class CraftingLogic: - player: int +class CraftingLogic(CachedLogic): craftsanity_option: Craftsanity festivals_option: FestivalLocations special_orders_option: SpecialOrderLocations @@ -29,9 +29,10 @@ class CraftingLogic: skill: SkillLogic special_orders: SpecialOrderLogic - def __init__(self, player: int, craftsanity_option: Craftsanity, festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, - time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: Craftsanity, festivals_option: FestivalLocations, + special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, + money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): + super().__init__(player, cached_rules) self.craftsanity_option = craftsanity_option self.festivals_option = festivals_option self.special_orders_option = special_orders_option @@ -44,6 +45,7 @@ def __init__(self, player: int, craftsanity_option: Craftsanity, festivals_optio self.skill = skill self.special_orders = special_orders + @cache_rule def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: craft_rule = True_() if recipe is None: @@ -55,6 +57,7 @@ def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: time_rule = self.time.has_lived_months(number_ingredients) return craft_rule & learn_rule & ingredients_rule & time_rule + @cache_rule def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, ArchipelagoSource): return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) @@ -71,6 +74,7 @@ def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: return self.received_recipe(recipe.item) return self.can_learn_recipe(recipe) + @cache_rule def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, StarterSource): return True_() @@ -96,5 +100,6 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: return False_() + @cache_rule def received_recipe(self, item_name: str): return self.received(f"{item_name} Recipe") diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 95f02c5a82af..ac48b769bd91 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,6 +1,6 @@ from typing import Union, Iterable -from .cached_logic import CachedLogic, cache_rule +from .cached_logic import CachedLogic, cache_rule, profile_rule from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 6c2e5b1107cb..114b49902754 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -1,3 +1,4 @@ +from .cached_logic import profile_rule from .has_logic import HasLogic from ..stardew_rule import StardewRule, True_ from .skill_logic import SkillLogic diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index af5f03e02ab9..ed0fc5f22496 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,4 +1,4 @@ -from .cached_logic import cache_rule, CachedLogic, CachedRules +from .cached_logic import cache_rule, CachedLogic, CachedRules, profile_rule from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9d07e47e46d5..7871046a4b97 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -123,20 +123,20 @@ def __post_init__(self): mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island self.buildings = BuildingLogic(self.player, self.cached_rules, self.options.building_progression, self.received, self.has, self.region, self.money) - self.shipping = ShippingLogic(self.player, exclude_ginger_island, special_order_locations, self.has, + self.shipping = ShippingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.has, self.region, self.buildings) self.relationship = RelationshipLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.cached_rules, self.options.museumsanity, self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) self.combat = CombatLogic(self.player, self.cached_rules, self.received, self.region) - self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) + self.monster = MonsterLogic(self.player, self.cached_rules, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, self.cached_rules, tool_option, self.received, self.has, self.region, self.season, self.money) self.pet = PetLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, self.received, self.has, self.region, self.traveling_merchant, self.season, self.money, self.tool) self.skill = SkillLogic(self.player, self.cached_rules, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) self.farming = FarmingLogic(self.player, self.has, self.skill) - self.bundle = BundleLogic(self.player, self.has, self.region, self.money, self.farming) + self.bundle = BundleLogic(self.player, self.cached_rules, self.has, self.region, self.money, self.farming) self.fishing = FishingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, self.tool, self.skill) self.mine = MineLogic(self.player, self.cached_rules, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) @@ -147,7 +147,7 @@ def __post_init__(self): self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, self.time, self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, self.wallet, mods_option) - self.crafting = CraftingLogic(self.player, self.options.craftsanity, self.options.festival_locations, + self.crafting = CraftingLogic(self.player, self.cached_rules, self.options.craftsanity, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, self.season, self.money, @@ -603,7 +603,7 @@ def can_succeed_luau_soup(self) -> StardewRule: Fruit.starfruit, Fruit.strawberry, Forageable.cactus_fruit, Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, Vegetable.hops, Vegetable.wheat] keg_rules = [self.artisan.can_keg(kegable) for kegable in eligible_kegables] - aged_rule = [self.artisan.can_age(rule, "Iridium") for rule in keg_rules] + aged_rule = self.has(Machine.cask) & Or(keg_rules) # There are a few other valid items but I don't feel like coding them all return Or(fish_rule) | Or(aged_rule) diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index c91227a46f3a..67359ddfe5c4 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,4 +1,4 @@ -from .cached_logic import CachedLogic, cache_rule +from .cached_logic import CachedLogic, cache_rule, profile_rule from .combat_logic import CombatLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 60f36e6f9e47..b980ef219c1e 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,5 +1,6 @@ from typing import Iterable, Union +from .cached_logic import CachedLogic, CachedRules, cache_rule from .combat_logic import CombatLogic from .region_logic import RegionLogic from .time_logic import TimeLogic, MAX_MONTHS @@ -7,18 +8,18 @@ from ..stardew_rule import StardewRule, Or, And -class MonsterLogic: - player: int +class MonsterLogic(CachedLogic): region: RegionLogic time: TimeLogic combat: CombatLogic - def __init__(self, player: int, region: RegionLogic, time: TimeLogic, combat: CombatLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, region: RegionLogic, time: TimeLogic, combat: CombatLogic): + super().__init__(player, cached_rules) self.region = region self.time = time self.combat = combat + @cache_rule def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): monster = all_monsters_by_name[monster] @@ -29,13 +30,16 @@ def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> time_rule = self.time.has_lived_months(amount_tier * 2) return region_rule & combat_rule & time_rule + @cache_rule def can_kill_max(self, monster: StardewMonster) -> StardewRule: return self.can_kill(monster, MAX_MONTHS) + @cache_rule def can_kill_any(self, monsters: Iterable[StardewMonster], amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] return Or(rules) + @cache_rule def can_kill_all(self, monsters: Iterable[StardewMonster], amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] return And(rules) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index ae68792fefbf..9857114bb655 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -1,7 +1,7 @@ from typing import List from .action_logic import ActionLogic -from .cached_logic import CachedLogic, cache_rule +from .cached_logic import CachedLogic, cache_rule, profile_rule from .has_logic import HasLogic, CachedRules from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 72042d0c0d81..bb2a1b17b741 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -2,7 +2,7 @@ from typing import Union -from .cached_logic import CachedLogic, CachedRules +from .cached_logic import CachedLogic, CachedRules, profile_rule from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 9907411f4eef..780be49ed189 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -3,6 +3,7 @@ from .action_logic import ActionLogic from .building_logic import BuildingLogic +from .cached_logic import profile_rule from .combat_logic import CombatLogic from .cooking_logic import CookingLogic from .fishing_logic import FishingLogic diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 3a2b987434e8..f2e1573e9681 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -3,7 +3,7 @@ from typing import Iterable, Union from .building_logic import BuildingLogic -from .cached_logic import CachedLogic, cache_rule +from .cached_logic import CachedLogic, cache_rule, profile_rule from .gift_logic import GiftLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 39f0fd6d3b2a..f1d27bde93cd 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,5 +1,6 @@ from .building_logic import BuildingLogic +from .cached_logic import profile_rule, CachedLogic, CachedRules, cache_rule from .has_logic import HasLogic from .region_logic import RegionLogic from ..options import ExcludeGingerIsland @@ -10,16 +11,16 @@ from ..strings.region_names import Region -class ShippingLogic: - player: int +class ShippingLogic(CachedLogic): exclude_ginger_island: ExcludeGingerIsland special_orders_option: SpecialOrderLocations has: HasLogic region: RegionLogic buildings: BuildingLogic - def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations, has: HasLogic, region: RegionLogic, buildings: BuildingLogic): - self.player = player + def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations, + has: HasLogic, region: RegionLogic, buildings: BuildingLogic): + super().__init__(player, cached_rules) self.exclude_ginger_island = exclude_ginger_island self.special_orders_option = special_orders_option self.has = has @@ -29,6 +30,7 @@ def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, spec def can_use_shipping_bin(self, item: str = "") -> StardewRule: return self.buildings.has_building(Building.shipping_bin) + @cache_rule def can_ship(self, item: str = "") -> StardewRule: shipping_rule = self.region.can_reach(Region.shipping) if item == "": diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index aa2ec6de1ae7..a3bd2ff97955 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -3,6 +3,7 @@ from .ability_logic import AbilityLogic from .arcade_logic import ArcadeLogic from .artisan_logic import ArtisanLogic +from .cached_logic import profile_rule from .cooking_logic import CookingLogic from .has_logic import HasLogic from .mine_logic import MineLogic diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 1b7450b7d226..3f4c1a2b27d0 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,4 +1,4 @@ -from .cached_logic import CachedLogic, cache_rule, CachedRules +from .cached_logic import CachedLogic, cache_rule, CachedRules, profile_rule from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule from ..strings.ap_names.event_names import Event diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index bf74d9e1c6ca..b70847c60c27 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,3 +1,4 @@ +from .cached_logic import profile_rule from .received_logic import ReceivedLogic from ..stardew_rule import True_ from ..strings.calendar_names import Weekday diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index 753c3aa5dd31..c2f2110fa25f 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,3 +1,4 @@ +from .cached_logic import profile_rule from .museum_logic import MuseumLogic from ..stardew_rule import StardewRule from .received_logic import ReceivedLogic From cbd4f548d343608bdaec946f68d3d488475ac34b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 20:24:59 -0500 Subject: [PATCH 139/482] Created some performance tests to check things --- worlds/stardew_valley/test/__init__.py | 2 +- .../performance/TestOptionsPerformance.py | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 worlds/stardew_valley/test/performance/TestOptionsPerformance.py diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 37c08ba2e167..b8f8923fe88f 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -5,7 +5,7 @@ from BaseClasses import MultiWorld, CollectionState from Utils import cache_argsless -from test.TestBase import WorldTestBase +from test.bases import WorldTestBase from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld from .. import StardewValleyWorld from ..mods.mod_data import all_mods diff --git a/worlds/stardew_valley/test/performance/TestOptionsPerformance.py b/worlds/stardew_valley/test/performance/TestOptionsPerformance.py new file mode 100644 index 000000000000..9175b24aa9d2 --- /dev/null +++ b/worlds/stardew_valley/test/performance/TestOptionsPerformance.py @@ -0,0 +1,66 @@ +import time + +from BaseClasses import get_seed +from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, \ + allsanity_options_with_mods, setup_multiworld, default_options + +number_generations = 5 + + +def performance_test_multiworld(tester, options, option_text): + number_players = len(options) + total_time = 0 + all_times = {} + for i in range(number_generations): + seed = get_seed() + time_before = time.time() + multiworld = setup_multiworld(options, seed) + time_after = time.time() + elapsed_time = time_after - time_before + total_time += elapsed_time + all_times[i] = elapsed_time + size = size_name(number_players) + average_time = total_time / number_generations + # Remove outliers + num_outliers = 0 + for world in all_times: + if all_times[world] > average_time * 4: + num_outliers += 1 + total_time -= all_times[world] + average_time = total_time / (number_generations - num_outliers) + print(f"{option_text}:") + print(f"\tGenerated {(number_generations - num_outliers)} {size} multiworlds in {total_time} seconds") + print(f"\tAverage time per world: {average_time} seconds") + return average_time + + +def size_name(number_players): + if number_players == 1: + return "solo" + elif number_players == 2: + return "duo" + elif number_players == 3: + return "trio" + return f"{number_players}-player" + + +class TestIndividualAllsanityOptions(SVTestCase): + + def test_solo(self): + if self.skip_performance_tests: + return + times = dict() + allsanity_options = allsanity_options_without_mods() + for option1 in allsanity_options: + for option2 in allsanity_options: + if option1 == option2: + continue + options_text = f"{option1}: {allsanity_options[option1]}, {option2}: {allsanity_options[option2]}" + with self.subTest(options_text): + multiworld_options = dict(minimal_locations_maximal_items()) + multiworld_options[option1] = allsanity_options[option1] + multiworld_options[option2] = allsanity_options[option2] + times[options_text] = performance_test_multiworld(self, [multiworld_options], options_text) + sorted_times = sorted(times, key=lambda x: times[x], reverse=True) + for options in sorted_times: + print(f"{options}: {times[options]}") From 13231c7f526f8ef33641502e9e15c11bddd3cacb Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 20:28:22 -0500 Subject: [PATCH 140/482] - Updated the number of locations --- worlds/stardew_valley/test/TestGeneration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 6deadf176ff8..c40fa5804797 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -358,7 +358,7 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1948 + expected_locations = 1950 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -372,7 +372,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2200 + expected_locations = 2423 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) From b5559c93352f1e6579a34885f3fe6ed3eac4bd0a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 20:29:52 -0500 Subject: [PATCH 141/482] - Updated minmax locations --- worlds/stardew_valley/test/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index b8f8923fe88f..415bc058343f 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -78,6 +78,9 @@ def minimal_locations_maximal_items(): Museumsanity.internal_name: Museumsanity.option_none, Monstersanity.internal_name: Monstersanity.option_none, Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_none, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, FriendsanityHeartSize.internal_name: 8, NumberOfMovementBuffs.internal_name: 12, From da01988126ec9a383246773e6c6689d36ccd323d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 14 Nov 2023 07:30:57 -0500 Subject: [PATCH 142/482] - Add back kwargs # Conflicts: # worlds/stardew_valley/logic/cached_logic.py --- worlds/stardew_valley/logic/cached_logic.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py index 40b312aaf722..cea431118c07 100644 --- a/worlds/stardew_valley/logic/cached_logic.py +++ b/worlds/stardew_valley/logic/cached_logic.py @@ -16,9 +16,9 @@ class CachedRules: def __init__(self): self.cached_rules = dict() - def try_get_rule(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + def try_get_rule(self, key: str, create_rule, *args, **kwargs) -> StardewRule: if key not in self.cached_rules: - self.cached_rules[key] = create_rule() + self.cached_rules[key] = create_rule(*args, **kwargs) return self.cached_rules[key] def try_get_rule_without_cache(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: @@ -52,16 +52,16 @@ def __init__(self, player: int, cached_rules: CachedRules): self.cached_rules = cached_rules self.name = type(self).__name__ - def get_cache_key(self, method: Callable, *parameters) -> str: - return f"{self.name} {method.__name__} {parameters}" + def get_cache_key(self, method: Callable, *parameters, **kwargs) -> str: + return f"{self.name} {method.__name__} {parameters} {kwargs}" # return f"{type(self).__name__} {method.__name__} {' '.join(map(str, parameters))}" def cache_rule(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): - key = self.get_cache_key(func, *args) - return self.cached_rules.try_get_rule(key, lambda: func(self, *args, **kwargs)) + key = self.get_cache_key(func, *args, **kwargs) + return self.cached_rules.try_get_rule(key, func, self, *args, **kwargs) return wrapper From b9cac2636bc7cac6b0397ddb93ac5f503f7ae3de Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 14 Nov 2023 07:31:27 -0500 Subject: [PATCH 143/482] Simplify on call only # Conflicts: # worlds/stardew_valley/logic/fishing_logic.py # worlds/stardew_valley/rules.py # worlds/stardew_valley/stardew_rule.py --- disabled yamls/AP_13458270422501645045.zip | Bin 0 -> 71036 bytes disabled yamls/DLCPlayer.yaml | 14 + disabled yamls/DLCTester.yaml | 13 + disabled yamls/DragorrodSV.yaml | 528 ++++++++++++++ disabled yamls/GiftReceiver.yaml | 41 ++ disabled yamls/GiftSender.yaml | 41 ++ disabled yamls/Kat.yaml | 40 ++ disabled yamls/NevaSV.yaml | 527 ++++++++++++++ disabled yamls/Plandark.yaml | 86 +++ disabled yamls/Plandew.yaml | 489 +++++++++++++ disabled yamls/Plandow.yaml | 87 +++ .../RC1/CaitSith2-ALttP_-_Copy.yaml | 670 ++++++++++++++++++ disabled yamls/RC1/DOOMBeta.yaml | 164 +++++ disabled yamls/RC1/Dragus_DOOM_world.yaml | 53 ++ disabled yamls/RC1/Fatman_Main.yaml | 444 ++++++++++++ disabled yamls/RC1/Figment-SDV-4xx-MA.yaml | 190 +++++ disabled yamls/RC1/Forsaken_Terraria.yaml | 120 ++++ disabled yamls/RC1/KenderUT_Neutral.yaml | 17 + disabled yamls/RC1/Parker.yaml | 24 + disabled yamls/RC1/Phar.yaml | 504 +++++++++++++ ...k_SMZ3_early_sword_early_sword_normal.yaml | 19 + .../RC1/RiversHappyMusicAndViciousDemons.yaml | 279 ++++++++ disabled yamls/RC1/Seto_Undertale.yaml | 93 +++ disabled yamls/RC1/Sheen-SDV4.yaml | 155 ++++ disabled yamls/RC1/SilvrisTerraria.yaml | 120 ++++ disabled yamls/RC1/dennisw100_Terraria.yaml | 17 + disabled yamls/RC1/speedweedDOOM.yaml | 178 +++++ disabled yamls/Stardew Valley.yaml | 469 ++++++++++++ disabled yamls/Stardew allsanity.yaml | 39 + disabled yamls/StardewRace.yaml | 42 ++ disabled yamls/StardewTester.yaml | 48 ++ disabled yamls/Stardew_Valley.yaml | 41 ++ disabled yamls/Tester - 3.x.x.yaml | 34 + worlds/stardew_valley/__init__.py | 24 +- worlds/stardew_valley/logic/fishing_logic.py | 2 +- worlds/stardew_valley/rules.py | 304 ++++---- worlds/stardew_valley/stardew_rule.py | 21 +- 37 files changed, 5768 insertions(+), 169 deletions(-) create mode 100644 disabled yamls/AP_13458270422501645045.zip create mode 100644 disabled yamls/DLCPlayer.yaml create mode 100644 disabled yamls/DLCTester.yaml create mode 100644 disabled yamls/DragorrodSV.yaml create mode 100644 disabled yamls/GiftReceiver.yaml create mode 100644 disabled yamls/GiftSender.yaml create mode 100644 disabled yamls/Kat.yaml create mode 100644 disabled yamls/NevaSV.yaml create mode 100644 disabled yamls/Plandark.yaml create mode 100644 disabled yamls/Plandew.yaml create mode 100644 disabled yamls/Plandow.yaml create mode 100644 disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml create mode 100644 disabled yamls/RC1/DOOMBeta.yaml create mode 100644 disabled yamls/RC1/Dragus_DOOM_world.yaml create mode 100644 disabled yamls/RC1/Fatman_Main.yaml create mode 100644 disabled yamls/RC1/Figment-SDV-4xx-MA.yaml create mode 100644 disabled yamls/RC1/Forsaken_Terraria.yaml create mode 100644 disabled yamls/RC1/KenderUT_Neutral.yaml create mode 100644 disabled yamls/RC1/Parker.yaml create mode 100644 disabled yamls/RC1/Phar.yaml create mode 100644 disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml create mode 100644 disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml create mode 100644 disabled yamls/RC1/Seto_Undertale.yaml create mode 100644 disabled yamls/RC1/Sheen-SDV4.yaml create mode 100644 disabled yamls/RC1/SilvrisTerraria.yaml create mode 100644 disabled yamls/RC1/dennisw100_Terraria.yaml create mode 100644 disabled yamls/RC1/speedweedDOOM.yaml create mode 100644 disabled yamls/Stardew Valley.yaml create mode 100644 disabled yamls/Stardew allsanity.yaml create mode 100644 disabled yamls/StardewRace.yaml create mode 100644 disabled yamls/StardewTester.yaml create mode 100644 disabled yamls/Stardew_Valley.yaml create mode 100644 disabled yamls/Tester - 3.x.x.yaml diff --git a/disabled yamls/AP_13458270422501645045.zip b/disabled yamls/AP_13458270422501645045.zip new file mode 100644 index 0000000000000000000000000000000000000000..a77f5f46d438756fe35d2f3d155cdd214eb5936e GIT binary patch literal 71036 zcmV(%K;pkpO9KQH000080Ay@FR~K%y3GUGV014Ls03!eZ06|b+F*7tZI5IadG%_+Z zFfleXH833N$}!w2L&Y6 zbXJw^wortO)_pjC8iS~oR;iiN1NgJ2&ozG~Z@kam*vJm1y4`=M1z4wXuP8`x`AWcn->hom($z{`tJ9yZ zEd$1K*#VOCu_4``a_9USX zhUW|~6BT_qyZAWD9F20aS}iI`M;ZcjL+otBtp9vCNh;_|ix=XwG?V-Ow)byRfsST^ zJF|IN%|%nLX{}bf_!kck@4e@Y+9A{h0SBq(qDNn5W|tu2XRQ~Gi!o*ic*pdLAzwHN zfC5AZ;-FC=^$~PXaR52+INWiNa-eb$c3{f`{l{r^>nrfMXH2<+1ktuNeM`1+! zmHI2iS9%M80?3CCEr|36YLX-XIjAit73gjQrvdK3004arWetlF{Ra>mARf+=ck4C< zA7BK&4%B{3^_koWpbO9i4gbBadW5R>GG6Fp6cmA0$2kXmR8UJPdFNIwZl7_<+$s zWE4CGKqOV62`0q|q9u{*Z~=fJC>Nwc8%&N7MJpmt;mm+HKnai?sGTO53?qz|Mef1n z0p6fhP&;if1x6hG2zdji2XKQ_K@b`&DMkn_jogL@z$F0opiU5k7E6v1L)*j8;k590 z_z{2;egw<{WC5)K)<7@-N{S=J%HMy}_?Y>zIg$?U1?L2=03QJ!0XqN-@Kv}foa3?h zefrPzf`Bu!Gm^WYj{rQ71n>(U0e=GThUWm3NdkfURD!^L@_Ei03I{`^Hy{ic4TuI^ zknfYsGuLoCusFbwK97YQNb_in=vZ#Ckg?FRkg!m*P$&R=?xXJ`yWwhp7*HR{L%>7O zL*PS_Vn8vd7$^*w0;a-Q;TdpCcn_c+XbSHE`U7U*E$|Td6`Tyt3(y25fN)Gk6d1rK zz$f52TrdwfPWb_t3GjUk8mCd<`b=5~aC=N%Lt1mUhGrb30K_OGW8ujF0TKgXHkAUc zj}n>&c?5I;rIAjKk(;uJVmA2PHATm)zitRlA|`N8DFi4H~D1LXl;q|2l~SbeC`-f&sCHL$sMCnu_y zVxIdy4kIcSpdd*Ki3Ugms6o;P=mYfu=>Qy*3Y0$op>HGe;m3gA$*C})&8;6)KC*e% zB1)2Z%6Sxd0(s1NT(`+&0Bk_X$Bg&sv;djFev&WnyZ31a0BL|UP#Q3oOobwt3j=Zx zL#rco;pxC?fE`&oc`zr29IcPEhBpI`0IOu}6v5mWAX*Kn2~Pwf0IFmVax6y;9fl08 zi!_H<15toZG8}acR}HX+%%~LB|_E&LWd7Oo8+gbTsT;BIg#kCo97BpI9<$P5%Gw*g@p(Jzp%;ln@}xeX9Yjn+Y$ z!pnhkfGRQ@iXU7Ub0jUC9Vid)4mY;pxoA9D01TpBnG ztc2f#r@~F)^#D(JJrD+f0I;_)3}{EB0NfCW0IE{xsj~Ob{y)rB0NuEmb-wVfwY4x^ z$2Y0TE2iR@i2BJ){DdyQ|MuvDJIc!zN_(+SdO`Kmh@^;IgZ(S8l$68SK`xK#zd0m` zq@NJ;fbpFGjmo`u3B<0R-Ggq$r6~VqifvE&#eZuMi1{sunILTAfga{0pxz+}&E0)H zbvi$5RCPHh*#RqU9u$7SkS7BaXR=1Fc?y(m?DG_bP+j7ZpNZ8hb$tmlC9}OcEB}hRk+{D(?IUNa||V*BHt4|E$Rc9pHClV%oq9L z;xfL~n&E3}{K6ZNnF}v&_QXeoDr~~uBUj9++l~3_HaYBIuD4}>9NqdB--Wlfggm+E z9-4D{em?SFQU_m>s)0TT4#Em;sk zGpJmiN_2_OXPH}EqM|~HK(sK z7wDJrt%?lE@4B01&7*02N4HB`H68ZxppslcegaLW7XoHT{zS!9tFXCE zb6>VjTjwC>LnC6CxGXF}!Yh%xzd*xmWU609^zSD;Y;Dr<1E-B_8#Kf*aP*ZweGW!nb4Z;jIv8$zr>aZ5J^UaK z`k2)us&%dTfGm~F#}%rjH2;S3Sn~cJ-C*}E4#&9x^E5l9K*;7Fz03Lc-=-sXTV9SG zr}DG&U6#mcDI%;SO_cTp`n5#}b^kE5>Wh4LsQT<=PDQ)jDT*_0`V~u+KfPuvg_c-_ zcHEbmA^{iEDzz`N6;?*)d1iCmJe*BpW+owc_lTJT(6IQO0i{zi%SE2Fikr5(rd45D z4hIFGAh3`RCC`9xGC7Xwqz+8A_L04i;_NYdiH|cmY5cHDJK!A2_L07wawh?Nuo^j(??SaveRqD6 z9Q(M_kE`o%##fV7gBN^7)I~W}VxI=6A}4rD)*r8Y!YD5%%y_a1cudd?}H)?-| z&M!PmIc|o`H2eMa1YHGDd9-Mv^P5biGUG$kGB0_``bv`WV_J39P49oNX7DEnvto3H zozNi+l3g)|u3Y@@{Y5|eKh?Wkz>E=`-+@WgG4cmW07}kb~>Y2Z=ZG}_u zU?ZwEg8`jGaW4B1{?f)CzDAMUwAq$xn%K9DUpR;#8uEKSM>R7HW495{NY!pk={gMW z6Q4wg(Nq79Ngq?NfZkWzD54Bo{xzw@ZFQe^L(qV(G(&(v_W`c5!-DD?Xh)o+?Hc6v z&K#$|I5Y8?Hb+AC2TM0J(P5o>RQNlG72jvDk;AY7XpcT+GWgc9?S$^6MOR__r@1s2 zCO3cH!C!W4ZyH!F-5=Y#r15b)Hu&$m{5D?`Z|F;E^m3>ra~HTBQ+tA`WHEkd zXtu|cypap~Xxl+p#pITytLyd`c0OU)yw#5_miYW^YQf(zYrPS1R2o@#rZaA}%sa6g zM=SV#cc}UrmVn;h`>NlYGr1;`I65h0t_uC*t0a42c;ULmKGYv4iZj;smDxZJ4Y_=t za6ayRl2~4?ro(q*7U5#yOevlBtZ(Q2!LgKaqzSO|zfTs$h9l7<3AE9kiFQhH!W{_V zR`u>{2&-87p@;ojw25@GePO0x7F7x7Xm4EbYE{qL% z-jnN2VlosD%p?NDMv>W0ED`|#C}YVBLE$^mJ-7P>#6J?m9b33XwspwSk9$Xl)aQ>( z$$a8s2;yfU#V-(MVqc{HBe5@qjLA@y&OjB7>-LQ0bIT!X1)F2W)L&B%zh867Udsxg z8a#{j-uZVcIt!s*GI_-X=U8&S{C+Ir(x{W*2$qdyHl4LxHQ_0b+%uqCwV8aL`mOj) zmP(51t&yS!vN1Bw0|CVc31D;bpy>R_F_Y3k-_lMlMvi(diA0C#60dRF%`a5RI}dq` z7Mbrd(Y4rTytU9Wk?^cu3j~>F=L;+C{&^c|P_8>6!6MlA)c!9lb380#llgSy7wb7~ zRc(Iw$awNBv=}idAe+PF3XaQ677maao#q(Km$^FEGBo*7Cb#pvE(`U`Bs*I>gKRgQ zMve0rQXgGX{A`AqsuSNyWtlL5P^o`}++P%XxLf_bHSdFJz{`R|n(VDoe`#qGZ2rIv zYhu7akaO!id9UnPt+Rm63>&-XOp|%ru5aW=?HB}ij{H^6`Ta8wWhU64X@-a1Z>9eV zj8~oAmw-u0UAfy|7zWjI9bhO*Ln|D`&sxqcn+ladjx13xF5!Vs6hE<86^$>;_E1sq z18F;LQW&ql%|5Cwx$;W8Ec&j@T>#3ml?lzGYe+bl82xOR5s~CRMP{o9`EC0s&ECXf zerlnxwyv90$+|zqwusUNzNO<5EhdoK`8R~GvnG{{b`BwvSc{sZcV}U=7T7Zu>!lje zR^JS*&A3%^{#M|&=#$Mce_Q?RxoiIchV6r5J`0cEKEKLSOor^1=e&$t9?>z3(YcoULDC>oWgv#v@o{k6ltc3zlrSd0nT1 z@vkwO5&A^6XOc4%nd@v~?ls1&yHNIss&q|uXr+yAL?hnBpg{J#&-=Pn>x^TC_L~Ly z3vQfW%;PLf)I1D2hf&VADrYJ;c^E71LDh6pQj03TZ^PWaFthTqMCFpfvTQHoV>x(t z#3s|{?-5pq>G}3efHc8v&WjZ{fx?KZY*HQQCwanD#Cr4o#R*H;PUD# zHA(^diXD6)%?x&4{NbFPb)xIyo0FrI0Cdf<7e~(uy#mF)c3!6WwdQvh772E1ynp)) z{5f3hep~N=LCm(9k$FaxPOcDvRrShP>O;SNu|HSB?5!Rq->w=XJSDz3Sb%VA#&CX?WmDn7QGVJ{0WGuP+2 zBhLea%a1}EV~_Bu(1?RUe>bD;lR&ukWu6)8lw=sMc3hHv^IUB6vgtZjdaR4WB$MWm zBS)1K+3`a(suDUIJRZhH|5x8#Gehsh3Fmrx^?PRIp>S?6%vJa;nF`A5`_0{&%btK$ zVQ}Y2@%@L@XWlRGW-O5pKM;{SJ_dDnY~{7zqjP~P#c%I@IK!ku|BL=X?t{41G<5ga zu)6?5ha~maSankM$rEC}D4+9{t#SD}-Y&eeSlN zHsRiFX*(7n3G0T+vm*$uU25DT#PKzM=^WboLzz_Tq5D%6=Sd59uNS@g3sbuHsu%Na zZ%2B1)5@H+S>p??snW`{qtyLE#{H?$h4%U{;! zzf%chN#MroN4s|GM=ArmdTm6y>0A%Rfy1eG)k!w3AW>__E8e-dWdAYtEZ|Y8c=7Y2i0QOSOno=Ic1b2v*zxI!8@}e{sEvd9UJ)ivA8ZM0mPR8v+Z=vti*g~UxaqrI*?X1r z>NAP`ny+$zZzA|NvW9u@xU3HCsjgQy&U~l%8J!yh?f#&`9)y+c=nd;9yR<4gNO+vz zuz%WkSVQtSUQVssZwkNl^-1WpFgWxf0p|yfbPRsuq3+Y_6Vb_q6BI|bhw`S$i zr8pO*{kh%5T5W&H??jz0vudyNHa5rAm;kp{>T2A|$r z?=43w*Gp&Si_<-QHJ6EV`#%EEYPSP$7FPH+>b0}erq&NSBXSl;Di>zP?qO%h%ZEqm z^Z9wJa*wV^k{g{FckmBk?JHPezZqAZFQ;ccTf&PSA|$Otti?F!t1O$%`oP5|HK6yl zEc`l~q`>XlkxyjdPnYY?gWF@`mzHurg*=eO46CnStn;@ArBOH+FH}MiT)l3yy%5oA zp-g%wWikOX%~ zSPP8$Qm{~YSZ1km82_~->pA+8a_Ju7VU`A#7e^~cb_|RH%CRm?Y<)pXICQCtmNZ@K zfE+s`irSXvo?toKhlh7I*39f%Zp0M`2c16=f#mROCI*O`Y5>EO>$zz?m4M$=4KuI~m zh>p0O9CMJXjAJ(7+>h;n5!>_Yr=p2JEu$W}QRYa$Ghii@yU^^C_;%(E6(!fdClbmc z{e8uPzhS_NhFI8!%!9XS|3Yob9A1SmY`cx4!EFNdHU%+xD(WDY6PIX6XYyM?7E7PY z`p$r+Da_8nkm_j(sj$S>J7g~1d_6EsDo>cc1Z1#Il}j;S4+s#dw#LXgV@Q#QgryEx z+o^XD{s7uFgy@ibb8&TVX^@UseRNPB_N+bSr{7j3e>7U3c81wU`q%zq%*Eb}?RWc? z0(0};V9uDJqZ)x~apJt+%ct`(&B~aZgRXL_O?B#3Ua6adoP)-gz{LacwiU-_<^A2j z`Rc<8fBTig@8vR)VLSObZ#Uh;+80E&4O*xoY)?i52M!Lg)kpD5;l76-%kRjC{n=He z@^`;Ln(jHVweLG!w5zqP?CSgp*&-K`=&Z@F{~P>gOF-JEzHutzK{48$+S}-PUy{%F zmdIZsBBC62-yBKX-(lO!RP5fZukfsrz52!dN=ZO^$L3?nw|Bbk?VfT=ca^u@R@2<& zqQ1|Vnq{3Vofk!m28<1^HZ@*iOqqWc$*($X&uH0veooiU`fJ#teei95tlh{;%zm}V z>w=c|&BK-ge>Dbf+zNxk->`b+EoAJ7+pIbww&EpMwVh1b!Tr`rxW`RV&+&XOR`DCM zBg4Oo-0bu=9?98ZUvY2Hj;#OQheQZ{X!gk;gAxpNYK5k!MEkW@xs(pqlb5-!r@Buz zDPG%F)61~#+_%|>+%YfCl@tqWWYzeaC{Gb`{BdTWO{cwGevyW&ndtb6IpFojq?3p9 zqW-{Lp;Ho&oHWxhz-IVWRj|L$z^O?6^ttXT+Sv9EGu>D}t&E+Ga^G3_s>sHpUjfc> zg0l8k@2;8z#j9+cquDi(>_KsxzvL4KzgP5xS2~^+@t$08OQhB=tVU2r#$8d`h`m-k z?c=OoJEnW!_$T!TUOy-72yeF5)3|z7>=Ru5DgAaxPVyW+cr#F9DmLWSvDNZrj(4Ak zUG?VMx>tE;M#4ce-N%W{lL`kI16zhF6|=81gR5#vg&%xH{7SFFDX8^Uk~iWxk6^&eSMmX78Zx38_PI=vlf7nUQAi+-8OvFa0NKZ~{ed}UTu*R?G=wFG#N zt-SLcY`+PGf~pY@B7deZYjrc=wfk!i62Z4l#WWlCf|lBNg0cOAb!G8m`|HNqI47eaSnbAx%*aRa z7xz3DUeJzEx72BHL}g0VzHMOLQsfb%HkKTFV^_K#fINj8*t}sZYmkzvt5{GYFEnUu zE=~79G$J4cqZZ)}is%Nb??t2K+8V}H79U$Kk26ZAMXbN@EjjwWWw1*5ypnk*pzH#y z6E&Q{65p?G@gn}Cr?*I{L0(*efI=NKH6yst$zm}3*|##GFBdv=<(bo~a&Mo05>Tg( zX*svkPK7+?GpoCw(vQjuhmys5beEPi zOyqlH^alB4j{fv$#^WIjOn&u0c?jF`i zp9othO}aj^xYr&xK`RjymEPD)i(rfWg+uacmNpFcmC6j8W`0S3PGhr0F7E9uqO8KJ zp6ewUn|P;-|Mgl|Hf&f!q|;;C700Q{7J8JPt&nc;~3GKBY zdS?U*fFT>0=W;v`92uQ{C#5BRO&Rm!oEmt(es)>z$MWc#&FN4FB!w`Yq-0a($8D>s zGaMci&8_+h`}d-0S$lBc+uM({Z?GTytYeHB2Ps?UF@JbX{9X&6QKnif{FrE>i%R<7 z0Jcq*`;t_oWW3(D+f@+2pBB@j`yi!OcxAkmQYV0s5R ze?HNw^kSU&anV#zEUH^r&}b0d_qUZ@`svKUSEY z-XqiK$S*BP!MwWx*zCV|Agu$1Ir}FEYS1oxa|E(Gh9~e+6w&;2j1Ld z@%#^3HZU|(!z0$A!eQaphLTBGpD~&bf(8~OT(s9xsjMUpS!%}M=weW{K z{24#uo)>&Rop3bK<(3X@@Y*TBGYRB}jwTK`$+zqInbS4`XDOCuhpGU z)5*88_WUOGy0f<<59jxl25;F7^pDm{qB90 z`@4yskuk|>1>={*sZh3R{Z2x3%JJ`4DO>Y(oTM4OcY#SxYW!K&z+Zz`qCHw<)b9NL zDih~Us*O3XO_z=(NkXaoiy-2ts)75fv9egDiBmr15BVw2wR}cjIUc9?1Qm-lo1NtZ zhvvsAnD8zIaNjG3kP z7|!9)mP<1ckg7EqJlmOC+9Qt7GLHINXFfWXDj3c<@L#+%Xhu97GR5!adp>g2AF&qp zY_)nTny<4pJpEuX6n}M=<~CfW-@9(-8TwLXvd|>$Izqb6`K{%u9V`iV&}xG_tGoX0 zt!HRypVi^${qL=B-n2>eM(_DcxBeculPkC2Q&$j@>C%QeX_yX7I5#Zt6tE0h^nTN% zqTe#oOmLeypcyu#EYh_0{*hl2k{KSh*g6GTb|0Q%Sr#0g5?_8GtkRkIa811S@LoPf zh9jtTgx+(Y(JCl2xozmAL3D2AL`Ev8V$;q0kUOnpr{zIf$-Pz=F~g|0@6$>=TTRnS zGFn$W2(Gn_rRRr>DeeC16zrKAQy|vqWlZ3y@*81+-TC6`7<|TpM(+c z2(?|;gQXy_qzSi-61E^d@q*&0_9|cKXP5P*uG&>e#836KlFFxJCoSbGU^pzFc+>$#kl)e%*O_VH6tlZYV~M{iso8M1IyH zH;p4bNc!Nt1}CfrynMe!ZxybxoFH)-^RGY;l#3A^1XZm*Ku{+{ns^ENm_EkL z&&yL=iL-p(bp$ty6B}i&@xBeEJz}g;$i&IU6FH*c`xDKu6#DrKt*Mmsd8}*EiQ68* z=I@PLn_tcxn z_L|FW51}C~QG48VZ-`#s&7k2b-*jXm4JMzm8kSGcug~(f%4Jd@dJeDm7~Ooc9o-f+ zWX#!KI4Nly?V86;`fNk25s3G@r>EnPdhrbdUc?&@oPBg>dNDY$iO@xNzU}?=;8W8R z?fI+*Ymj-Px3e?Zpnpb-sN<=N-)BYkN>60f-Q2aOkI~;O)OOs#qzIW zHM9+D|F|K}pjq6R!Z|Me2*lG(O_JiQO4y=Qz%|K8ra_a6SazoaerkS4Fw1`NkyzbT z{;lbqC7qe_8dQS8Afcm<{ZCIbK{j$iJw;5V_Yl`A3u?? z4a*iA!>geTqnZqeg`P|G9yl5QJf5&$v2OX78hZwg z9Z?=PMJskLDn++YT}pdBGuO?0nFyvKL-kUe>tXZHf8*zDvj_hCk2{|6E-d_q73zHY zz|HLM4L$X-3`_fLbjbml-2+z4`X_bt+NY85{8N{zO(hKVZ7PfXdv!?unQM5k`5x@a zKm4`#E9etwQU%2BNi^qeq<~*%Em$HdXS-M@Rm9{Z8V+SvaT0BvMV#B=l{eb?Shtmy@=dqDEfZJd-tCr`z?gr~X2s2b@P zb2_I^WS)cFel9 z_-5Cj8xE z8lIxODU(w3B88rgQ zmjce51}|O{MN?L{9}xHcvE%e+Gp&T5@W~S&es5QzVGQ+h_$F%>9jsT5XV1pd5{d`5 zVw!LTqXdm|LPkXw5zvXemND54*8k`o2r3(zb26vzLkKOA& zj+CI7w#-eWG_is%e{_ItO@R`X*9Bmc9{AI4U}B<3N0?i%pRRZt}fSEmVbs7!LaR(qW;+LR-~Je-bf&xT6o=n z?bUr|r6Kq82mAV)@2J*X{i(mTZE?9E5_yoCD6}z8_=PaCcb!^KRLD8^IRA)-AY+)l z>IhflJwkGi7U@{g*(Jy3Sxp_M0`-a3M4TeQbq`@EAJ=pU`StSM=2c!)0qoQ>=GH8J z?Oyj)W}jG94Z*F>p`{Y_uiCFC-&S70iqofZbAR;d6X|6A^S1}0`f~>b(SDV{d306U zE5)9Bq^q!PKUYDy149#C@l#GiFK59puD|pXm|_wFmKu4k?!5F--az3s@M{SVFE!Adpv8~0eE!7-ihxk(yuF}0jy1_&c zF(W>)3kv;t(r~ukFjrzue(p`^B);7vRCtd)X*=ECzg)QJX*Pj64kwO%SHP!ARB$-% zB_>wdxURSn(3CFVpj0`QeEg|wTG=mWmGvIcQRsgt*Q<7W@=== z7A8I#{IkSXB@4k&9(nM-Ycuc=hB-*5%i>;4^PLrdFl@HC`o{~qHN8h46uTI^*HCGaP%|B*euScmHgd87y`zoCqGZZ7irnu*; z>ebLDor@@<9mcMQl&a)X7LCPxKCC%D)-RkA9otU2sK5H7t34X>&(hdD{+WURf2A_w z#qOW%%SN|yxy)@6-O*6Ex0tQxaMqZ(;!PMNVo*pzwQu80zH@kES_0v^*uRCSmOb!1 z9gfK&x44v6JA{nxjG4jE!v+bRy_&h=^#_SZj}))j5KzBGX8Q>Dx}D=ErPlkGC!VEG z_Yh;x;{7iu78~NZIdc;=@w2U`oI)-tYsoK0u|MaEO z=lGGne$BEi#l2tkQG4{Nrsp5(?NpTK30QdQRM%D73@ZCn7SlKz?mPhIZu1*$yE>eS zZ&JA;on0Bl`UlpiVE>za{x52h`?OKbJVrOF>92Ox&ucY$ZGvB{ItgPiS#@$;Atg|< z?>S=(s+!^4UU+Y^qy3LW03mdkNJ&szqK1M{{n14EV3)aF7fhRSITa>>>2sr`^+M2z z`8{-w-SoZof?tP#Rm<}LlB3_k%8@~VwyjZPfoAv6hBftGhL{`6OFMLqZS{V9H|~NQ zG4u-SWnl^*vru($tbzDfTOdYo#+_Fe;>Km#LOJo^}DH+2g7Yi z#CHcZ7YqR~x)ou*fB&_vC(44o^yIK~+Ad>3m~zyS=anr|e&J*xb;r7swB7%E3ps!>I?}ZWKAYX&`-2&ORffxh) zYozjd7hlTi3ycBGiW~~tTLrBul07#6_DD8-2&0S{6@9@J+(}zRkaPTs+SL+CdwqGMK(Na!cI2{~(8wHI z0*QeK1!_k_xjBfJEYdm_2+He{}N&$SAE%Ej_>Yr@4xwjUdpx&z{Dq{ zo#tSwmyZ4TvGk(E``683y3DwEvp3fQSVzvvd+q+Zr;?bKS$u6}sUbUY9W6bJzlE7w zz#>SG8ZJwaV2`e&oyzWGJS&D6=(XuZJ8C}`5!BGWt%jpU=UA(~X(rzuX6{yAAJMgr zIz1gm!|KY%&5_l0ht-kxu8r+;*zmx12q(^KwCrB6%gou}pzel!}(O_SL z%BKX>65BrgQ4E&;A7~3P)=>vXyclg|FoZ^R)3pelW4c)KZx3Jpum9OUH43$lgbg>P zS0mfX{~BFE>t*L*U1Z??rWjZRY_6}Ft6e%5M$y^bQdDn=Rj~#Oz`-cX0IxwaGrn^y z&Ox(DN^l3Yc0>t9sd0AWIu;plxxf!Z&TXcLSWOQ?5IJ~dAytjoI$9hA4%RG(IXKpY zgV}e--l$#oe`1fqAMj(w7B6t_f}L|nVz(P&x;op~6l0uyaf_f(5*`_3@L-h$5x6+l z=Ws&|cC6_Nf4bVTNlSQM4yz(LTDB4#I^bkMT}K7=^@FBk>Oajl^Um8}M^rbh`#!+7 zWm}J-$nY=<0-H6=9uDhI+ip#82!|{%h$c!rJy<7+Ln$kx=%Gz`0s_hHaf)aZQug_n zPTN^6mS}^CQ7kD&CpP0lJU$?P2+hMvBDpuR7bA`~_jli68Ij7(!G`4E@r=Z$gr%oA zZaK2^s8czz;k}>w-4`K}SVzw*6deKJlJ08k)7i@0UN3TdAM2lE%eK{@cIk+&u05TZ zLL(Xo2-Mwu?l;|t!)XC5Yty6fpC?WDtNQWFvnNDuXZ*G|-6%zPw{o*Zj3?b_BCi}p z|F$1Se(9_)a?IDDRt@(cADcjmS~=;5kJar+kP@R0y!$WqIThZ22X@USAOg@i=WD-M z>~o9@bdgZA6zS_z5dN*`fV6L7G**BF7_n+d{?ade4i7YzHk8(z%mUJ+xdTR z5nt>25JstXxNVWjZLe(APJNpzyDvI;u?3!Cdt4_dUK#sK(xdFUGpegG@~-(lRMz#o z8BM=`D&%R&zrvCvRF77U9YvllY|wU}K)KfEk`0I?C=_%|7wzqP)|23H1?FNSdXXGu zuYo!Jx|nf|O^;AOXodcfD&}VKB!moilucM+@IXmK26?qWrWq>6=#gXf$1qB0JS|Zc zD>;j|-Wt0~HFCufg$ucH<-7{q-T+vne|a%)X*KlIF-nmiMcLU4_2#@T@Ey!gyN{uEn~KkE%Cv ztaH&_jf6RmTeD-8=&q*2<_Kcn35){eadUcr&cT0>m{|RkWBeS0P}-x#^egYh#&=(Z zRO@#ihakowIALsQ0oapjx86G{$m`Yt7aQyn1dFKeT;|9|AoeMDNfO^(^yE?>7=}}+ zuEia(N8O}rMj-a~FW;SY6sR3@lMsAdx+ri@m$;cCyQX*N`aNkbwkfgZ9${s`u223$ zbOifR=vW^*bcMwJO@Fg`K9)HOv5wOLLg`#m$nj)VUegdR+Ry>U85WOL2bS(rvDA zK!V$A!XYS#8=(b9Xpr+J!HhfPWw>j2t?GQIoeg(3w;k1c7%Pq;4Mx^}T7E1sOR;xk zib=TlVQ!Y<2HYgKd=ewPc4+_SX>^!QLXq<(q=Xn%-Ei>dz=-e?j(o%)CZDouz87_k z3fqfXU$_x9bWyeB<~Rb=9CKIFADV}EsLpeN?YQ@k5Eb-I{f7T^f%8QljlzC>9xk`) zB>Z@wKy(xt&jAPSF)njM()ZL{y6(SS#a#8F3BAexaJ_ZpO_N~H61sdvXFZZCmY_-v zE!*_He{d*}8bw^LYSxH^EuH)ot|G)3Zkl=#XVnM7_oLCc7!s9cC>@|{;2L}z_dF1% zNQo1*=A!VXJQUyp5$v{S$*`4jUF&Mw%8XC1dLk6Lc`=3=YB%1=a-`?KgwQbWy)a=c znZb=ZwyOL$_EL84be2<1o?B^rr=wHy2Q2vES&zuU_1}pEH13)T$L+M__{J5Fd#dRJ z34iJ613ujxzv^d4!)&}x+Su3F_kSZ$WH%@-bdG%h%^yOE*iraD&7FinnSYOYBab{z z!Dnp_H>=FJF@qZt)Ko@Sce6Fr8XdNiWqSz<;->=oZ=GF@2b;brmt|($ZQ1z#SqeHMk?OkhM3SIObB7-otBe}L z7;U2=E)T_t;5wvix@_d^CL|V{vDP0ya8u3xL;OgJ!#An=yqw_Vu1yKLg!y!juXL%I zwse7d%^KV6BA%oUmFja_zdyvqbH8mnkL7-6)>jED^-In5r5f2QCM8|AYt3MT_#-BY&Z~0A_gN3-cFlL%Exz5VxzME zmFm6hQ+3RFns*`8^NIy~XIS1B?{-ClRm(o@PRJwFHvDs$Y!Ja{k2sx>*BQh%S3g>* zj7iS17Dl@$HJc!hyl%XGy)Y2J`@!4hbeBltZI|}V%f;&sb{v2m^(O!LS_p$$Bm|mk zV%jmR7+5n7jD+nhM;=g)Hq*Z)JQg$GFQV@a(ny`}5k<@+C*L z>o9#SnBluwdm&7-;(43mk1ikTi+T=Xb41W6v)2);3W6||h9>kCSw~)<$)dZO@tal{ z+R;k!X%sjvjJ)q~w_~wy`ll=8CEt#^1B<-;CVzVH;QLr-N42U->qozDanH_HDkkYQ zk6DF4t;e>sgd1g&Dj3})GH+FVD&+lnrl+13{OOyd;a}B&iMw%kCEitpzqTH;c;)-s zdhOTZQtQM=JL_D7-?5d|+?2D4%sK=fw_8>l?2Xm~91!df`%<5KXy!8h@7ssQ=NWHpUkSzAZ%;qW z%;dkybd591X=^%9Gqhwee@N`rEUrw1koo`g`|P*BlzsNL&Mrr8Q!fnCuZ49?k-9hd zu6^dT{O>{H+Ckz$MiW=(gP*LH(yb%&`KEOl38HTEf=_Zr%ZlqSf?&uJ!eh5wS$e*Hp;Bzbay@s%zQKjRnuSU%hL z8BBw{Q<8?NKPs8Y?%7pn3#Xsyc}sfCeq74Cb!?TQJGkNGw%{_ z4z7;f|q(@y;_(sV__=mPsZBXL?M|+OM7uE?+-;!FKP?)R(s% z0*$Pi+5-GGclf9G)xThpzhAEL8^73zGr7NOk1KpJ*|xbJaK6DBVQ-+Q@ghlU`T%@O~zA3G8JO^)#s`ZRRvl~?S2@^8>gT~YNq)ALDjBcN5L zrOk`Y?#{AX#Y+xVYsEU;LK*QFe<n% zw8@jlRelU-Z%!HFTC8B|{{^+mx>if`XM{@ZY%B8ReAT+&^ZrR0iqkK=76D1PV-hy# z+~jIYLjBE+Re471^Y%vz{r6S97X^>!uk2);JFQ}w_+F=&4l-GYjNak*$P?)b$OTh6 zJayGUYE{XIx<#_ws0j7jLc9`iiO~fbJf=Q331|Ufdg^v9|HuwWruaEAonGAP#G6-o zeV}``Fm>fvKc-iLzNJr=zsGD+kZI|t-yL>fInY#!75}PLr1S8Xl>W%ydLGZG>6Jr# zSw#YE2`_3`CC0b?gv!z~KX)q?Tg6ar4FSIXEG?*?OrIqCl1uXenmmXQs_XlN%MJ#=RpRB8=Q$V;+Pi8~!x7MfhFP8#v?W9({%9spYs`k-oqeN{6dPcT5wA%CTchY659~op^ zUObC_q0*Qq{K)$SUnk!e;SBazbz}V`1^yAYjB9?Ht-ibbkZ;dUe#-T@Chvr52l14+ z3|2DKbV%(+bb7qdxZBo>d}hJoH}&h)w?DxW0sQB=N5jtQj`6}HsUAkzg3H3|52hh?_ezwL zUwPEn@wk3@P3^AA{nkH4iLH-HFOo+m&vSY(Sj;n6@?A%x(GGRT-Tv+uZ6=?br{ASL z7*eYgeWUaJKN`IaYk|qR$Th`W8O<%dJ{lK=kt`E#MlzAys!R6ZCt8sVf$Wx+0(E{{ z{K>s>sSF1~Y=26B6n1zvYfr8eRXYZM(Mg|_U^SDQRRpAtB^<;EOb^G!_uQJ&+ic{^q>*y`L!j)$YcT?FvHE4N;o^3pE zPr&%!k=+;8*%uigtq2!oPH96xu(0M{?1E{y3a}4onw3| z0S>J}NyBM+_X3QC+82_a%_UzY%a}*mKCD=Qu0+Hn#V|Kc>cR_Vm{ma#H& zXS8POf^$LwI?}Q~mosd;z3WOdh9I3<-JHu#x~>irya9&@YCd?VPMoq@PGRaO{tFh` zdAYoP+cYOyxIm^!b?x(aby5@1HEW<5XxMnhd1vtZxMK1%>;FZ@S4Tzl#ovx@^wbXMgtR z^Evm-y~96frv;gDtx$jd&YiKCH!LnjT>H{s*VxzWHnJlqbVp@0o0Das4BTFTYE&!xToi5hn#TcgNz?Mp~X z@o(>wDv4$Ix{OZ=ha*%z4o;8o8$En5AfA@%4)*`@?f5=WDNKyzoyyvog}nx(_&0Xe zrx*v-u;^*ZFEb^WM49kesTD-kU7EJIHZe*1R}&pYdit;rd|=rl^{)kT^;k6(H4y@s zlNQ&*@kXBU?c&S1%S6v=Cp78WXsNMrdt_;!)GiE)KPe5{BX!|1?nI9n%$!UFK9u;f4O?w{=SysDB?)~&C3!QpAW6ycN``rIOL zx1(<&%{fZfQ){CAg){#)-+WnU^-PWFoRNuvk^{?QZ^HI=ti>-y2^=P^-C{ILZ|JVQ z#R`Alom&h=;1HefV2yn?PFVqoGidOt z5|h0?q~zUX4XXCWFFNx%Tda$s@}2v%OnhL4I%^q|_=<&oN{%uUFJ8BBz}F%TW}hi>Oa`cFy|Qt) zEix!v=P7J1Oeq1+koM4Al*H4N=V4Wws>Dl^{ZMsaDz?&kD-nKDyOeBK(aB!S4`8D`i(Ik#b6}5vdUOoq_Fw zw+z(77}tV5neP}$zm(SHa+hPg8%HtweS4nvVVn9eUKM%haAmI7fgqxu;{R5E=Gm9 z2MD|o{%nzl7fe-45p-1TU6TKO(sJyX*hd(KoGCj>qcuhLVlIMAjj%o#9PDSK3Y zLTHvC?5`eiL-yjVVX9miriXkpXzxsm&@8)q<~g^*I>Vf6G7_F``ARc;WF@LaK2qT* zO;cptQo`4Cb3o%e3$rEEghp1QzUwXV3153oEy7h-^ssFr_RTMZd0BywVbACcH$e0hr8}oOu#wRWOz&rH5;@338uQh+(6)DHy-9V z;@&@sqj*gv&uPS+@Ar3doRT`1Q8%RKQ7?}aZCjK(SGC`BPB%>j@~et;x0nNGv&RXO zOb+F7^*p7|GVnVt?Imd1-nq?*dD+x>v3X655X^VY$oYC|=mgpeG0Qy_dQE%k2t94q zI^P~mqt!Mo9E?F3J|H}QJv?hjIxekqbk zspnSHas%>Phdro@?Zc~LH}wdzSCt>mvaSv0cCBkHa+69&U!(N)?%H1%NK~Y~4)M+| zy2;pZoDl^Za`vVtspS|r6`9t*8WgE0GTp-wi`HE*iXcjqaU@7Q;U40y`~!x#3sosR zn7;5=rrm5HO$HB}ZN*M2d63~RW}83-+v;^i7h7Rbv;x*X&2rmiv_UZ<4&t+yWvqH9 z?$=oohG`Xxc5!()Z;6?^8!bjuV}^x1jBH3E+(nH^&D)mD-l@)|Lo|0DzunYTz4#sO z9j;fP*4_1WxvYfHq`YKE!9&afK9zq$$-)glR^xfEK+zF`NrUvX& zcDy^qjyJwiRz&_}YPW!FC6hKKs3_2#li^o<45LnQZEq)>#^`(oJU%LXv!?CLE>CMC z3{I`e^tV;#Y(=K(MA-Ox_-2}(v4^SipJc8!saFw8|7(lb@AJCd;FHO%PU*ex+ZFp<%X@bv zHHJxJa)?oz#uWnt+@SV+C6BA6K7q}rGqRBq9H;ZBzo4UN-PEFj6jhFLgI{K92QnS6 z70NdUxQv$L&#CubQLNCEZ!W&u75H)q!PFuDW)HqTwqnN~noqsK(f{*bW?U&^+NsO7 z%n}s7I;s;WcwQSPfF!XrG1Vf7*cCHS*GOiKai6p(m(Sldbw&_c+QaVo9 zR&u9R?aR~!&xR%$E_aPMy7s<^%}pe03hFKm-QCBe4(?nNe_=z{W#M;FU;hH$Njlr( z-D91V+QXMM-<_UM)stwVtoZT6vC>_l7V(uzr>xi|^S=g{!q!ZR3(@)UykEa6u}j|Q zT`u)08qJpnUFd3?`p0lfaOP#o;%<%YEtc3d&y_lHIDnHf-c-gEP86?>M9h7VHY4|W zR#Gx}bkiF4?0HGo%&eLLavltwyN$Hz3E*#8Jy>?q%Fg9ilAj%y;CYi*SCYHy3cOyu zmSzfQ_w_txSH73>-!xh=x(XWX|Cf}0iuXcktyl1gra<#jU9WIp@z*1t-eiUStnYG2 zr5XOZ^}G+ShF|;y5kDn*f3k|xjYqQ@I(EOD|P18l$l_Wmw=kZ_6X0ut{IU%L*OtLQu#-~QncAfiez+E;6@ zSA;SUOy#z2?EL8V##Er3G)20T z1`pChgptE{;_f;<5`1l+rJ(@m>wi3E)Pdsp%9hP}#|IfMHF@e*Pn*BcbE{o{-|f0A zlNL{4RRedMMK&m?#rKC9nO~HOw)Y5vUqWoo37Rj`C3= z{qZyQkvHutUbxPJ$9>KxoqygJ<+wYslhL1rMD6LC%xuKuCZpSGUOkHAYiKvYjATkak$nD@9g5atGSi zq_=+^`=igT-0qMW|GtPevYdn%xBmOO{d!5z4Rpf1lvp&jl&h`5Ag)jFcb1FM2GReb zt?7+36Tev`zZjtbY+yL>>TJljXJFXz)~-86d-kA0wf`ySfAXCg)tXkr^6ywvxZx$J zbK0om!&1|xo02S%_bZm}rSjR>pMDO_NJ-{m)0u4iQU89Sz!3D+=8Js#-J0b^dqX)Dk+ zw=tU{dLQS|)-Me{!JTQYyazQVD^&zLkK^v^GJg0-QqRoREZ)U|%Lt}6q^Lp{e0YRH zv+wG;>{y6i-@e|Z)Z#T*mjk|EM|}bQ!2M|PSf?|9g>s;w{2k3pH{qF$m@svFNptlH8bMNi>i0b{iq;v%$WhFzB)kM=(eG5nq5s*)Jw~3 zs!Wvx<}DV_3f5)+^5bj&CrxM0{ku0#9U4kadk_@&`FQ{&I$gEdV2ucm*q4M1zk8L| zk~;7SP$0DjRMF zBLSb2Q!mU%7X6(Rp!$h*46HGypwkoKRv(G2uxF-y_(hxti|V;Dbp8Jd>wa9kZ@!@i zDHA1|uGY)0Pz}T>5iYKdV^ECe83+%!v|!l9Brj)H#RvavRnD6CpRJqZqC1czR(uP| zcj*2lzuXfXG`_aGYN@38^N>N#IHXi;T<61&_~@i9JLFdR3NxoLzsyt4wuYPiOr^MU zrKj84#cAGcgNR7dn}!EY=<&UX4H^62HD~aBHfM8FkJ9=+5lCI)ZD-6mseICptz+uY z%U*7-W8t5cP3Ad4PyeOLrg?FDp48kjy_cmN{r4`F(j#-7r$Ega1etwybeWCsqL=m- zbpah_A{+dkHS(|UhUu$9_rJ@*R{v~?rRS0#LypbuN&m^)V1#3`V1u-bJG0c5khlXl z7ISYhsx3j(jPxhhJzdmzK63>7K3gq^%S=<(X_FLm5$}X3I;!saV%!|* z7DsZXZipnEx~Q*8AF5CA+(a8I$?$bHZn;5plFXN6ghx3Rl)*V3Pv{@x8Lv4jzvl`g z)K-n0P(Q9~3UU#nGpX*y+w?Q2rtkVML5XMviui*YM9E+BokOVX;|;s{!1&XUXxdRj zF2_m6=5U^W>`b1c$M7Gd-ONZUryC{{xiPHSKx-`dwo~?2{ z3E${!H$fpb5>v}h>JIpXgcTL@vLywppML%5*?oa(R=YbFmHf-7lHVV9d?NjA=3j=~ zAMRCsvY38Jd3h}TI=Xh}7*a8bt7V~-1Yw7=Y!P!gEk9v!z5#UZdXFmt)Hr(oHpf~0 zTr907yGgypHN4=Y?Q+@sj*p?pAYwk%*>co?VrX%R*Kz*0=|_&4IQ9JDer8|4@nMgH@g>i8zV4d0tz^> z?vppR{<{oUAltj?>n`3QDz{rfMU?zQglv1yTQ?w&AO16R)OK{3bI0tjf3x|s^cSav zTg@DbHC8W8h_;{2A7kE7J}G$^f;h4R(QWj`tGL;SBA@MA2`_~`lC;`EluBr8 zDC5XWn?Uh$rk7AUytx{U@Pc1e*lZMx3pIy@+Gc&~C-6!7jN6lYuz@k$ z>m$SBQPe$hX7J1~GZM9C+LY?mUeXYH*t6#`>nYtW12@9-k51+CAFULI1D_MWvZ|n+ z#OU!tsv80e5Ud9iK!p6EGg~aNoXXRRTEFH}Xn14gt{qZ9^|41M#bc@%?-pBwJb%w8 zT6|?$mIjf;MmY7JmF6<6;^?HYeER442ZARg{|e7W91mQN-S&xzZ#q=JV6G|HGo5?k zWvFMraepQpO~K&t-pU<6Nh+e!K=!DIbT z$*)aJCbO~3-GMK0j}reSnM}6Yx8>_{dk&pkoWJ)ZvVB*glfaCeJbcTY@)^|3sHm&{ zjwvjVxenWN;|2d%yt34Ppaa|Qe{zqf?h3FP?_gVuoX^_uZZSgESiFf>E2&JI%Tcb! z6)WL&va92xyss=I_Ih;$zB-$Fh(H^%t`}#X*vf0I22HA@Iu~RM5oYTBVNb(}*5i-4 zzKakv|I%UUly+x?k0Zuxd}MT$oT)tO7w+)mho|lphWKI7S4J7egC^%2yppK!-}J`6 zA_aex6EoT=`3rjpwN_AkRMrR|jDDFUhQ~SR)?`5ax3Blj!PKFevzj^C(RM}wZoX}d z4u8qcBIsd894lz~n~tdo{WDzXsA*gP0nh6{hw9`rJz*m4T3g-l@*oN|-Dynij_#a~ zTrCBA`isK)k_3|1Lb-9JSB!f<@Acy4ZNaDidR5IE2j0G$@tn1_)$^zPdHiUPT9idy zWhJO3W9NY|$Ty0T@DW*SgqMc?K=%)yG0dO?@qo)zu+pF8PLlO(M!EUWjSqQGr1@%k zzcAW?B%_Jw$dU52=HwZvI-6c1(swWTauuXo^blMfQKh1)PEV7n2DcfjTVxb5u{GVk z45V+cyJ$fyNRv&RraeRBw#bj$v%J3VB}6r~Rr!@@tBu$G!lLfFJ94`0TfIU4Ons3* zYw@2Up>Xx_KnW|GM@dil?t|@gak5DKquS=*Wx3F#lM50N0B`l9|?%gSX3l}=+_MAHZ$j8t#=*4 zTHhk{s&I3u7dPv1g#F-e)$N7`+w*Gz*CXTjsK8I0=yy`eJGY9+MdulM>gw1GwRtt3 z>m&#cMC(+qv1Cu=J{NBKq*&7yYhfH?Q-1V#-axva*4uBPfe+~@ZK4{u*huT`CNA_V zb~ROK8`=>1J0{_i!wuvQRY%sO)oDaoeB)}K){rHxz~jA`&+qvIU5*pCCojl$Y;%Ja zhAC1`MCihH-^L^u@b=d_x%=*0HVb_!eDgbrv04}dx0z#4pm6J${9GLCDqian>q6Da z6R&?9*|CZh!i|}7*CU?7C4r(WDui;xSEvRGP0>BPU>neWIXy~5{W-uR9hvn19lqzp z3Uul?)}miJU}Qcs%pTe5c`BCMau&N82o~G$3!$2k6?-FPc~R`j+JVSe(tOeMO}Asm zs<(81WXPR4(?_a&Nl>uiPx_8sE5qe6JHkQPZq)=P2x>|>6acF#+mWEOKH6iW7!&(x z5oQ}nJ){UmNHg9A3v4i6j)2`4BScPR9UsLr5=I5n&eB_ZkL zKh1Z^o@_lryHAOi3NPGoFJsNKj#^J1k(jPh0(v%h-dc z8uBS6zws-K^DQ&9?v3Yfuxe z8Sye5h&hp5G)|5jF$HPXc=r0O?%jP#XolP(KGb`yqliAZ=qZIMCD*%bSD z;QorXr_FA|ZhQ$b2|bK0|EB-N-6ZYDPkPb_B$3-GXT>%O!pM}5Fi<)p>m-P>oFjY` z2)qIE!A-JoXW-!!RRBqXl8g5kz9<)w)IT!y1JA_`$)}Pq=J=Arh+(#1-ndEZMM42q z1OG`;4h37LScIvYB78^K7|2J`PA{))NlMzyd3TQqd3pF zgJ)n5uzXwu9%2@<`h(2xTB1?evo~HKsSyW}n{)ICB|jdD7eYUDjOj@TQvmg6-~1(k zRpuPw))TEBlY@)d4#D6qwt;?7|Euz2Y*g_0C9WjH{Uvq>dF%6OR@fcrE>R*mp@;Tf z2PB+yfDiU#+YkfqDVvj``2R8zpfnSi)#+_D6aM62_Yp3ENeNH#CH2%(10XE1hZx`( z+z>VxUG5hUWD_^!KbUKx3=V=nhnWx+2;K(GU`S#jbih;~Gma6iB39T0#9rh6ZLD?T zKYiT7q(5bk>g9)iDx4?x{zxxYXE0E27O=|mulQ^od!Pq?@^RKNjWcWbo78u*_oh;r ziC#3YGiB!4z~lp_B`oJf$UVl2EqDd;d&qiN5V)Z?ypHx5DB(mIEX1+D0wv-!hZ$FZ z?mn6bh5K^n>p9-a6Nr7h(zkfOzvRs?3hRFmy&MaG_&%b+ya@Z-fEgk-v=o0s$d3A^ zn%j)$iNW`++V2Gx!V&D3P>*-vHbUtll-iAn7|8k2QIgE(`~=L)k;Mac7?LFQWajJp zv;IK|<_gARbM2#E`K_SB1@ci7;s-A$=p;nYm?k&lx8NW&bA)k2Bw#L(W{kz5@}VsP z-~@XPVqXY3^TrD#9CCr@*f#R5W^*dAP=+}blTtV+i6w4ZL%a?G1U=-@@Ws_3k=B(S z_#xR_7RGDT)5IjtZi9&m`fD@cm*7nUBS<|F0uQpOF~aV07TQ1+7$`D`h(@YXD>1pF z}5dJ}{k4E#Wa`nTRFV)gg^bLRAOBAIAxl&*j< zWB_ZCgd&Cn#X9~;8gh(xA#BDa5MRy(YI+x#K+Y)hA%1lnM2!e5X8?u7)_;2UV?Q%_ zA0ic3`p8pUo&_chL6JKO;<!M~f#%Kb@Ls7EM$uzY+3qiGme9}*F(6N@51y#V(sOD0S{x=?UDCPB%A zqm)BpCoww+OhsS~$~$o=kUF`kp+G#OCjmuNPX~*J1X5JzT)*MKM@fS3K>ehi7=sDv zY_Jkj9FSQo1CFO0>@&nQZj}IW5BppJI#N|9M+`thaV5(E(GDaO`yvuBo5ktCgPDUP z<8P#CKwult5iSZ3c&XkId-A~;a})YOcG^H(2;>qs1RHjzOk+%eQ)mbjf(iQpxrq~S zDdE85e9Q_H124x4xJ?787uiSnz@nU4Um>3CjMykMAjg1;b~bj1C=6Q}c#kTBufP;I zA*?{QH|YPYItjdbJh@<}5RHUV3{Sp4ViX8J7=HX}22f=`NFVcpj|Q}h+v)+)K!?c& z$}uBcfHZcPo{xa@Py(4%7iv?!qd+`|m?xBypq_%wAoeOVOr)N|Fj+oC066BH`41irH0(MOoR6*)V4-;1w2GR*6 zF_jYtV0+5KB!Ii94Hi@m!R(+!kV4GkP&(>4JMqR|*d2teZJ-%-h8PUV6rfU1a04g{ zFN73E0GY)N;RBxZ`Z$ZEsDSo~v+Eu7hw3qm2&90C;s7Vq;l~TS1$trw(k3X|O+I0~ z?#*Kwv<4=YQD|t_!sf9OqFabu$T*_t*ywm+w79!-`52%w@#!_`b)ya&!YWY zFRvmCnAUOb9`(>iJnq505k6N(J}JRZWJ&Q&s!a6FkNCmTrE3QY)6!RQNUls8;4rNE zw?WWv&w~YB28DtAVh4C+A$<-hEb+%h|3F)@EO7$_cX>?foVAGq+PHTZkTiPjW_ zDtQF^xdM_Hc{{)4%t7807jX^E{P*kH9yvN5%_VF@3_>>9mSBwc4(j*ZLQa&gbQM&U z3fF^`OJjC%~;^P-H(ny6jm4MnC*u>p&HMaBT&0#X<6i9qzlo$nm6U8l= zwcsV|xm&X|b_Ai0vSG#@o@Ck`p553*Db!C@9I9>`PJ8}%-x@LoHAfNvCZxq_%1AeI z%z-eaVr^)5;G-iKmSFDgQnEYiLnXdBdLn3w3kSJ121Rnnm5O`XFZDwuq-=Sw-Z3UK zt^%27N+3LtU$k3^p_Cmc@@QNR!U%PO8s;@@Lwcdx&?$H&Mn7PL3~YIT2m&2a0>$*x z%F*|v_f}w45LOV%f_a1S+Og#F#hH*{Knok#wY8x@(>?s*w4Mop@UyR>Al5yB4S0m} zJCJnFaWMaTpndM~*_uVXQX^dN?ZYe`bQT$1d>A25vop4Odj_VMo4f9|kMQ^64-Gw=lQ}$Wtcs z2B#v$TP>mhm^gej|3#2~hi9f0mewwJY?Cy=e#zRd4{W1uxlMv1*-=tuO~EZhlw*yo zAI%D)E5_}izF`TAEI~8_Ib-N<4N>YqM+dUoX7i!Ysb5xk#TL5yD#faFZ=$ja&|Png zHz(dF9d;Odjoahhp&52(3(y=#BzABvP=xsSCO*ly8sr!CN*VOIGmi1*ouRW|(xcpd zk{i6%E>(4)mr&42tVltca<~}07eb5Nn0I^3tAuq|77_mb9KCZ7`Dx1ZRHOI#Pq0?- zpbt66s>b8n^QC(jF2ZtB6tRru{K0S8YG(Jn@lKn$Ge@Z z_n>WOw2c$J8I=V%R~79z(3`Ohogd$01*i0FIo}w55iGe+7!WjP4NmR35kT-S#K4JU zw!Mrw+8v6+#N5_}Iq_Tlv`8U-Dy+(pWC#KCs&i|r`=ruQRDKwS#l1*yqh(Ze;l2`m z&LhM_^cs00|R;>NCh2 z3_bPVKGcXR59U2FDvEJwSHFa;XNj}q1>oOgW%|3b(&}oweSkPXqfEVtO75x3;zA!D zpY!=#1;7%5s$y4xLdw$@d81fw`p-E_F7p3P{CR)=0!ZB@e)U)UoWt1=bj2BIt>M>l z0}&I82c0P9$^8{CLcVY*475u^44X6pUAFT(w z-a+Oj|Ga-{_9rhsn#-KE-5T&F1{xbcH%1R5V&JutZZ|24VaHq9hnv`5CmC}9n|V|t zPjyoS6eSI`e3vF}uEVe0MQBZUq5P08w%Bt{$r%BKEJ8A@V9F#j5SChP7{X*Mn16vu&hCbZD-M#^C70l4}u0|bwBh!M$ zAn&xLMWP&lqiol5Q^Pv(NAx@qs9gt5%qn2?+cqkCcmciks{>YZju+a^Kz0V8MdYB^ z0q>nEU}fRoKgEp)Xzs{+uzFG>ZTas~gWo4@3bjS2d-5JemlwP*zSo~@sKK4=t2#G# z#@k63JHfl)h|EV|S-fofWp=2DY-q(0;;j7^1rH0C@=F;I31vmhMs2Y-*&Zr->^NSf znI9^;cTeAHZ*32pB;8~5lihHhN7qRsvB4U&v9*_@#|iVTnBG~xpvI~P~W1(4aNn^(HQ+^M_R!p!b`phROZh4d7ym9_Fh*Mg2WcKorP2j@ z$RmmU)9#E7c?w#=;G3hnNq;JhG(c*#U_d?Kc7M!^NMhl^z=R&YAx4^ti@)d$q)G$K zZ`GwRRLB74PDctuXRt6_2`LG562W{Pg_H(z+QlBGz;&UKP^uBE#Ax2LXtB2$xcC*K zM4tjhf|X2ZiNFzWEn~$v{J+foBEh?}-LwE&`w~8XXDoyR^8*-Y9$Xvxi{M{zCNyqn7R;Bly!TP z@j}+>r;bmyW>Izabc@r}pyGw`xD4(J!6& z%=zG*$harwZMGwC0}tz86TLmECuY}+G&p-&jf8V(5wpME`@56%cOv88&kw`ZZ@^zP znk~rQy#rhSxNYk?HLjcfjwD zpA?uLvjjV_O&aPy#T#NT-0KK3(mK2=ow#Ejvo)fW=6zgPiyQuXtSyk)MrMYa?-(yb+srF)R?vd1TeV^*zk6`tT-SCF zPgpT6dmxby*=eLhefoA!XV`xG*OS-fcWh*GDJ2ecNgIP&0Yll=YP&(<0h#zbx3%4o zb>H7NyPbPmhgtVBCWbfrOT75Wk!w@F+?gu&eZ<8VjPQShEWVBQLeljrmD!=v8%0>G zv04^3o_Dd-$_FCBgUMPOdGPAb6NT)VUAObUar-3k%RjKG!$&UaHSLY3UXe%jgTvs# z5`QLCa78(Ch1Zdk8S`G(MM3=#CD+<)rmQ7a_Y5c1XSK2%uSVYFW{!@`DIW!uDa8>Enb+4ON8Eh6AgP={wH8{jGomk zs{AaV_*E~X)o;7aQ)rqP{r_HJ69u9~{0_9n141?b_M@z{u3K~dxUla`sZ16p z0ZRi@H2`_rnse#Gel(@B8sqymK%3Q-@wL}83v5Q&efRa21Rm&Umc~M^=d+%;thEpc z-{r3#?KHPTnKwr2ym9UdLS+Q`keOQMiH3ng@urqJq(oxRK~h5FNw{{;LDB)#(xY_MjqB(|HQiO-II}-!h^)0^V+^qKUQ}ovlD!gZc8+BMVMGILgg#?9ADXsx{V{- zQ+W7U+kUOfGqUe=m?}r@KIb!$Z7x3y)d!pGINH;svDcI+|Cvl&zMqkMzz~iZM@3sR z6d!Dv!#)6`qgjd?md<86!6$=~R76rEYOypus!y9tRVOx8JX92ZZp-|aMZ4Ns-&>TI zSXqd=`#vxuxJJm(~Q+iW%`7Vwh%C^s2Z0TWzTn4vT7DKjX z-?-b0KUz&z5d(+!K z`TRdF9b@N+MDZ$YV^>Ycuh zr+BpSK0)L0XJiZ2(_{SoC&V^bPjEK&*FV4(*u-mth+7LlMN;EpkF2Ch6;!iLjEv+2 zCe_rFr}nC=n_)0{j%wH8YIk$_YOAAE*AC87v&KIwKOScu{|Yy)Kb8+0t`9mmE1G-> z#{Mp{nI_EP!2KgByQNM9mh9|G1j=c*6 zNrjdrI50f8??2%eWJd8DG3CCecvEvI9aj7?{ciHx2&GcEvK6J?(t)g_5o3aMulhM2 zg)gl(CqsFpiK;EEw)#T~zLobvFO*BjI?TYWTm9hGCUix#&&K3Y%HHvC=iil(hOft^i$26gc;>#t=`ZN4JD*>8h@GM$b~2(9wc>mF z1>WyMI^wOc`BG4}!@_S2ZkIGQ@`5#7Y{r>|YJczQZi=L`L3N7m7z5erVCGKF zX1wfN!Ee=>?LCvqmbsm=(`VeGLm$YR_9>-IzZhqcVk$%$h&Pp_?i{Y-;MC+73QK;x zDYu`|bkDp{^lR(Qqe;6`TriUu3Y|(CJ`H!{%*28Fs57J|3P_9L9_Jh+JF#dbXZhaj zWK+caXqGsH-@s-DXe8f+?Q-W0p>RT5U_J(#-1!>PFEidS#QffZEfL)_nn~Dujv27b znr;3y(b>~`VmC>yA@%F4mG%CwwDLNx()pu#6YZMmLMI*~TS3_>6#+M$I%5-^LMgRj z5}DUUZZcMsZhyGyCi3;zMN1~~`2;^W&424PUNq6()f2Yz^qiPC(Jd-5Zq2TvfjW7r zBVSun$h|dB%;u+k?n#!ReObqKP-@-ko2;Yy%Oz|rReiz3Vzhkcn;CzvfRBaCVSS@r zVOvAbp+Kax`x1|EMqZnxF?g`*~4zvC}JL2q0)#k#fTRJoF+mTAeyU-(sGlO+v9 zYzq=J$f(Z{_UB~_XyL;xoq7j}(uGg8b6Bol#7BZ3rN&U>X4A6~Ma1rbrNWC>lfEHC z@(N5|Hmy!1#ZPqGqseZ9av!h%m_6P|yH=2^ygK<+!f7lzn?x5^mS$2~hv7PhKMtxtHXneC)CDL86oq<)u}Ch(m(IaT*w zpJ0j{B?{O}cFlX)T-YshAtNOgE3UagOMbO;>jL88BepfyT@0)H8%q1UBQUlu($B~+ z&^2@VsWil6dT3hhm~5km7-aihr8|$`ls(V{3`KuKoAXuM?>tSS2p@JYPNBx1+ z7Bihnof@>CZNr|c+92WUBAF&!XJ$_8dq5yma#h4N+u6$)XcHx0H+_KoUh=#}4@(GN zH|q2FkbpE|bm+sky@%-BhO?&Wo`s@TYZ*G1xeuOX(`0&xE?;5)9W@;fz0o?BkHzju z3IT1}z7pzrre4^icB6MU%{G4$$ z$5>sKZmiEZf(X0JM8yT8Fc-DqFSf(&7i&?|6s|j=o#X|~*7U3dfzc8r(q!L!;fcFc zv_0CHM(i6zWkWn7*`EJ`NQ|1Km&wf}P`>+}U(Pf5SsWXX383FtVt!NpWe( zH+01 z&3RdTn@k5-T$_{Wa=MqDkxm8cjuk>QxNg_3J%nlMJi3EZ4Dka|lkORZ4^>nK-;V@A zhdu^PSLw;H0l#(Lv!a%llv}^Lc!e|R@EDffuRH73T8kj|%-6`1w!cYpo+t4XHmIxk z%@XM_{*YdaCu9ziWb<|o0crinnE$yc{ci%!kkga(A74<}%6jbdRowT<8O;5fI;(_7 z+&HpOE;!mm0>Vl z-3aqtk{RHexv>1&OyNRqWBhLVr^HYH-wr3MMlGs^y#cZP)}A;AzyZyHaF$nd=5cVJ zCM7(H*)ZFOA)e^0Fl}{Nm3ccl;V{7al8px^Ha`1F5q3>@osDIV@n{NSS5z!xmDHdh%Bpmf7c73CZAka4I>P6UxBv(HWeWuSkPc`_{ znoAUPgY)Zuv0NXL56jY4S$Dh?v7Fl9yp8y77j~9*0w-W;P2+sbv3&I5d5Kfbsn2|> z@}|q8yxW3(k|Qtj%vc7OHTzbKB<yA`*3>De>&Fc`tqW6$^&iVX*ZnsWsY z^hvD~cJ0?s2-D3)ggMqHO+$DK3e^`2zhhQyuj6qNlDP`~SQ66NG$nT!>p6K}F)@J;Y+F_Hx7* z-=2F~%u{i?$v-NA1~VtmhdkCmEf-%LC8rmHoMpSW;LR|)OFnx5{a z&)d;ssRgmHGLN|4nfCS#S8If?q>vl1+zKpz1C|e@7Ft8fJU;i#w3`CUHNdh&7emo& z8?U( z$KGnKPhkD}i!1y1=j&#!~+TTP>%_jz?oi`&F z4!k$ct)Vh&yzbL3I`@lv-r#BG2-ufY-28F-IJAK|JZ%ux`j>Sf%R``>{ss7)8S|S^U)rs z2N~R9#eH-iB0C%Sio%`r8Oo zRx+P2EaMy8nX2Hui- z13;B07rc9_%`A8Jv4*rFJlHs8_GL5xPxC>qzGv0q&joTOlAFakP`ygnjLBj_C z8YK^8Vi`*TSq2&g0PXK}0Q@7{vavtD0Te=Lh0}~2>9Y=CX1iSD)ZgSW-?C{gxo_#$ zP!`ofXoI8C>YVa{VJfikOFu& zX#i}{MnR zy z<+q913n4}T-@^v*7u><+&Ba^*ETZ*6X#PKdKSJyGcmVzg&AXv}mD@415o`E0N9lSRoJ6}#Sm$!NyZc0_{MTHRJx#Q=NzMSXiL0K>&U0QMEqPgp$4hJOw zCjCmnVD^v)fKnci=N9dpfmXTCpBW59`WfHy#OR|T1Px{Y3<}jnPLG3K~-9S z01xdmg$61(>j7908l4=Ys>kqiePXgu$h8u-*y3+y@1#AV za6~=w%vZ#o$x*~^qHdtJ<~HYVH)u3=@35=|zp|`_Tes*yB^?V@4n_r%ii|}YwzTXa zl5iuqHH^d>PdI)_l?X}#4|L~jf4qt_lPsmGscHkchOfYF-328KSH;_vfgin9afHYb zeJSS=y*1WRY-O!fbKE`I4fVML(i%Aje+PX~u8O-SjiQZsbi))Zvwar=4}#9A&LuRb zWXJl(mO@39V+vVt?+hcT&*}D!;6Yl;=R5;Ks zV5KcX3Mf_ESXgNiPo$;xb-aQNk_E{H=R|Wl5Vt+1jk3g-U>G38Xn%I1YaEG37-onRnhkXy8>~}!DU4c9N0AHGEk^{m zhY7;E6-pI@!z>?MGe{6(@TWRfg!{xk_sly+D`q;^z7 zh~)!sIeWQ&1#B&q=L=1U8pB4A3r^)gIZb#b=Yj+~h&143-K&b&QrLs}A)yX34LD|Z zT*9g3vthkRI|qUWTrF9j zj%9=(7(Y8vyrOs+HkAHwR|h5tZ3B}8L)JU(5K_5Pg$#vUj9Is6PCiklj0$-$$* zE${fqnm|4Fp@yzmxJl^ba~PRM>^qse($pAsv=qt)`4c&Ve1z;T<{L1sLE~QTrgc5F z>O_JzHVv?I?*tbeH0DFwVc{lurazSpBq*;*{MLSNU8OE4+$#}C<`U-m&ZqGDu271X zTex!K^8GY;Har8~i3=4+E0x>VlEN9W_lz}zg3~vN@Yxve2UQe%56$>ypEbx=DmoOJ zL?MZKCBnxZ?md(+s8mELVI}ROu~Lt*Qn<^^>yZJ+gDuaj0t8$KsF~2%m-R497OMcH z(?%>=+g%I}gaxgL;+gL2L|(y|se&fqIDMLNOp~u(gUz;V6_bbcN&^4@!o9iMB*NLR}*Zk@&Dx1*TN72xJtj zA5NyIBgYhy7cN71O^SJf_D6wHWXOKFtU`YH&3)j#YZ~lYe+=P43!xoRd`NqkJ#1Vd zI6?;hnxu^sBZ>AyF(F9=Z0-fh+d0GNKz(>^YFHxsFQJ4bf`|7<%s)|peDE+IM#kiB z(-vq@!2*)^0z*rK@1xZmXdxun(#GK+0pSt4hk0eka%ybRipSQ`shswQm^hPAq&>VBxea5{ zw;VI!+>A(9^Me-_bzpOy!Ja##Lrz7*5@z#)Pd91~yqLWzJK97EWDb5mBz~^ztUP*>F&SMWPjl_ES&!rCThEb5k*@&$O=8slEX#aX&}ND&QQ`xz9_h;f)YEI z$b(e*CKX#d=EghzX%U1mkyz2*8o|N}PeUA}t;G8psy$ z52E^D1P=5PcV=K3@VUXbduV8;$2-PU8hq37|k+3|zCK~iz)1<_7_EX|XaxAjKd`gV;2j$^F^G5{bWT`dqFt}(QR0gsco*%=) z45H9bUQ9F*n2h|EoFwuhof!SeL;%T*?8L6P57-qa8_Af+=Y+C90rB`H@i`5~2AFDC zZVa34ns!wdchq$e=DyggKoWrhDJ2wVjp2e=0-97=qhLR%Nrjfm91JbN5|E-1Tlpyv zD^b=nK~r4?yE@okKnwe{@GyoG(t?#&8NhHhsBL+|M+Gv7T#{NXP|lgd5lurDywhA> ztw_)bh@{gDYcgXnqp_pCH#wy1c{(wq)I{K93_F4qJ?p^%Np)@-Kb2?}<|Fo6+YJVm z^tk!Eb?5h&Us>MZFB3DI8*wwD#F5nSZ3U~)Jp5%s2GV6b2ApM5t+2y)3E{5fdw6Z8 zm2|BFsfk>QYOQr6Uh;D>-uD8{D(O&y0^_)WMq910arr8w_g}^Yi!%Qu46*2kK`ClT zBlZEN3_o5}*kAa8*^9XpEaNReM%-z+6#_Q^F+Pz{!xAZQpR#PP48>A;6~)z8{^V#E zlr2gU$$|8R8^Dj`bCDNtN+j7+e9W`d(8GvHq_i#`hAK7Ud_uwt89q`Whi_|%+h({0 zfMpDJ5TZRZjYBM-opK_%K$f`BG;IGB$WlqqTaqZbq4uLF&tn zI>}=R!R6~r${mH3LC}>!*bXJv#mR+pekTp%xP*SYkE$5Ewl~nLT9nY4L zcW(yMVqiN)5k2%RX6)Q6<`1v?KJv>(jP|PDR|0z50DO*a*3G%1>#Vrj*PvjJ2TVWt zYz0q;zH~;Myd6CYXs9-_m7Gc9(uly(Q@o0>tEL|u##73<`4LuNs?vc@*uI~z)J%yN zQ@FouEe1bV&U z>!P-+vK3r*2kFSK3e69 z7yD6KmDc&?8I|R1vQObw9mHoF6=~$%A4*C{kCNt@s-!Q?%3FrLDmT)q7)3^wz2>F` zE!g9tZwbFTj~GVjYXkdL*m2q!N=0*)xL%0Si)MW(k^gS|X}hts&MD)5R7(CTRK?ta z?QGY*NLIEwR|Tb56Iy!FVwv_pda97Iq~?%fUv(xkf2NSu;fMURV&+aFX!OkLSGxx$ zt7AQ&Q8goP!k{NYCGT^s3Ma3cds6uCq2rTTZv6PF4^!g28V8!@Kvc#j(a{Q``=97) zX7TzKRx(Y1?B#7VDe9&$Qt%bgffErzJR=7Gm;4XuORB0h`@N;j9kAZ2T$kCChpPgo zJq4IctqLOM2oJ#H3vIzpl!N&d5ohx&e^Vem_=tj!#ZvSm%cFPmKxs2b=O3olwwP{k z-p+2|D>5(ZB zn#GJdk9rm%^D@K@e9j|Ex_g!i0a>1t_8;JTgwB(do2@u#MTU!qtSd9bwpf~o56?aQ zU}FB{%etGVOKtZ=)nb53eCg=ePT=KaUL^Gn&B=y87YGnT@w&Prgr|ksHBBQmI^@sC z7N$L}GW*c+4ZGaw;cp|2Y2YCC7f)(_>PM1f|33dpZQ`e!D?D_gH}hKC1ipLvs<5vX ztZ$^XIHT#c{P*9f8O7`S4em?KET8KLwH5hR2ID586M(CRT9^R_Qi{C})$%lt34lh2 zXh*FR5H9fEX>;*oLm}2}Xydr9^?8U!yQMK_!iRQ`Y@_lk67{yEA>o%1cN8K*E-%({ZkTu7Z4SUZn@7&@Z2yCU0T$!Y3ZLu3OT8i3wXvn^hpff2}Z zCk;dhlZ2St^|vy*{nnRnPujr6K}LIc!X{-u^?WcD2|SiW(%I?u`_cZ29Esr;) zCy{n7UG*_D(phr@pQq~NWBhb!d8v60vCd*ur%a8$ z4{j(^eJgNeLIMaA$a~vQeywH&TI}mEpAdYk>nc{uAN=E;tM-%#)$o-gzKUxlF;!f_8e)*yNm z<(XeLA%caewfskCv;EJ=VE^JkNspj!J+pCIGwR)QLZvQx^%0z9)|gpOJFq%?ADP0qpeRoF!ZBwFM6rC-fV)l^Ugc z+h1M2jp{evcn=1O1x}mI^g3COg1^`~I<>!mj>E$=8e5Eo8^K*-31HAwdMGU{_BYie zG)Vv1u{SA0P6a5C{0)H)YuIB@Q@VlbxWA=bOyS#(-cy5z41i9Qe{8Ej&2OH=2@zoh zj@SyRG66}g=pivv^)^_rTaTW{T=-ibZ=Rejp34*6;y1IS^T{>ov4>Cmiq^7pW9g`? zIzPO!=^_5&VtzuA<|%GP-;+-FB)zPAkZ0(7xj87xKk|^O*nn#IZI7xJr{3{K<0G8~fN)-}F*9Az)0s>2 ztNxfZ`3Z(Q_RavS*Lj!i?tAQRiC|F1?%MrQo>RZslP|?#iV#>XxXs{&+z(1Ul-SHcvE;XO!|MT49rO)1%o~S(@Ekk4`+q^Vp>`9&LP4 z4Ym8(#c>qG1?}_atF0lFP!Mrd=VFd{24MJ;Q+b>@S7GVtZBwmgiic>4&oQnIArP(A zTU!~3io+}dmTx}eK({MDzvYHE-(7bPdOhxt*BqpwtGSW!PBkzyZf$>>ZPG3?&OL;# zs^-^^P;x&4Ui2_ZK#Xo>PiA@{2q-P1nr*dMYAKoKK8A^Od^dcrK)Nw`>Fe~i!8)ne zwd3@a0ZG2}$rW#Rfc;AS$5)hZg^%ki`LFGatY{T`lcny@i6CU>y<+l&i@=dd?pxx* z9XeWNU305^t{=iel`rNz^CKo2cw`5}YGm&=mw)--YQj#b+{^f}Rx6OrPg$jpTE8PW7i}j6=U9<7Z5C~ecEBc_w8*t0RKUv z_$QUlqSS?~Bj3^QphwH;e_jR^vvnviFsOZ^I07tjtw%fxy}Rj=5TNP&{6a%dICXk$ldfJBcLeqre4;+jQ6sKcE5V|<`tE3W!JRJG!8~NI9f$ik!Ko$w zN?nxWTmL%0p3=tDHS)`PRryzO6LPJ=j8fOTu?1kzZ?ZPoBnwwvyixCf4CP6OumCO! zK^3Jlcw_^2mV!6HSJQ(TNJ~CFEqQ%s>>)F!)k=D11K@($NZn0ccRfs(?d9~l4#(^9 zufM(#OT(FE(hdn#`q{j$zP^~7%>DWMw{6$T>$0d^rOVC|W3q`-P5(6C8mY}*yv_jM zXrB=Iz24I-H{AntN0YJ;Vy7&HRkLcgG|muSc%^JH<=#N%dl@8ZJ2H`_gh#Tvqd#4& zS1b^qa)Q}ND6{Ma{&Cs8?_cMR|6zrn;;m59R%YJhyW}Pk_TfSf=CIIbT188*lt0J0 zIE=hiT>n$1VAn$Y;l(;#Z@O|?$Rn`4VNFy9s{D&x_e(^LXpbtqY6qI^VRY{sJ-Vlyqg-6j>E{ ze~32p`XyY)j&SWbBOdBo3Jx;d>HM>;Bz)K|JIUKld{D=n<)BX1HH`VuLz!_B@22s* z?X!PiraZ${Yiicewmw)rU!$BOfVa2=jRkhM^@l{Bmy`%RFL7pGOLkDW)fHTY`H;Np z)zi}K*3_EiGx!*s;>Z=P~G)n9EZkwe3L{9ird zpUZfae4iNJ`>64@_+jTw5tEgvx&N4Uv9x{ZVqX1miSjHMY->Yj>r)38lQgX#j?4y% z$-4>|2#Tg1bBh*Z?}&d}d%E$jWUSP;49T%q(*vfm!k!odX6Frvmh}b%chO6%e)-r6 zcR58Gaab;eIOM>#9RIeiONCkG5`g&J#Cs8XzOB$D_bOSdgBrKAW#z}YT|WsG=g}@o zovjX-CiUQnWp&Z8hr$%qM14iWD_@-qth!7PpSBzDoAakI9h4h8fzCqiI_ECB&bwUb zdL^DCOHp|$wEo3N*VnGkU=y!Z_n=R8HC+tO5=&-8E1OZV{@-(%wZ5?2GGC#)KKEQ1 zjv=Wv{FheS4_>j5a=@5MSVA zR_7&7%mHKVXoXeNtKF-zATg1IsU>CY*?P(%kBBo|PSe%bUU_~kS}tw-KWplSWQo25swnsTE$q+ZsizfL zslL1G8T|l;h$)>FykuD}lUq@)5?R%=@p_)%bkS&1C;!_#s@7D!CTu3`Fo-Yb~W zdF|KjX+p4WI?6)${4Oi#R)27*YoRg$fk2*heqZ8Z?joTPY&Jf1j_I5EME7cxB>1_F zLWtJw=JEMVZ!J!rh;S-x17h=2p?M>dukV?@BJF}nfrKpFom%NkXlL!|sD zZ$+XTv$dYM*ko_WGA5=V-xCGaW7|(Fcv>SFTRQL16Rc zuB@6PwiSNEtY7E#Y-2p>_-NAZ%xxp}dzYTYU5^5)sVWzA3K@--?d5zb)aM+Wn{vA9 z6EB+D$G`8moGxvhHTC#Xp$ye-_PG$4ZSBF_p0$OAt7l)eS=fZiiB+e35tgVfS#m_{ zATJ~?%JHnJx&G~)?xvH-FY3R(KV*w&{$);kj^n@bu2bYY{d~mNVy^gut0`Y{pt++}61c`n*>-nf3dtpY z!H1N_a+vBCwTJ|TD^V1lM+)I}me(y#?uT)iizJnY z@Vw<}A`>EHwAU2|zGP zq}MZi43n|8eAF`y#da8R1KyAVU$`fd4#tbhPA#Nsqm$5D#DhqnT~HB7X(SDD4lW3H zljBP+#m&VHq%7{u;&m8mak{O4_&_dlA(iaSx|w<2M}ueRF=}Uw*;7YtbIGL zLl)%y9RzY1#*YFZ#n9Rw9rvZV6Ea{TW6SutI0sQ5I2~)8YGp$eC&66+B;&=^X|c^l)*UhKXF^{LRjC(ba>7Ckra@QDi?%3psiyZ>5bfmcgxKU zU&RZ$CVFHDcHIFIFFznr5S6cay38XW;&Dg~&wyQ%r$)I(1cjc9(A2<|HUkNkp9Ma| z2%vpXT$816Nw}|^Rhp-quiA&TA*+<_*!{he0C+om3Fan8IT>gG{a|8-ltG!F1gKrO zpe$@xllT>K))hgvt6>R|U1SXS*LT2CK@WJM4kK<}j2#zy$9M&xOd4cEf>eRa_{&7g zWZtmr@&+Fi4hJ7v@Sk&obDn*CMXYcuh4Gjf{ImBn_{+RTOlVP$l{-KVED`9j^3>+J zz0}=6l^oIc>5%S-L+Wjk0;O{?NU4}xVl$DU6n8naFb;|ghDjq&TRjOD@5RfxCF+r3 z_zgo`LzLkcLuL5Otc8q*aw2%roQGR5CM*EdZtFx=A!Qsal%-MBYp$e=;Y}CrN~;R~ zq-ZAxIy8MlAX3OdvVn9F=OA<}qKm_g6{TvsEl&qOg+D{xMKSsb%G20VD~Jwe6JT09 zGGX0+2^t8$kkyJNk`UXwJ)BLTjs@HD1PPJ%kh~}khX3rCa2J3BtJG zIH*P>J6Zzegw+g90^$bhV7=`@%A;DbKmyhuA#UtI+l%~(&@k+vSR35Jn&jQ0d=#T# zOas{jP<^a8zr!l-nfy^?4ALLAjUAvFK_?k)_zKzbC_v`UwJKJk21X{Yl6csI1f!UB zaWL#?5^OwHGq3{@Tl}D?BA@>b3e!VRJv~ zhOF(L*}L;$--l0|%M}yW&ORHgJEK|0VQ+Z-}5WXg7znzlP;+L%POj zZX-w)&t)BIM>Of-Wd>N&BuFoKENojof8%=(+|E`-P8_Qj`!Ya*WW*9(e|6b|?CxU1 zusZ71=I%4#3oF_y2*MeV+$ajHwQDMHM6$yY%*R0_HF8VN9M+1I{VPu`#Dr=7>pVUW zb|>Y*ZZ@s4aAsROg_AfR4zxHn#6pnA5Xos$V1Mf{+}HDP0;vJFf#H%n+ZCV|60gu-$%7fPt?K`v>ass**YS5htxPv}^95O;Mf>~df%6bes6uCI~P zVsb|`2Lz*xup7THG6kzx`q?2xaq4s*)G@bc>CW=s==`+@{A=bk(Ivz+4Qu$WtvP%~ zmrv;VITNIDJ{Z|!eJd{-eT_dV-+r%6eP0&kjnwv2{=P1SBL6#&L#kr={F=%NsCWT# z1tuzEC*-nqmEv4Xg)mCHb`~B5i-P$MsXhq23w?qq8ktaV%Mdq1{S`S%!4lWlhmI1l zM4^BRQ71lz0d0x8z-|~!FtP!99<&Dy0n5c-k>sR@n8dhn?9R)F#E09%J`7@2zEV~g zND^sy*IeE347EHN2~z?25MioXD5DND7I+*?79T<~M_lD)$*FUYD#ax7>jLe#owxhM@)W2o(D(Vzwl7(&1*b)0V`K1hK;y~NVb{?yHJaOFO*RVkhZ1?6b)BU~ zJVx%phI>qO{b|HE6^p%I<4p=dszDB`ZFPYzL2kv1T}Iaw`ASiwO_duem@p-e$X?p~ z_Z?bH=By@qb{+wnKP-87`<~@8{DKt=dh8E*b_sdFkX?0#U@HUKN~-7&3!*PA%2O9b z{XNE^~T%GF{J814GKvWsfDCDBb7 zY6L8sE2J9?;2MpO6E;ewYlh4v)A^kkr2s+;xWl1Z)_Lb%O@Nsl2T+6238GestBJDD zFuoS|+0JQjUvb5HZ*4$pP`P-;3G;QDy1!eop>BL&4u<5w3 z-`J-9sFqICFMs)x7pQvsgHDt|IxQ*5EHki2=*BbtQ(;RYC#8Fv($jUsMfSxdiAOwW z#M;#D+#v^PFnaXWDl!LYM1A!=jHjHaQI_Fu!J32;z2YdM!XF^|dOyoFBPY8it?%C0 zjNOGpDQFF>{-HTZ`KQZW^VV)y-nuS;3fSl#*vpo)O(1QBOVWE+N6(iZsmpV27{qsv z#KlVoln;GaL1g)M&J=28C*2;+XmL1jNaJx4d7BGu{<^%xE`6|1SlCxLvt~C!q}g7q z?@`#-9$ zZi)jIZm|w6_F%u?;xDBAYFbL)V|>iJvZT2U;lEptm;I`mJ&4C46cNxF9&^E>Nkqrv zi>(DCiiMy_g}Yz-oAS+Vk9xz!oKg-5LNZpR#yQNFNlZI={0M#fNmpoR_nC~D!8j_q zze6daz`bC9n+mOpecVlPk!o2L+oXypi~3RTtI!}!yr$~y&ftf5%4xBXFS-|PTQ!z* z)aI*i-!O?9N+}PVMo$^$AB~f}ujpC8sYSdWS|RW_-^w6OvvBj2fkVyDkM#TBY7@P8 z!dtn_wlO1g$?ydi%se!z+! zYL`j?*+tcb-mvTIG>QorakOWBjxeq$6*bZ0`OIh0Q{DR6doKNb4sW;Xuh=;fF7was z-QK&6g_WYl6lLLO2&ePf&q7<+CMO7)JDGum4JF*zNOvp*RoMzip^ufKr|KKw>t;QPAyYIh+WFdeXIxp zOX-VZ?Ipx6_7%I^g^jgHr6%nbQ$nH1mC(4_Q-!)UnFTd!utI0AbcFljVl@ymfjiWu zMFO}^3nV`Xkb;nR88%IS50pFYiRr3qX5&q~>s0n5+^w5I_bcv{CIc?N=;~IkKwW3TljjVBVb8;ajZSHg3t*|f&_c_*AHe<| zs?H(mMgE+_60&9^QM(@g@keo=S;nd!gd3~c)WRCAOl4FUT|oU z2TutUzO;Ert7G*>edo8qZnk}afPqARA}>faL!d~5ZnF4#$IK%0=X4zQdIp?Lu*2j3d4FoOpv68e8Io` zDDp_<^a*&daVAuNWVY@$!{<;!c7`uty!D)Lp`m5IU_WlAFMsbF*r0Z?VekEDrT4$5 zi$H%*7v%_0m+r?H_{4e!sYV-nHM>%O6w37hjF=_>)9NZFXNe_@w1yD1Ry_Z8Fmnnt zGtU{&-T3uli7TMH^Z(OeL36Hv;Pz`UO$Dpd%tmDvZ$-({{2%Gy-&;7ZxFpxL|FtZk zof&Olx1QQ61~Sg6TQVf_*7@zqz*FleX`|y~-B@noB4LyrJ!5Cn*lOZpT-mfV?QLOv zFM6#uHw;_M)|31cQgFp9$BQCe0`agmSu}IGq19588_%CSY2+);|^m4SXrS_%o zMiTNj8S2c?6vj%9M^6-6Lmd4@7}_~O#=RCVZHz$&h#cSy$k>~1ct6t0^i6UvjL?%-t-EE&mF;;Tx6`OKK%tWybB=ZSS zL^&gN!n+q0N4d_JsY0N${SBqh-v)`}r6?TkLwWK`*erA+h5PVpymR^4B>3A5<9Hbg zhrglf_}eVvc&mS%{8&9+4T~BK#@~)0pW*p@i5Fom8fieE{TyUamL^v^R)V_)fWK#)Fbl%({@gKWA6pP@|J)`Dyz-vblVs< z*)p|r1Sm^2`)z0c353Vo$bT8H=2D(>*?sZKSAg_h0jeQ)ZT>Mw_H!2lTj!Wct)zO6 zHfKT`N%Wd2jd{wfcOQq%_`hf4Bv|XU<9I0xW83Xml{4ZeHmxB*eu;JBmT*$RF;IJ! z_MTb-Af*mGX{6PM7&H?WuP7Nt@EhNS4~?Wf{a<>GLhl<38iiKuG~{iV2y;}hy3E*C zW>o@G>cMT5wCnR5N=bqVFU{s?yb34^HF{B#{B4?XymW=by{I;8NZ;(U+S9nIo*Bp@ zfZzV#EHxKI{Z-T#)EEayX#{&3X=MOxgdRRnYxx?W-fR67=HVQZs+H8lAt0hOTQacl z7$~CDe91u(KH+fWkI=qy{C5@l0Q#zj76Ibzh~a7hKRi$h5+a@W zU%h;0_VqO_zPa&#p3@$M*~}DG(q7F77-`KS22F*5Mq15|qhr+WQ&pcqK7rdWsNGp7 zO0gH)ggxtoJ=?@K>x8dXfoRwI1GHm6e{{i=PmGO0k#kIgR#GiToruy{3961GF0762 zYy35R zKSIq^*wK9UpQJb8OZ$(3@QitnyE=R1A*O<|Y>bQd5e>k!+KM_Kz*zNeT}7P#H(J-7 zc>iw!yJKqTl-wiD0v)Xaoqqe(f9gw$g%m~2SYL(L@ox3o##TxVxjSB5K7d^QwwBYJ zCqPc+j3)c3+6sMa)x{O`0nAnpEdYQ%X~h_VudmCM_5T0XSszbyV4>KnPnAQC#s5@} z`0QH@xc69n=KM9Vn7@9px5IvMKVmE^FN7tR<#!=KJm{o-+2Q3 z&(+!S=~cqZv0rWf^ZN7PdUM_uz|p-L`;bM}hI)>D?;A+Z!}U93Y0^Vh;-*QdOz)wjv2j`X|*tp1vtbuNune zZ8tIi>azbHf3*6H?i8Oi+;*+IHvF_6mOCFUXT~u8*IV; zQwNrpR5d9VFkUTc#lW?$1PfBHp<}PUA%+6F2ikQyEa^Jal0v~=n}1qvw>r}%CJ0tX zp+4H7-cDWjE{mBS<4ex6pNA@E`E5v|_b5D$ zQ!DxYeEqOjz$TqWwV6Vd>B7X}X#)*agbTTUb)KInZ)(lm7YP&aFt4-Ygp>DBhH`Qj z3M->C2)Ql_`K3rkhN)C|*T|pffNPjCT6IHNN*s&pC8jl4VJ2+PK6WI}8~(S{R8MnKlWTm_@$$KA*SA|3=hCE@_x20S;F$0KRMU+J-0`pdKu1ci3 zZc11gvA)Kg=rX!X^xFJqa@Jc%=M@v0qh&}|-M$K^5b|>^g@pDX?uN-4nWus-Z0zGE z0hIF!!*xpm_rq*;Yr?6hg?C|S2=(w!g6HgH6AAQk;Ksav@s&?q_vK{s5&k##tTIlw3I-^ z>9oo34J1(L(mA`J=*W`hw;=u#Y0b9I?F!VB39)nIByFpHbv9nJ%9xzG(kRFgqoAHXV;*Z(<(EYC?MxTfU(MOM(XR^XTlR* z1=2sf-=?QmbEXfkz3?bWM;j_*YQNYE-%pcHF5-pzN4}^g(MV|gcKU-O6QcCn&L~%v zDQ4YqHNN@ra?Z5Ze(aY@vtqUbVydEI-s%inBVbYNd^m|eo!N<7 zMMOWrxrKf~RlF|A)0TO2KzTTcB%PU#Q$@rgp|X}<+(z6p$#diD=77>rQfw+SHHQkX zS%SqUdhr_i2nyO}(zF-$+-e!MFMvtOkO+-QN)9#SqJJ1AEW@p4jEaUt3{QZ#Rhnz* zmyR*uuea)*D!*hlLf2Q~r zEa(8#VpZ3_4`zlOJf2#4#z)&2ZRq!Nt!q^nLwtOi@~sAp`z?ak?2XTp@O7395YxXy zGYfIE`HPzmzm^K&j5f9yXRZvL)2lQl|JY*oqn~I3OP?=gb&Lp)&D3=fy8ht@;CqD2 znh&!a2EZkDBY!%mR(w?14Zbhu%WUlY**GY+y?xbfglpmz?)avP#<$bjLO`+8!~$+Q zr=80i?G(vYC%Ikzx0!Z`X7%q;JiYpZZuyPQ90~DnjB7Y5`t{zFK+n^6IS#d5yniCP zt_pZ|_liXdjE$!&g1w6?ncc(FxNJ>d8wb5}%Z_+d48AAzx+j|EHd?RvI$hg-Bvboo zJ^YUt|D}fjKU<0Q;m4SE8_unS@)m`X_3Es1E8(Kpb_dqOf=ulzrF#C&@jl@X7CCiX zypqfO&HD-MU|$&C7H%5XrF(`hkC$SMe$cCppA^c3>pc|c7|@$ulzVOd=o=?4g!xY< znbbSoS2L>TsUM^7q^X3~&!_I1Pb2nIa9-Cc4YqB=!-y0XHNcli9qm*SvPJs&R##HK zJ@TW70Pj%R==c36_fZdGW3P&D6nrg}9)D;o&Vmp5pA_SWv!oX0DMXu)Z3r6<Zq@rjyrD5D02S}?|L57m|bKeC}4UX+v2Ni{C{84)2*D8=+12CnE6Cyi% z%;nln0J8ILd|&80TW?Xb{;csg)I5WU-ntPIt+pVl3(zVGR4jTbe-^1aOuWO^{<$>? ze7@Hox7gY7evVq5`O!gEfOkMkXDOnM*dtDX#oQoSP?YMNQeAUDoH4|n_!ZcXB!Rdn zT`?@YotrDDmU;BOU;lYk;f6I_-b-6+6D_y#rK|)&+h0a2quE?xL|TT|)G2qTT9Qt(g{N$u-5}em=PNv>eBJfM@06>Yt#DzRy3Y)4$Pxm+Y`CWzZ&{v$UuAYI zGZ^wvtL$O6(`LX-Y7Nh&e$earR6da3Sw?~JVu7ae1rkin?i0TUM~)xy(z8YT_S#sStSV_r5yv6Yb^zm&qP@W&rn6FLZ8FvCwFh z(TBLa>6=ZXQ?rIMSz)>^(67g-tr}3sG3rsS)LATsiqscYA=?o1AM;f~a z1^^$=`bk!Nqmo>#c9xZII>~v`iaCE1eRpFK4=$zlJCQ&7_z`E%`H+Lm;*%!h*y0#E z75A|PayFHtYUJs5)gkQRM+3JdGix5TbYbYprf0FCVe5B6I+mC zAoa=mG>Hx8UM~XtWY>Tk$12U{pt8P2?PIE&Ref-S*;Cl?^Pp+5LtM(!Q11hFYJ6MK z8Sabbz<@0BSF!xnyn4%^Z~#L(QFM4QX8t|*S!?YV+RkXCozU+U+Im_WZhAB|Lh;1s zJL|LPUE0oHY-_FF$3AD5V*z1YR+SsQK#BuIn@B2vC$56u*~{a#2}#dLd`{1z>G;c7 z@j5SXBv;~qr55j8jE!~JSX$57t`rFTTicPU6@y{o)?jGep=B}Kb{Wbl#0055Kf<++ z7+p-~8=7mOi%-hvCY_%P8i_flXqrQ8uCc#i#s}1AFC)bd*!FFYmDILHigwN^Fhgm9 z%$J@oy_JirTPDRx9JPV6R@Da_c~4qgGRTc%uMt)@p6tMEx~!xJ@7B-AvZ%VHyYJuvuu8IOidgC3R zTlx~3T+(oiFg|nVR6{F--YLzAC6Ub@!r|k@Dls{8{mt*tmDaBbob2*xfPsfQfS48#M2X0ma`krmSX3-1CxWIb0vpIg{3;1`PTCb zPj{F!M~?f0KHmmMP8HvZDXx?R(+&Mu9q_-{qg`q|$*n?sHzm^$^9MxK8v~^L0maxx z#vhP|ZKVAH!r1|axi|7Hva3C}$5UTRgTZ3m&{p_H_TrScj>Ks{aJ=k#kFDb755eHZ z;B9{6tz}?BA;nnbO@H}qXVY5utPy5zap=~}eACLQ;>O9PQP8PAzgjxC^m;Ed=Id|A z_TLO;%F8$GPV-edo-b4XR0F2p^K-hMl<=Y0|+e$#H{iG6=PTy3qlM6yj(1p8-D zwEsDv5ey+!wbWu2tv;eY{qxK6V53~b8#TiR;cB4*hAM4|ib9ArsQGjo+!x29TB`2y8Y zu`^d-y0od)WV2~%-Df#rU(f6T-(0$^ZVI=>0_*G12UdeKBz7LGeFG0zzkKF2rL2><5Phe zbPeqZuKGq{eJu*Y94XAzrFui)2?vB0)0AREDq{%<{eY)b#SvFpnQO zu4^FE0m?Q&UqY#7f=nnZs0bHr@SO}JekgOTAh}~qtJ6L45+f~xQ~Y~Y7?z5bC@#oM z&7zw0Ye*g|jfdbI6bK20OioItCNP$w(NZ9oC_8hYT&BY#PzfM4LPXDKQELHZIi$_Z zfiJBjzJoiYy#iBkaA4;FRXo&Na@DUFzbyoUb_3_cpr_<^JPk!b} zYJO&YTu{D2aDO#?5X+01(XGCp)nintEVa2g!OMCi_#9x^&QWbU@;)`M>6^6YHzSE1 zXRFCa{jP=28ggA@Xp&C);#5hjmE+jd+kueiy5(bIYvrOH@WrH^?;ES{GzVQJ0a(Sf z2c)_)A0Mr^iLE`&{dGyImyH@{OP&$I2(l;#myk~6b8uh;z2j~)tIEWd)mh4ffyxIc zPp}S4xnx>_CI79y4yR&Z8TVPjWrl0v$u#qpRa-8nZt2J19a6+A->a=cj#xLDNTaJQ z8;(Msb@qGlr52EPo>QW!QKb4SEk>yyNT(to;U`miZSNB%0Fcn?k|R{slcSwQ?A`X{ zs9ZVj!cef!zfGpkf9SD|Bq*U)y30K7AXT{U{3wo-zscbI$r6VO7WhAHmuXZ}*_MF2 z3Kb{7fMJLNWg;@8KoALpF#{wdkPy@g6>LErxy08M~nAn~Njh&CwkqXgXezL+`g; zW+XYcv%CduQ7y??L6AuYnJ~`n?G4FUhavSYq$WGJ2jO~^A|O~t2eb5B1#P$A9sFbu z=cXpwN~UpBoY+BWq_ypHE^?tMy8AQDQ$V=`R6EjKZI#nmD;ys;=?pKpPjk?4Zc)~R zzIxkS&!{U+PSs%uhiN%$&>i(DV zb%r*{2>)Vf^NZR=^;35ClPGlb^8#!0uyhXc(jfYy@8uRur><~NGd@3UXli*;OBkO| z?&)CR_?0;y~CD{wb?W8+EtQD%U_ra}$ z(zkZ1gp`GD(pxt0f`&5T_8@)sPD>EDzCyk))MJR?Vyn>O%S?yC9YN*-araAgI_M6U zo(%OFBI0d=uq=yi{ggDEy@Q1h%%wOlIZQ-GcL~sh?k<%lFnZ_c#S&r#Cpk{k?h>b| zwYGWF9_$a!b9Ht}#wO3*ROe`ays_1`hDo}Ei)zy2qnbqK_1sP2t`5R=?V3JyP5*Hz zzm=?bX{fu|((W>|HQbf!33=gn(R$JrTl4+|(}1te{u9JUUmb_iXa(_&R>N)rm+6Cw z>uYJ1>>kOaJT6wM;n8%NBUC$_$MtU^`{+_F_A zT?dbWJ20@E)dHWKctK#XdrzaLgE~5qnlj?A4CHKD!JW4sL8L!0b@ zOT}uxo1xaulIRB!*?9I^xJt%otfQ41>q(}+8Y31rvZyHCq2K(%;3w-y<2|yN@*~;^ zH~Dc;UHHSbmzq_QfUo-{X>iVte7T1#J>y53K5TDAtffL%p;8rgFqJ1xu(8oy_ zl)stRf$fI+F>@h;xXexxP`ubFGh|mb zQjqZlh%)xNo6qyQ0^}%gm%oZ=^Tm?J?a|JT0F4*8NXCIGydq+0Z2KLpR(8HcwNZn)ZPa3(~jjU~JAk zcG!ZNW2i5b4xz7n9!<(vhRVAORC42^AK=B_9}94t|3@f;gjm){2|BSTR^rv~H`VlO z;~f4kgpa7*iq)`g;BUeyHf^LN`UK%Ggri8LVi48}7=;tmhVM~Gg&U-d2`AWjxI=~n zWX!ZD%ukTUVTY>}$DsBjZ;ewFV|Jg!C5FZ>$RiBh1LlB9!U1~aG&#Y3bP~TD8t*Sn z0^Q!I&O`S-P|NH3V1XHhpMg=HI7;<97EXmuOabP=c~hYr29+i0bblQ^-+6W)niIL-Azx9(*>|{;%SlkoI%|;&t%>9HTsNr zdV!v}VBbMfI<4mrxt=rG{<>`ya)R{=BF~4LzMu`oW=+{RTXeYhWVhyf zIT_FqHvPPeZbX=|R$*OUF(NGoXTY@(4LA=An}1= z`MSe)_P<_j)^ASy&Nej>3GDcBDS^N1IGGV#nQBUGEs)nE@8HHEJcy+Y)qid7)ZymO zO1HERky;3)4FMN_^YqVOUgIx||9z*WfG2#ZJ`cJJ$V=vOe#@}zi+vYGa|CqkL= zSc612)KeGsF6+G32mWav-_m*W4^O8kS=IxFF344e?hYV;NnK{I_LsJok8<({oSnAn zOZX`aq{L661@&rLLEO*6p6P~X`Km^rV2HJGd|_TXt;ilxL^d)su&&|ZCU(kW&!X3cdk#_p`yV7NCu$#OP-1JHPi03+#EwEu74?($Q z_LWeJIo0z@>6`w`HP0=prqjNd_ee5R{D?$Cs(7&Xbf>T?Gy`{E+*&Hj zhAq?Qgo04=$gnuB=m2R;|ITBL{^f>*$`PRBR~WINn7CDtwZPsos96wa9-z5S!xCrN zdGkUA4Yt~HL0DsdDXifX;eO#A!2MF5f?VIc414kL=Rlap_=>Qqi$F}uE=C5Z`(YlI zpM~|DGb0btakB^cK@fkAkq}r26htgUI7H$=JvtJKDIE%W6bhOQ1>Fe+{pw!&L#T~P zdtl0RwiAFd$ovX2hk_&h;lanJG|us-g6(Kqrg68IhyDSgD)79(OrLSSP=Jp7@} z_Q{D5bABsLc^#$5{5y`&dQ;`2D|+p%qeC2rAVF|nd;jiED2-k$cSTNkdJ-;S3p6+5euqhM5DR#-flnt2MBIs5&yiQ@o}8pteg{C@2RGD#E-Mi z(J1rJ)rRkG21Yi%BVJ_V=EoVFO13OVvkT|PrC(v6EH%Hjq;1e82{zMGnwqq|g@2+TftY-?57MFWK{+&? zTEtNHGdtW^Q!QdeU%5P(^7%FJv_H7TICd?`;d%OlwqX7ddGEg#Z(Z$0;)kp=4|Fiu%qmQm)4vr9)zbqY? z``5p%i~NQ8KTt~p1QY-O00;nPY(7`?w&}7|LI40_mjM7H0000%P+u`KG&MLfH!w6Z zGBq$UHZ(ObG&NsSaBpdBWpXZbcy#T3TXP$^lIFW3{2yv(9(+3H^n^s}9=jVMQkG;} zvelxxJ?F7VLS!8kt9a@nnckRRwh#N0_AhKEP{k@F5-1eqopbAsn2SYxS-2z;nTgEA z|NY7jvOG$YVDH}#{(Tq(KL^1?i1}G?w0|@h3{HnfCws@ogM-t< z3Rl8T9{#(4X2B#a<2?BA;ltZE_xQC{^j!pBMYx7x z-=wp!{pml6yxnTDj6^)|YIUBi(#&W?TixTd8I6oD!n(wrv_6RqLyEQ}BKyOHYIU7E(h z!)9$=*~zkee2fJwe;H1h#EABSZX{Oz=r>J*#2A)453Z<&E4jZqqD!KH9F$xkT(0!p_{M( z{tWXd!4|)zFF7|)vem`S*t*B7g;ATvvM!1gw2~_f>=w>Bda~7p2!VZXqU6cJF7K0Y z8oT<1jkX*P3pbJ?5w?H3{UOZ4`D}(wrcoRf8;;m^Z%8H$V+)^G%>Fqo0%xdrB3VUoVh;&LwLoM@?<++`6SAsa^%9EV&E+bPmI83xtK zAYMEU1{?vj41NpaSZn~0hOrYcPFJfk!QPHx>O@ve0?PEOG-f$!|6u=gAUWYNDuUZE zTSN)hZh$*v^s(J&<`Oq3aEX4}`I@>md>6`I`{G4X1Fh)i#GCYf|R4<|&SsBji zi3oEPZPw2>lI882ah9(0FtPA#BcY+`D4ad5;eUeGe$YVg!z|vk&x5yb9`FFLwa5Ro z){`gDNLK7;eFGg}y++6=N5O5rl^^Q!*-jS64+4x9sfJo%BtWBJ`Zg_6t^92n7ttEehY)xt7GfQ!17qG+9+_6-G%p&;d)TeDz*&F|Ts4nG*8cVo1xGbe zz@(N|2iWRDOtUDrw7~y<0bNRpwO`5z=1HywKTg^ItLU*H2O87rHl62Asfw0JDAG7x zZ2lOWZv^mF2sQ}Fy5J6`133I^nmxgq{9#-IC#_If{ppXe6BoEpwQ#{dBnk446b63` zK9&iRxlci8qY442KY}8RTPFIxZRdI1|Gl2%mvFS51^a)82fCUfMF9Wx5EUo~&>TbQ z^RN5CA8H%$r!$b6n>0znC~pMlA1X!QClfo+u$M6?3c&0jqt-EUiZs%i7AAhE;mNNq z;DHW&fjN+d^tPP~d`Lzd%>}Gdnz}!Eq@gY{u=kVTA}9E&hR#%B6@9TU8 zQfIbA(-997Cr;e8+Ibp{?V8|zSCK;z;;Rfp*b^|K8Xm{h+t&K5UI4-SX`$P!U_ zboG$H;yCTz3vVria5vn3up<#gkN*O?AX5Y(Q7 z$vQ*jXe&)!qt{vRKfttIqJ#Q8Ukb0mpD^p@z34jU-HUY?fx(}?%!QYr*?ZN79qumzU_=GuqV2FHZi1^gon?lxJv0y-N|%vWCP zuCwfQ`10gBmE&+q&&E$;!COeO?V!I3Epht#pM$lYg^C69my|+H>xc9agg>a@aPZ%O zeSa3fUbzhy(F_dmsL(pkP#XAJE)3R?rcYuT;}+^Ml7oIH3P(a`*}D+zap`F;0UU*# z>BkV!`Svaa8jp|CEI>`>{ib_1j=hyf2CVbx4SrPmXbfGD!RnIr1E^q8x#AB7mY4Pj zGtD+L*@SZtaCn^=Z_0I)L@)u%Ou$mY|H?Zl47?5&7OL|g-Y$T#Kbd7I)%7{>0izD6 z`{_>Tq4hw)=Cy98(Scn7eH+DTo`b?j_HZZX6Eu-L%Pf7t9-5jQ!I3=+f>mmgD;I{G zF5yDJ#u%gS=>X{yr2puE9T8(7THuLz{!JegdP=70%8=HkUD>o8c()vSv18MIhtro> zrPNCoWm&ikeiM1&MCn7C6!NOIwb^L4FYis^B5|a@L?N7h(lsC55#F z^+-FAb(PP!EpwNA%Q;|krL_-aT zZk0Zvu3TiHx(PAtH4QxE4*#n#o9Y6pb-Q86k|>6citveuQw`%UMHNb(nB3<^QIgI| zd33m8gx5qIE6cU^3wFSV9fyVb%P!hWg`^gGmW$vrE(=Z5tJ)4(Q|vCyaFL7P%VTgJ z+=^@!Mso&j(PM)Pk&8?%QMS$n*U3Y23O$P~2O(_inX37b-=rP0ZZayms>UbIgK#hS z+UU6LL7x&GItyQd>#$&25}DX%4XMlfTUx-mdXbi>u#W`SFCqgmi1{Iv!5$BI>&5_l zIq|^LGOOF`YkL`H860zl`B%3l4nR07V5AROS^^K{EaJG&* ziwa;=|9aQ$QCmq^*n;?$mGkx*{lE`!Xy&LRbM(D6r5Z5wbfDMm5Bh%Kkh4KuD@UBY zK3q*4yIUKYqkiIR`_zEbeg|+ZGx=>@xd4Mn8E>A$CA)~j{eD|%I3QleC{GjqR=Y+F z%^Q5>e;L6ZnLnm6Kc)jljhF6V^Qx?d5H~7Dag|`UeNMlBk6FOc&f;)*Y;#16(zIZC zZK!j@ZJOlhTDUFs+upkMDciR{Ez@iz)yS&|lsfJ^2fi0gb$hDhM@Kj^#l52!b@4kR)=bs5TtU^$~UHPlqrG}ORy5jqLi>m_;$tjHmW zz{y}Kv!t_|#LX*a$UIp&D^ksl(J=aqe8phbxizlAt}0Py3hE#zTrwGj?@7bzICF;J zI0zD5ewCIBTmX4(14q|tPNd8>9Vt#iBo-u^&*kZlq0MAHon#Iz*JrR) zB3p~3Fyje&EP=1I@E|;R^=9o}j<&1k0@HDN_flV#OE@D+V73P^>$w=29xJ1+2Peza z#v_eyY65Cm#B2w<{BRK&^bXc@Q5(Ab#WJ3LiS64XY~;FFFSup(>R;2W3{w zf4el|A3|wd*GHkD;Q~43IB9mG-H16DhU=Ay{bn8_drGZ87 zzt{a(M5` z_+}l{0Ea%I6V}L+ofr3%3BG4Sps1MG&X(4bvJ!zDJ@flZ@0)pStY+g927O@x?O(yzdKbquIYATkPolg^O$*s<<<1FSP$6|5yaoZahAM5HT|s{$PL1swBk zKEJV@u;%nT0Iws=5yo_U{KoK|Yje1h-#m|lTBhs~Z%q;Xr3~dYG81`5!8)(~Db4cb zQ;4>N;r%tBJ4B~f$YIYV8yI(rVIeD9xlxC&;6rlx}IL*-mg9w?}4AQEi{dr;i;YyIZ z8v{flUCOyU9qjjW)Okm~TIn};eW6h33M{Z(EEM(BO`NmwG z4rrI8#8Iwf4V|t|^Oi5b7ENFSfqVtomCj{k3r2F8{6)~-e02}o^5y87#2D;_>D zb-gOMOv7q{4K&j!T;M(2ZIk26f(D$h(t^<)U}|k*xKylNOiTX%R6b>q;iiN0yuh5w zNfbZhmajbc1`}53f$xm!A;DZ=Hy=hoa04bR;2sP5jp2_Q%{{IIhyG!C)2Y(1bp5={ zl5nPZI7Y}HqY`!o`sR!7uxkS_;6jaLE5qzEuta|rlB=F{-xl7|**oath^G{~a!_b{ zy_a7_toeBUBxJn+dlwzG4;U=jpN72ZfDikrRnjx+=zI5}ZBnp%n^tMkfgL&(ewTUJ zTzi-iuTm}>_s%T@kpSU(O@gbNrbDV!WKp5K8rI8^)Z|!1N+ptWANf0fwekRi|Vy zYu&i8*_o`oNxZGm2GguER2}Z%&n zGI?G$51wu_l8-310UL$-xCzQPfm$v%H(zpo$IB+yPtI4lD4mte2W(-}P5VK= zJ*&bNxlhSsmv@A8O;qhMtef7I)T$e zq)`~WqRf&;h}_s#xpm6SGILk9rG|_l*y?z-F|6vv$UhR8ZLA+2Zsws!Q9TYK9XRw) zjcN5wt!jBDR#C{70akL!F*D`h;0O174EMq7GG~Fb7&M6Ag_q{Jj3W1WG#J`Bnr;T zDY*!avQ2PN=3J^v1qnB+l<*KnwT#idf_ZjE-`HGI?qHFvZ(tivK~dV-pMXRx*|MH{ zRrNYc!+CCQcBiT#krmIs4;RqzQ&WtLhSr7)mWd<{Rn!VED(!NoG24tTFpJT?PB0D# z3Azv0(azI#Q_e6DTo+3s#>4?3=DE>+vI^znGsRN69m6CcpSA_Es>NwP=g~89Tz=gv z-~#z5OCombI76+i%>6ao$j`>5Ah~QW&>SShlEiKNI@wMY77*v|!BG87V5;;^B9LUk z8y**4Lz&>Y9wm?1YHo@MvqIQalTq7{aGuG)-(W<{K);`a>zJwvldValI}e<9E-e)2 z!=S^QF>#wstYOZ|>Qb#o4XRaI(0DQ3Ri zVa>>n*!@sA%Z)pd0`KslhwoYrv2C!{Yalq@@vMd1X#LI8@;tw1;Bg($>~p*O)j2E4$eKzDph;XmMWX&ZdU!+v`BT)-eLB~VQ< z;Bzt{-e#3x4?rh?B}zohXd4=q-hXfF8?gyP8kE`BcW}&Qf)SXmU@50*CO69_N!~Gf zAJ1-lkup393YbOn&}?D25&5o$JulrVXRI|`ytXc9S=Qy_Ib~R$TkebbZQze_k*z+M ziK0N&i5N5vy&ZAaW~DrIXB08U^pdv9O);5m@bur^|0uV*UolfMiGyi8&eL8+oxY_X+EdU_V&wR5o|1QV6y>s0RPPf?uE>KQ9` z0q-X*zY8$s93veldw&zN5?}gI_AFmywN2=nF2QzY994hX1Wc*rwNKk5I3EC-7_Y!0qu?La$n)aYnT_NyAdw9Jkj(swqq|mNxWn9+tWSfT@O$6DfHvc^V6X zg;}(slm8e?HQ8X`d!<4pf)l?ZAqpNMON~0Se*0OTNb?#LYf$B+;TAqVnpc)oOSzx4 zE)5Khy9%=y?<=|P+pZeyrjv$ZPLYq{_wOCw;`LmkuAcE#6gA+1P>_ z+%isApw#j*wW|Vo*BUx%lT_8BV7fv1WSOoyWnaS8+J5S7pM+_OiqTFeI)(=8imO0p z?Y9W8^tof=OvdJ7un~qQve6Y2TdAj>(eQHfZ2dMUv8Hi2Cu^W@1-f-@UZ2JZ`T>po zm3og$y1iy$E=~N2$eyE_u#;p?IFPocly}yJW3QF<4F zaMLD2dUubPF^-R*^`Yd0=_VRqxT<*8;hDDJ6-3(t%g?I!8`GrB=@+e2Rb`ERl5ZKl z{|2HhxM_5!E#C6(l{=agfv#5$SP#QRl+UnYEhXfk276wp%K7NJ??s6KN(}9V^lsLp)LjpwH@jmYx6=-G@LbOUahS%4;vWG7ohQRLEi2>oDxK%X(D^)0)N#N9)WuP& zIU@ndLn5ul=Ji~6-RcY5a|Ni!#qoyen*FsSDWt$GPzmikj@CUvpJE<8MpB0e=YmJ6 zng=-}lCK4+AGzfV)ASEB0k+ypbK%~|lrCe?rQQ(&*C|XJDQIiALMG?zw_MNE6WtlJ)7zIkva5OXPqC)qQOf6PT%##k_h}9`E&8P{<=elx z_dWP0TjmCLS*qHzsXyBXzuGs}pX|?moHcJ9%labbiHPV{Lgqzl1MEbAyMy7KF$UCR zAu~9|EPh40LQ7#7YG3mub)fgXM*d*U`+8V{B5V5rj0h9xwJL zqK+|NhPkBz7}EHf#*go+NJ@3&F0wG+aZnb0#nX#a4T^n&rAH_DpljC^$%QgqeJez0;wp1s?MnT2nN{_u4Xn)Yaeq1L%uOVg?^&RokUSpxS%GW zntNNBQTDh3hQf!?K_nT%k;&L~_`#duDtqFq2-j)CJeTH*EU9=d0-9O%1j!Ay_&GSA zZeZhn4V81ar}-l{f+xc?r3c1wTF!GDoluTqW27kg3DZhG;c({ZLJqZZ+VsA~ACH@u zafh#pF%Vk7+bDj@x~~rra)nGJ?Ji+4e_{51u5SoTsnY%|7vt`uMU!qg$DN=BMC_4q zXGP||#?jasWoPjMDoiDqT8enJ&9X=&^Bhg}N<0iexc@{ySu^7`Fq+yaz|BdNQ9Wjk zK5*lW%Ql6OVPxxGpI{V{l1Tvl8YYEzSvN$k#q23Y#mN!gVY%m26qImO5z`|Qu-8cA zW7_4GXe`2~uI+({&YMpgP>bJT;^(^dtD@5Re5MgsW$3C%<{|wC0{J!~#!FqmZ&uG3 zQ;+qgt1dolBs3TWcX+mE(7cm!DzuVMl&4#T0(D0JBI2@ymcPb@-COlBq|s{4YDvq* z=1Q8(mNI6 zXh~ws&0y^bHMCF(c>fJHFKUlJ&p_M7eQYWU9WgwLu~E-;9Tc1cMfJc@AR1svgys*J zH+jx7j}dH&c3TNn)|`>&of->I()4SZ6?iY?ea$BQlQD-lVhPE5JP+EkAu zd&SFws@cp|lgk+z2JnkBd6T4yn>sxnBcS{a&(HJ)6ySwEB^RikMDbMRj$kvAMd9K) zyqL;R9Lq{Mk$7aKo`VT4oE2ivIN!2?8K(r)$~<-gd3J}Te+&~w1!O3gF&^C~kRs!( z&fw)<_;7LNekZ{vELxFiOcc{5bUqO}k{&G5sqF+B4o6$sA)@{RLvAsH&Lz&PB7Qka)(rG=d8UQ`p0a5VlPVl)*aIq`*nIqRL#gEw?+;G*x8@=y6u&#LXc2 z0^O#{iF)s$nDg#9NyuK(mRpy*adkt^UsQMHMpOix#-&fi36qF%AuC1EZKPL7Vt|ZJ zV!2ah;cRq@QLfjVMAuETGj|xl){s>+23MlUA|rbWVeey+CKz*}-9zJ+H552=q-+2v zh_^%(6xcR)VT3Tl*~WvffJw7ea9_rvE2a?+|AJFHWv>}8ul=1bUeUiB`@9i`!K`uk zZKKIt_0Bq2-Lf@zDRaKYbW27vL=@Pkc;F^8w1>?&5L;LrLYttB`*OM=cPhxxIzu3Y z^@tk@xwhz`^BY$hZxvxbj#2Wo3(1Wg&tBnT7iET5w_;t82U^CCf-=r~KSbJ#GV|Gn z661`Cbl2w_cRUj2?LRRonfm`2^hitCsR`$mqK*JVju2}P*x#YN8CwbgI}UWY3RaW4 z@r~aAljY``cb7y%4xU9}9DTQb-}yF|$6<9db`-efc- zMg7H!6UH!s(dF#MF%hcBmilH01@HJ%Nj$Bb#~_~k6@43d*)h<^!-Z`fr=8zT*F_d;T-Jlh>J~nNNG_cM5|)PoOtj0Zgsxg!C@0B zRq)2hl>~zbba*_zLSvmc9kM>8lqTChBx$?;)#i|SZIxO~=0qiF!b#sMx6$xW6&F=U z@*DOGAG#)&gOtwNRej@VnF?IT;`3y9@!Xk@#S>!%HHKVpYEgT~FgB<;HBu*-hkBWa zD`#PLn*>lmcOeTDS?e{U4I}g#^D2w}soz(1eHzn+=IwFWcHQy>TDqOc`VJ_K;_Vg5B?uTZFbjykgz*#cg>FZ)J$0AiYK{H8f`#5>y$ds( z-?hDzHir}%3U~sn%YuFA6{&c=ek(nji9CFWnTaGk7NH|41F6{FXjHe=#?w;>fj&Qp zsVZ;EM;df$m=ziOnPoNS@38twnaB(x*Ue~maF8O__JEIY$>}}uI!qRv^QjqvJrdVB z3cqKD{U5_M=G06)bfxw(1Q;7WeS8Ev)hIe|KzXt6ErJYstmMA~T>$KEer@g}P$n?l zh%pMgNGl5M!@UXr@Xw}haR}9iJh#X-PS-YFjLY$&T7lZ*`&(zl_9qp37QtEgB~zhe zq3#Y;$N`6RmF25}L-v!t?>I{m2ONoyX>s?-cKM`mha9fEK(hiLx%%y}(rWxMhsWG# z#^b6GCmf=E(<{qN$O9%!O!z7LK}#{FiXHa&Rn3=p{XA#+r;2!JwRhj&Z`sELx*dZp z1~Q>8=Vi?^460A`>XwI0I!wCUmT4S)HLpXqtYV_PN|S6E$Box-6?L95kws#`F-}FkJwcFMto z^iAHP2O$wGx0oP*Ua7oq7VbXhB;y$1 zgAACET<4k-`m{b~T8}Zz*t}e+7QV+|PnpKn+HkG)Hc{1je?aGTn9DrZbPd{k!7+@+ zi9{;>e5sN^m_@gszC^KUt#Sj*p zsx)mu9otZjOsR%RELbz^pk@@?Y;-tST1;d6q_?D~>n~_Kfp^{4EW<#|NRgUXn8yB^ z{s9N)N_sWi!T`==@y&94aO8dT4t5G`r_@RRNj~Kuo$5940|R4t;e549Ic8}4%Gz7T zS~9$52@8-d&0cec1>^MB)ofwGI;7U24P$#}sb&$|oY(^5YZkHKI=sC#$5_zL%2W;W zSo=KPhGUsd*)0!Q&>nnr3tcK#ISy-s%HBnq$l_kPZc6Z>Z#o#OCUEGhE}Z47*7efi z1IuS`vwshMiL^{~4sH9mbpz@6q2=pd;j0EQOJ{6mijF?8%|9P6XRN&q&OHgCLyz`s zE6C*i>Cj^f)Qs!ZaVNIkx|5wLnNtgyPERKxV_7(F-!a({(saZkZ9DPgfQNJCiU|Ml zK)bh?Fdz@Nn+*m7vT(QfB_jY)SVWKEtk7s!%S8}A=F#15S;7rG8IQySgAG_hHbuk` zt1Pz~o89AWW0sGE0*}wx z>rjsbzY;}JRZYk=SCG4sZ5T;c_Bn_tB7^G+E3)Fxmq+=slXiDGf5y<`R*ZuhSvbf0 z8pCpjgG`=d=S%eaX&xHwRY@&veVr6SX+atinsgSB5pxhxE5}=Rnt_e zE+S0&x^-#_*XdeU3eD2}?ZyS@TzUaPWWbfBd!Iu6M7C#DHW>9{SX;lXUcI^(>ohC4 z&(yIOmMNGl`JJyq-rA==ll9XymXES{sB2q9xmrI(NzcWvWUG&Rbqi^|?9uLDSqO5( zv@pwZ+C;beb`B4o$E=KsUN%*O-WGe`30{>>sDhw0`O5`1HMqo-SDqSgP2(Y5k=4gS zd6$*JOpcD_DtmMs|#uX;p*1E(N)z=(a>^?4QDw=bcm| z_-7b&dTA`bd-7lKtVECAh%UU8T}xVUXnQQnq(7%)yJ@N(lJgQtRW)%h^Sj1WwJFGH z?WlU&78@(E0JwHjgr;ZC)B)Rq^c-^5Z{D1zG763!0oNs73|pS#sEV3ZMi2&W9ca{B z^cjBFz{=98 zHM+BLILV-GCG26wo^*w|Bj5S$8`Q_rc{wxvhaQp9*T8%aDTaF0<@G7-VUa_}^zG}s$oiDP_Jz{~ls^C47wOu-cvA6~QslaEW{ow49)i%oPE@K% z|9LsDGs$l^7}}$C_&3ZpG4!X)3@cC@r-r+}(m6VRu)+>Ana;}n*uyHJN~PaxhkmW} z7|ePbZe+I3XQ5lw){^+hAD<l{UtDs+ipby_=6?rpYe6R zOe;C!VQ7!UhH}+7Z$aAr)v;^02ie|UHBS?n!qV1nD9hCYMR!%;nC-DEI ztKdPzhR1;?aIz}_6{*53KxZLshK$h*zbc;Q>c$LH=tW|Mi#cM3H@x9@0#2YV-WY7( zacHXMcTl7qvb+^Z!JsguG47(B=VMFZSQUVAV6~t3?aNYO4dF*MIu>PgzrMdv zWhOAIY@V(hALp#nmY;)rzQG_syKb`{D9-4-mJmk$@H$?;C}i$rthtN#B_G4g{%wgh z7)QP(bW=H~nHoS04LkGrZzdI_+aV(~pjvcsd6=jrf5F)D%A z#gs|LSS5?|)kK=i)%onJK}J0+?;6Sj=)X&9w6Ro9eh3v~R6ERTy*=r;RKhnF!CFRX z(v3IPruz*78!2O07?AQTYr12V*jPPgijVX;4%gbAqvPV=@nNBKNUqwkHX6oQeDc`d zFBYZdH4C zNY)PesYh1i1hDu#IT*g7?y1e9P^%;>-)0gEV4v-iIaOIl;^(@^u;RS_@*T#V+=T_G zl0Lb*wFB#|=K)4msfE}unWe5_vur|1#($s_@=eW|-)DQMR))8n$p;ouW~qOaweI*+H}EX@Ro(XYXdN@h@=m3 zFJ-qe7;kY~#zaE6zk`@b64KBaS*OcccZYZx@zPFbfpI8gH7F}YfF@qf%2xMkPE}P2 zTXpnJucpD@wKKv#Jr7YFuA{KO!r7*QK1llk(2>lpT^Psd)ang3kD)g7Hkwxt0nu5I zepV24%sWhE{?=*wq^euAeJ|Te+wRRUj`b)FQtFX3PG`h#-T5-R;WwY|;4{BTr+Fc= z{#W9+WuEJT!g=M{hJM-5Pbx2;ohi}9vs(Lv?h%hqRqu}42ewy@d9-15-B&mq&e{NQ zJvvEr*$^b62O)wLy+rUwbXE(ZMYp=JS`ealt9OgA(R*jr-9>a!qFbHSKIfd9bMc*- z=b86v-m7_LZsz^HW&#TP&Sd4$l-(g8r!t2*G^JC}pGk_>2U5S}fif^f=2PKssC(4V&D7^TNH^q|ZBr|Sd z-)}jxtNW4Ddi76Fn?S@Q#!<*3!(&FK4;0@1?0g@0H-(tS+e7hY=k^ejCHiU{t}nVS zOmuOCn{4siCh7fClt!WuF5?|upRDfMU0xEcK@T%KOebk-gWaOZPLwUG4TnZxM5MNH z%)f&4N^E8@;l2%LgGMio3)VIov)h29kjlvV%k`;XgrItuuh?3MO@p}(!OepUAD;J| zQ)G$V>J?ky;|5>Ha#}%sbl{6YO9Ua7Pq9->YdswD2RRu{z&W6ZCA9+-D8UWgPIiVo=Mywn43Ctl^i!6>KAWl zgjnIJqpxD!tinH15w?fqSW9Fh9l396J~n)^HcPkVy*N874#5r25N=5JFp{*CA9~ z8?I%-Wo%D6SISWnYR{wfK=UFY>H##*jz0|PR<;%R)Gp8PX))$t3!_7EMy{4lZhd(rx-4|s} z9}$HI`(pp3#8H&T?FFZITJQUs-X3OJt^(t@ z7KauY_-ikXcwtjdv9z+Jnr91gd87C&xC_FntrZx(RUy> z44p=X@K?4v$*6zKAa(kuv|6{gfmCy_^-+(e+Ny~~_SV?XSWA7vnG_;7k4u%l(w4oR znGMtFDBjE{7#Z^=EV-~1bud^ix5-%hTF-nlvE_)#Y6xHA=yid}Y_j6K_-N4`0c5*rR*LfFnFx+5+O$!fBrjMjz8a5TA)?8IvE~Y+u){`N9PCV}hTeCN2 z0I53KKMJMkf4&#a4H|27f{uJq3VcL*DoO37Q_?F&3!Aj%H4TT{@hH<0qsqrO3>CHP zEr)pDn_wZZJ>BGVx^2eFaii}5oP^?+9=18zBt=yH`NbNc5drE^psj2%ZL}qR2N6jL zqhsCbQ_b^@KsBWIZGqnYGJoB8T-Bo-tL5JUv(ww-gDRqeG80WU8 z^k8OR-ORklQ5U8ZRd#1sYi4DlBNqQ^(}XJX)6N(K*xZ*px&CMAxst!Uon~axxk_3> zX#A(qH?kslki{u^!hY=B>~z&91I=`MeR#6Zq7+H@?}~IU@$YA1{%J)VHmUw+_2`tK zG4WrsRHa!nk{Ii)+YW6L2P*R%qXj(m$?BID<}~40;$Qqe(q)+M5LMa2Bz3k&tDgCl-H6EvqXfFyPQ}XP8q>3-+J+ccbxA4=1+{&v45;Wl zSPy+d{EXKa5*Lpu)AkMacF!boVkcYgydt2gXJqL&T5>7tqVRd1SQ3HQykY>T8+RFG z;swctS&qGOU2j&7hI}|vUpYH}CHovP{K5G$=!1jSje@i*R5Er|E7AkLGm^c3Y;wab zyV^-T`#Y$x)+BwJZp43vz3tR4ZG#XPQ2D+LL_l1}6S>BVE{nRJ_lu5qS`(5LWjSKE zYkv~q6VHvs3=Y(2y}rFGrYgnwW+Vr&WC zZ5qAu^*gUH$2X#p;PfysB!lc80QN^G6sP(6=SB6(V3HjEr!GAsbGHHKbhW*PdIX+Q z1$+;dI3f@8GyvmJ)Nh*!sx!x8mMJQRgns><3Vs7^mB-~eM?fpZ{V6%1HNXAiy=K6~ z&jC^I%NEF=jx((g9_mua#*Yt?=P^F(uc;TRypSn zt5PaF?lBo`GxTI7>bA{;175o5C?3wIXVNn%F2jkTD+QVc*??02VOP7rlv%CM1)=RY zWM zM#S)iUjITop?_a2R$7Fy^O2~V!RxWH|4kkAasW;~rLDR7m3dDfDXF=8*qSQOd15q!SW)8iO_q99s*ExiAg3htm)e2?9i(r~_fmwf&le3a?Tc+BpB|Q<(cd2L zW!zwkzq#)N%`3qOruCk7P6%tw1Oya2;uX=if?UCv`H)hKC~CPVGZF6nV3KjZISp$? zYwKZlk)^boMIq}N?$JISJ^It6E>X`E*>#@UrKlv||NLIOS$>+0ml9i3q-ATwp8A?v zvV9QAc0rM<1ob+@3KL^{_=r09bD3nS-5w^f&NMo!QlIck={TaYRS0D;O_OLD%T+Cq0{?9F z5Od0M^D`<#%3y%DKDzGYg9dqU7R%n39N^+}Cyh_%t09g=ONEjE-X0k^b=3zrMesDL zy>N57AZ{8dwN|w7H#GF@5xKwDWp#R&RL$mI?2`+>wUT7As&Zisl3gwQxtxhAB9YK` zHef>hY~xx}XWLCVtM;Q-)yfP4Kb{Ni0&p)eenTyx3fF1v9^chc?FBxBKM?WK6K3Q< zJzL}asu1}ue=cXdJds4XsK~oW!0!%~e5{?o~^r(41W{M+@r?V`d^ zf5HTG*Bw;wEFi$Ox)&RvU1tH}N8{Rq!sos%&%nK@&IFAD^#+QIO`f(ZAzypL+;t z57i7wf~Wh5M8mXwQ?adqkAPp+@Dp58|30~hNMHdVry`r=f`k?&)Ou(gBQBq+K-A=*U*lQiAXrwv>&W^BV6)?s4tzes+YDa zO|rc(&SUg1AZF9^ZxaT6!!Un5wEWR1i7V5sR*A&#s|c6&H=$lU*Pp;VElcd;E$~{o zkww;-y}@9`2tB^d+Gp0Kqi0`g9W-e_A@n&Z0--+DH#=kl1f4vQVmMy?6^8SKrQHxWN3u&@#P9Q6{WE9XjrL}=JmB;HDsbK9( ziSQ@Sw_5(R`yt@xK=$j&a(Hthkj1n&z~8oRj{W{1L*BdZh=&EzWW>y^BoTM>-KM9c zRPehVa5B9ObO3XKrWl*$7$|lkftL?K2t5=UE+!B5ZLNqCO6@iv*^6mh!1}M5xTUyR z7K7(9YNuWGHbbSBTiyWZGmHqQ_%dd)kj07bR==B%2=wn2g|T23pWLz~OFITUancwc zm+fpT2lJWI6G+hI$^Vx6Byj6l#yVu;bkSDa0IX<@VtTDqQ5xB_TWwj?n$iol&^CRG zmXlF8$QTo4GmgRceCt_~*nB#*U*nI7J3g)U9i^wtZ>xo=oDgeDUz~~h^!Kz|SE^B+ zGeE1YsjJkqdIF~F#ZPUk_f}w|Li#|rv*u~aD_7YK3`PXj46t)BV^Keq+RZ+Xh*O0_ z&FT%~O9j3amb=PE&>0b7ftd^jcmY0RU{$0~S7GDzDLFJ1odUgs~A|(x; zZl^5o@z(eSQ1NC351wnInM0-Tv%bw| zd1BR-+Cp5vCMNcG?+Zf8#)Sy)zBYk#Nuxr=ca=Jd&<@CV|NeiWAuDuAzivbnP|EJG zH7&wnD{4mowS1X7SmR@kqR|s`S3{|=rFOTa^!Wy%joEpZ3jDyVOda&YJ%KhZ+)Gt1 z`8-fRmrYjz8#>v8yZhLv)cn4T6!fmLg4D*2Z70A$z1v|ZGIQmr@5P^rr-pK;l$jHs zqY1?+W%R0R2Pmn&TTY+X4{Jjs)uz{bO-nFBQKzhkapD!cA&hQ3AI zZ>rBdmF0Z{QcE#>rmRDPw2<1P05AVI_4H9YRxvqv%++145OMswx`aF2q_<65SQNS= z;OXzHOLjYlWzHCY_TelWz4Bd;`W<@x`H$Putbi&~s;4x5_L62X;pS=Qe!+j=SrKtZ z)EaMOi;JjV$6yb1Ijk_pcjQu0Da)jz5|_hw7f>12gtx28bZ--NTyrOMNX6xxDUMW& zis~QTGBcdpLn`CPIPu8R^0H@ezC)Q%{-p2fSaOD$Q!kAmkZz)G2|;$a2y7!(ZP-OW zq}E+zgvY-`Ke^J$xm{HM9=TY5u{d>soD^hc8?~l@yNz#}EyjD#O3wuzOW_8XuD1Uc zSrl!4DWmrOahUX}YLtL<2LkN_IlV$zP+}othqn@L*9k)5bHx}5qn30&vq-+Sl)(7G zP!$8x1U+FWh3(Hzau+;e)bWS%f|yIPppNL!Ts;aaEfK^>glYI9TSL ztV`6kX^pSC#>&$7YqZm3`q|0BuXwe)Ui?aNi{v2e&PlhH@pcuGF<%*NTFeZxs=4C^ z9G5{)O&9A&jYgKnw%P?(TMdO{=hl`|_MM!z`~)z8rpP*R$0_^O4S|@bC{Z37yktMv;@Hq!v~&Q5ME$0D`LhU( zQpoO7@5@`3e^hbtXmI|+Qhd5+Dd@k{k?c?4;E+t?{F|k?mnr@|eg*w2{12pp-`v&m yv#qn0gSm~C#Bry3u6aKe)@sBDY(Z4p~-Os%H*h7PRzy2S9{)K=5 literal 0 HcmV?d00001 diff --git a/disabled yamls/DLCPlayer.yaml b/disabled yamls/DLCPlayer.yaml new file mode 100644 index 000000000000..39cf505dbe1f --- /dev/null +++ b/disabled yamls/DLCPlayer.yaml @@ -0,0 +1,14 @@ +DLCQuest: + progression_balancing: random + accessibility: random + double_jump_glitch: random + coinsanity: random + coinbundlequantity: random + time_is_money: random + ending_choice: random + campaign: random + item_shuffle: random + death_link: random +description: 'Generated by https://archipelago.gg/ for DLCQuest' +game: DLCQuest +name: DLCPlayer diff --git a/disabled yamls/DLCTester.yaml b/disabled yamls/DLCTester.yaml new file mode 100644 index 000000000000..ab846608fb78 --- /dev/null +++ b/disabled yamls/DLCTester.yaml @@ -0,0 +1,13 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: items + double_jump_glitch: simple + time_is_money: option_I_want_speed + coinsanity: coin + coinbundlequantity: 20 + ending_choice: true + campaign: both + item_shuffle: shuffled +description: 'Generated by https://archipelago.gg/' +game: DLCquest +name: KaitoKid \ No newline at end of file diff --git a/disabled yamls/DragorrodSV.yaml b/disabled yamls/DragorrodSV.yaml new file mode 100644 index 000000000000..b65e5cceec08 --- /dev/null +++ b/disabled yamls/DragorrodSV.yaml @@ -0,0 +1,528 @@ + +name: DragorrodSV + +game: Stardew Valley +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +Stardew Valley: + progression_balancing: 10 + accessibility: items + + + plando_items: + - items: + Beach Bridge: 1 + Amaranth Seeds: 1 + Corn Seeds: 1 + Desert Obelisk: 1 + Fishing Level: 7 + Galaxy Dagger: 1 + Galaxy Hammer: 1 + Galaxy Sword: 1 + Greenhouse: 1 + Haley <3: 3 + Harvey <3: 3 + Elliott <3: 3 + Emily <3: 3 + Alex <3: 3 + Island Farmhouse: 1 + Island North Turtle: 1 + Island West Turtle: 1 + Kale Seeds: 1 + Luck Level: 5 + Maru <3: 3 + Melon Seeds: 1 + Minecarts Repair: 1 + Movement Speed Bonus: 5 + Parrot Express: 1 + Penny <3: 3 + Progressive Barn: 3 + Progressive Coop: 3 + Progressive Fishing Rod: 2 + Progressive House: 3 + Red Cabbage Seeds: 1 + Return Scepter: 1 + Rusty Key: 1 + Sebastian <3: 3 + Seed Maker: 1 + Shane <3: 3 + Silo: 1 + Skull Key: 1 + Stardrop: 2 + Starfruit Seeds: 1 + Strawberry Seeds: 1 + Sunflower Seeds: 1 + The Queen of Sauce: 1 + Tomato Seeds: 1 + Tractor Garage: 1 + locations: + - 25,000g Bundle + - Catch A Squid + - Catch a Lingcod + - A Curious Substance + - Aquatic Overpopulation + - Biome Balance + - Cellar Blueprint + - Collect All Rarecrows + - Complete Fish Tank + - Crop Order + - Danger In The Deep + - Deluxe Barn Blueprint + - Deluxe Coop Blueprint + - Fair Stardrop + - "Fishsanity: Blobfish" + - "Fishsanity: Blue Discus" + - "Fishsanity: Glacierfish" + - "Fishsanity: Ice Pip" + - "Fishsanity: Lava Eel" + - "Fishsanity: Legend" + - "Fishsanity: Midnight Squid" + - "Fishsanity: Midnight Carp" + - "Fishsanity: Scorpion Carp" + - "Fishsanity: Spook Fish" + - "Fishsanity: Stingray" + - "Fishsanity: Void Salmon" + - Floor 120 Elevator + - Four Precious Stones + - Fragments of the past + - "Friendsanity: Abigail 14 <3" + - "Friendsanity: Alex 14 <3" + - "Friendsanity: Elliott 14 <3" + - "Friendsanity: Emily 14 <3" + - "Friendsanity: Haley 14 <3" + - "Friendsanity: Harvey 14 <3" + - "Friendsanity: Leah 14 <3" + - "Friendsanity: Maru 14 <3" + - "Friendsanity: Penny 14 <3" + - "Friendsanity: Sam 14 <3" + - "Friendsanity: Sebastian 14 <3" + - "Friendsanity: Shane 14 <3" + - Gifts for George + - Galaxy Sword Shrine + - Grange Display + - Harvest Banana + - Harvest Cactus Fruit + - Have Another Baby + - "Help Wanted: Fishing 5" + - "Help Wanted: Gathering 5" + - "Help Wanted: Item Delivery 20" + - "Help Wanted: Slay Monsters 5" + - Iridium Axe Upgrade + - Iridium Hoe Upgrade + - Iridium Pickaxe Upgrade + - Iridium Trash Can Upgrade + - Iridium Watering Can Upgrade + - Island Farmhouse + - Island Ingredients + - Island Mailbox + - Island Resort + - Island Trader + - Island West Turtle + - Juicy Bugs Wanted! + - Kids Room Blueprint + - Kitchen Blueprint + - Level 10 Binning + - Level 10 Cooking + - Level 10 Combat + - Level 10 Luck + - Level 10 Mining + - Level 10 Foraging + - Level 7 Archaeology + - Level 7 Combat + - Level 7 Cooking + - Level 7 Farming + - Level 7 Fishing + - Level 7 Foraging + - Level 7 Mining + - Level 7 Socializing + - Mayor's Need + - "Museumsanity: Golden Relic" + - "Museumsanity: Rare Disc" + - Night Fishing Bundle + - Pierre's Prime Produce + - Parrot Express + - Purchase Iridium Rod + - Qi's Challenge + - Qi's Crop + - Qi's Cuisine + - Qi's Kindness + - Qi's Prismatic Grange + - Quality Crops Bundle + - Repair Boat Anchor + - Repair Boat Hull + - Repair Ticket Machine + - Robin's Project + - Robin's Resource Rush + - Rock Rejuvenation + - Strange Note + - The Mines Floor 110 Treasure + - The Mysterious Qi + - The Strong Stuff + - Tractor Garage Blueprint + - Tropical Fish + - Volcano Bridge + - Volcano Caldera Treasure + - Volcano Exit Shortcut + - "Wanted: Lobster" + from_pool: true + world: NevaSV + force: true + percentage: 100 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + Farm Computer: 1 + Movement Speed Bonus: 2 + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + goal: + community_center: 50 + grandpa_evaluation: 0 + bottom_of_the_mines: 0 + cryptic_note: 0 + master_angler: 0 + complete_collection: 0 + full_house: 0 + greatest_walnut_hunter: 0 + perfection: 0 + + starting_money: 800 + + profit_margin: 125 + + bundle_randomization: + vanilla: 0 + thematic: 0 + shuffled: 50 + + bundle_price: + # How many items are needed for the community center bundles? + # Very Cheap: Every bundle will require 2 items fewer than usual + # Cheap: Every bundle will require 1 item fewer than usual + # Normal: Every bundle will require the vanilla number of items + # Expensive: Every bundle will require 1 extra item when applicable + very_cheap: 0 + cheap: 0 + normal: 0 + expensive: 50 + + entrance_randomization: + # Should area entrances be randomized? + # Disabled: No entrance randomization is done + # Pelican Town: Only buildings in the main town area are randomized among each other + # Non Progression: Only buildings that are always available are randomized with each other + # Buildings: All Entrances that Allow you to enter a building using a door are randomized with each other + # Chaos: Same as above, but the entrances get reshuffled every single day! + disabled: 0 + pelican_town: 0 + non_progression: 0 + buildings: 50 + chaos: 0 + + season_randomization: + # Should seasons be randomized? + # All settings allow you to choose which season you want to play next (from those unlocked) at the end of a season. + # Disabled: You will start in Spring with all seasons unlocked. + # Randomized: The seasons will be unlocked randomly as Archipelago items. + # Randomized Not Winter: The seasons are randomized, but you're guaranteed not to start with winter. + # Progressive: You will start in Spring and unlock the seasons in their original order. + disabled: 0 + randomized: 50 + randomized_not_winter: 0 + progressive: 0 + + cropsanity: + # Formerly named "Seed Shuffle" + # Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. + # Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops + # Shuffled: Seeds are unlocked as archipelago item, for each seed there is a location check for growing and harvesting that crop + disabled: 0 + shuffled: 50 + + backpack_progression: + # How is the backpack progression handled? + # Vanilla: You can buy them at Pierre's General Store. + # Progressive: You will randomly find Progressive Backpack upgrades. + # Early Progressive: You can expect your first Backpack in sphere 1. + vanilla: 0 + progressive: 0 + early_progressive: 50 + + tool_progression: + # How is the tool progression handled? + # Vanilla: Clint will upgrade your tools with ore. + # Progressive: You will randomly find Progressive Tool upgrades. + vanilla: 0 + progressive: 50 + + skill_progression: + # How is the skill progression handled? + # Vanilla: You will level up and get the normal reward at each level. + # Progressive: The xp will be earned internally, locations will be sent when you earn a level. Your real + # levels will be scattered around the multiworld. + vanilla: 0 + progressive: 50 + + building_progression: + # How is the building progression handled? + # Vanilla: You will buy each building normally. + # Progressive: You will receive the buildings and will be able to build the first one of each type for free, + # once it is received. If you want more of the same building, it will cost the vanilla price. + # Progressive early shipping bin: You can expect your shipping bin in sphere 1. + vanilla: 0 + progressive: 0 + progressive_early_shipping_bin: 50 + + festival_locations: + # Locations for attending and participating in festivals + # With Disabled, you do not need to attend festivals + # With Easy, there are checks for participating in festivals + # With Hard, the festival checks are only granted when the player performs well in the festival + disabled: 0 + easy: 50 + hard: 0 + + elevator_progression: + # How is Elevator progression handled? + # Vanilla: You will unlock new elevator floors for yourself. + # Progressive: You will randomly find Progressive Mine Elevators to go deeper. Locations are sent for reaching + # every elevator level. + # Progressive from previous floor: Same as progressive, but you must reach elevator floors on your own, + # you cannot use the elevator to check elevator locations + vanilla: 0 + progressive: 0 + progressive_from_previous_floor: 50 + + arcade_machine_locations: + # How are the Arcade Machines handled? + # Disabled: The arcade machines are not included in the Archipelago shuffling. + # Victories: Each Arcade Machine will contain one check on victory + # Victories Easy: The arcade machines are both made considerably easier to be more accessible for the average + # player. + # Full Shuffling: The arcade machines will contain multiple checks each, and different buffs that make the game + # easier are in the item pool. Junimo Kart has one check at the end of each level. + # Journey of the Prairie King has one check after each boss, plus one check for each vendor equipment. + disabled: 50 + victories: 0 + victories_easy: 0 + full_shuffling: 0 + + special_order_locations: + # How are the Special Orders handled? + # Disabled: The special orders are not included in the Archipelago shuffling. + # Board Only: The Special Orders on the board in town are location checks + # Board and Qi: The Special Orders from Qi's walnut room are checks, as well as the board in town + disabled: 0 + board_only: 0 + board_qi: 50 + + help_wanted_locations: 40 + + fishsanity: + # Locations for catching fish? + # None: There are no locations for catching fish + # Legendaries: Each of the 5 legendary fish are checks + # Special: A curated selection of strong fish are checks + # Randomized: A random selection of fish are checks + # All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal + # Exclude Legendaries: Every fish except legendaries + # Exclude Hard Fish: Every fish under difficulty 80 + # Only Easy Fish: Every fish under difficulty 50 + none: 0 + legendaries: 0 + special: 0 + randomized: 0 + all: 50 + exclude_legendaries: 0 + exclude_hard_fish: 0 + only_easy_fish: 0 + + museumsanity: + # Locations for museum donations? + # None: There are no locations for donating artifacts and minerals to the museum + # Milestones: The donation milestones from the vanilla game are checks + # Randomized: A random selection of minerals and artifacts are checks + # All: Every single donation will be a check + none: 0 + milestones: 0 + randomized: 0 + all: 50 + + friendsanity: + # Locations for friendships? + # None: There are no checks for befriending villagers + # Bachelors: Each heart of a bachelor is a check + # Starting NPCs: Each heart for npcs that are immediately available is a check + # All: Every heart with every NPC is a check, including Leo, Kent, Sandy, etc + # All With Marriage: Marriage candidates must also be dated, married, and befriended up to 14 hearts. + none: 0 + bachelors: 0 + starting_npcs: 0 + all: 0 + all_with_marriage: 50 + + friendsanity_heart_size: + # If using friendsanity, how many hearts are received per item, and how many hearts must be earned to send a check + # A higher value will lead to fewer heart items in the item pool, reducing bloat + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 1 + # Maximum value is 8 + 3: 50 + random: 0 + random-low: 0 + random-high: 0 + + movement_buff_number: + # Number of movement speed buffs to the player that exist as items in the pool. + # Each movement speed buff is a +25% multiplier that stacks additively + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 12 + 10: 50 + random: 0 + random-low: 0 + random-high: 0 + + luck_buff_number: + # Number of luck buffs to the player that exist as items in the pool. + # Each luck buff is a bonus to daily luck of 0.025 + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 12 + 10: 50 + random: 0 + random-low: 0 + random-high: 0 + + exclude_ginger_island: + # Exclude Ginger Island? + # This option will forcefully exclude everything related to Ginger Island from the slot. + # If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway + false: 50 + true: 0 + + trap_items: + # When rolling filler items, including resource packs, the game can also roll trap items. + # This setting is for choosing if traps will be in the item pool, and if so, how punishing they will be. + no_traps: 0 + easy: 0 + medium: 0 + hard: 0 + hell: 50 + nightmare: 0 + + multiple_day_sleep_enabled: + # Enable the ability to sleep automatically for multiple days straight? + false: 0 + true: 50 + + multiple_day_sleep_cost: + # How much gold it will cost to use MultiSleep. You will have to pay that amount for each day skipped. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 200 + random: 0 + random-low: 0 + random-high: 0 + free: 50 # equivalent to 0 + cheap: 0 # equivalent to 25 + medium: 0 # equivalent to 50 + expensive: 0 # equivalent to 100 + + experience_multiplier: + # How fast you want to earn skill experience. A lower setting mean less experience. + # A higher setting means more experience. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 800 + random: 0 + random-low: 0 + random-high: 0 + half: 0 # equivalent to 50 + vanilla: 0 # equivalent to 100 + double: 0 # equivalent to 200 + triple: 50 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + friendship_multiplier: + # How fast you want to earn friendship points with villagers. + # A lower setting mean less friendship per action. + # A higher setting means more friendship per action. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 800 + random: 0 + random-low: 0 + random-high: 0 + half: 0 # equivalent to 50 + vanilla: 0 # equivalent to 100 + double: 0 # equivalent to 200 + triple: 50 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + debris_multiplier: + # How much debris will spawn on the player's farm? + # Vanilla: debris spawns normally + # Half: debris will spawn at half the normal rate + # Quarter: debris will spawn at one quarter of the normal rate + # None: No debris will spawn on the farm, ever + # Start Clear: debris will spawn at the normal rate, but the farm will be completely clear when starting the game + vanilla: 0 + half: 50 + quarter: 0 + none: 0 + start_clear: 0 + + quick_start: + # Do you want the quick start package? You will get a few items to help early game automation, + # so you can use the multiple day sleep at its maximum. + false: 0 + true: 50 + + gifting: + # Do you want to enable gifting items to and from other Stardew Valley worlds? + false: 0 + true: 50 + + mods: + # List of mods that will be considered for shuffling. + ["Bigger Backpack", "Tractor Mod", "Luck Skill", "Archaeology", "Cooking Skill", "Binning Skill"] + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 50 + true: 0 diff --git a/disabled yamls/GiftReceiver.yaml b/disabled yamls/GiftReceiver.yaml new file mode 100644 index 000000000000..9b63c341a31a --- /dev/null +++ b/disabled yamls/GiftReceiver.yaml @@ -0,0 +1,41 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: locations + goal: bottom_of_the_mines + starting_money: -1 + profit_margin: 200 + bundle_randomization: vanilla + bundle_price: very_cheap + entrance_randomization: disabled + season_randomization: disabled + cropsanity: disabled + backpack_progression: vanilla + tool_progression: vanilla + skill_progression: vanilla + building_progression: vanilla + festival_locations: disabled + elevator_progression: vanilla + arcade_machine_locations: disabled + special_order_locations: disabled + help_wanted_locations: 0 + fishsanity: none + museumsanity: none + friendsanity: none + friendsanity_heart_size: 4 + movement_buff_number: 4 + luck_buff_number: 4 + exclude_ginger_island: 'true' + trap_items: no_traps + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 800 + friendship_multiplier: 800 + debris_multiplier: none + quick_start: 'true' + gifting: 'true' + death_link: 'false' + start_inventory: + {"Movement Speed Bonus": 4} +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: Receiver diff --git a/disabled yamls/GiftSender.yaml b/disabled yamls/GiftSender.yaml new file mode 100644 index 000000000000..c7105919df42 --- /dev/null +++ b/disabled yamls/GiftSender.yaml @@ -0,0 +1,41 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: locations + goal: bottom_of_the_mines + starting_money: -1 + profit_margin: 200 + bundle_randomization: vanilla + bundle_price: very_cheap + entrance_randomization: disabled + season_randomization: disabled + cropsanity: disabled + backpack_progression: vanilla + tool_progression: vanilla + skill_progression: vanilla + building_progression: vanilla + festival_locations: disabled + elevator_progression: vanilla + arcade_machine_locations: disabled + special_order_locations: disabled + help_wanted_locations: 0 + fishsanity: none + museumsanity: none + friendsanity: none + friendsanity_heart_size: 4 + movement_buff_number: 4 + luck_buff_number: 4 + exclude_ginger_island: 'true' + trap_items: no_traps + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 800 + friendship_multiplier: 800 + debris_multiplier: none + quick_start: 'true' + gifting: 'true' + death_link: 'false' + start_inventory: + {"Movement Speed Bonus": 4} +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: Sender diff --git a/disabled yamls/Kat.yaml b/disabled yamls/Kat.yaml new file mode 100644 index 000000000000..d9a0301f5c61 --- /dev/null +++ b/disabled yamls/Kat.yaml @@ -0,0 +1,40 @@ +Stardew Valley: + progression_balancing: 65 + accessibility: locations + goal: community_center + starting_money: 5000 + profit_margin: 300 + bundle_randomization: shuffled + bundle_price: cheap + entrance_randomization: disabled + season_randomization: progressive + cropsanity: shuffled + backpack_progression: vanilla + tool_progression: progressive + skill_progression: progressive + building_progression: progressive_early_shipping_bin + festival_locations: easy + elevator_progression: progressive_from_previous_floor + arcade_machine_locations: disabled + special_order_locations: board_only + help_wanted_locations: 7 + fishsanity: none + museumsanity: all + friendsanity: none + friendsanity_heart_size: 4 + movement_buff_number: 4 + luck_buff_number: 8 + exclude_ginger_island: 'true' + trap_items: no_traps + multiple_day_sleep_enabled: 'false' + multiple_day_sleep_cost: 0 + experience_multiplier: 200 + friendship_multiplier: 400 + debris_multiplier: vanilla + quick_start: 'true' + gifting: 'false' + mods: [] + death_link: 'false' +description: 'Generated by https://archipelago.gg/ for Stardew Valley' +game: Stardew Valley +name: Kat diff --git a/disabled yamls/NevaSV.yaml b/disabled yamls/NevaSV.yaml new file mode 100644 index 000000000000..da096ae8b67b --- /dev/null +++ b/disabled yamls/NevaSV.yaml @@ -0,0 +1,527 @@ + +name: NevaSV + +game: Stardew Valley +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +Stardew Valley: + progression_balancing: 10 + accessibility: items + + plando_items: + - items: + Beach Bridge: 1 + Amaranth Seeds: 1 + Corn Seeds: 1 + Desert Obelisk: 1 + Fishing Level: 7 + Galaxy Dagger: 1 + Galaxy Hammer: 1 + Galaxy Sword: 1 + Greenhouse: 1 + Haley <3: 3 + Harvey <3: 3 + Elliott <3: 3 + Emily <3: 3 + Alex <3: 3 + Island Farmhouse: 1 + Island North Turtle: 1 + Island West Turtle: 1 + Kale Seeds: 1 + Luck Level: 5 + Maru <3: 3 + Melon Seeds: 1 + Minecarts Repair: 1 + Movement Speed Bonus: 5 + Parrot Express: 1 + Penny <3: 3 + Progressive Barn: 3 + Progressive Coop: 3 + Progressive Fishing Rod: 2 + Progressive House: 3 + Red Cabbage Seeds: 1 + Return Scepter: 1 + Rusty Key: 1 + Sebastian <3: 3 + Seed Maker: 1 + Shane <3: 3 + Silo: 1 + Skull Key: 1 + Stardrop: 2 + Starfruit Seeds: 1 + Strawberry Seeds: 1 + Sunflower Seeds: 1 + The Queen of Sauce: 1 + Tomato Seeds: 1 + Tractor Garage: 1 + locations: + - 25,000g Bundle + - Catch A Squid + - Catch a Lingcod + - A Curious Substance + - Aquatic Overpopulation + - Biome Balance + - Cellar Blueprint + - Collect All Rarecrows + - Complete Fish Tank + - Crop Order + - Danger In The Deep + - Deluxe Barn Blueprint + - Deluxe Coop Blueprint + - Fair Stardrop + - "Fishsanity: Blobfish" + - "Fishsanity: Blue Discus" + - "Fishsanity: Glacierfish" + - "Fishsanity: Ice Pip" + - "Fishsanity: Lava Eel" + - "Fishsanity: Legend" + - "Fishsanity: Midnight Squid" + - "Fishsanity: Midnight Carp" + - "Fishsanity: Scorpion Carp" + - "Fishsanity: Spook Fish" + - "Fishsanity: Stingray" + - "Fishsanity: Void Salmon" + - Floor 120 Elevator + - Four Precious Stones + - Fragments of the past + - "Friendsanity: Abigail 14 <3" + - "Friendsanity: Alex 14 <3" + - "Friendsanity: Elliott 14 <3" + - "Friendsanity: Emily 14 <3" + - "Friendsanity: Haley 14 <3" + - "Friendsanity: Harvey 14 <3" + - "Friendsanity: Leah 14 <3" + - "Friendsanity: Maru 14 <3" + - "Friendsanity: Penny 14 <3" + - "Friendsanity: Sam 14 <3" + - "Friendsanity: Sebastian 14 <3" + - "Friendsanity: Shane 14 <3" + - Gifts for George + - Galaxy Sword Shrine + - Grange Display + - Harvest Banana + - Harvest Cactus Fruit + - Have Another Baby + - "Help Wanted: Fishing 5" + - "Help Wanted: Gathering 5" + - "Help Wanted: Item Delivery 20" + - "Help Wanted: Slay Monsters 5" + - Iridium Axe Upgrade + - Iridium Hoe Upgrade + - Iridium Pickaxe Upgrade + - Iridium Trash Can Upgrade + - Iridium Watering Can Upgrade + - Island Farmhouse + - Island Ingredients + - Island Mailbox + - Island Resort + - Island Trader + - Island West Turtle + - Juicy Bugs Wanted! + - Kids Room Blueprint + - Kitchen Blueprint + - Level 10 Binning + - Level 10 Cooking + - Level 10 Combat + - Level 10 Luck + - Level 10 Mining + - Level 10 Foraging + - Level 7 Archaeology + - Level 7 Combat + - Level 7 Cooking + - Level 7 Farming + - Level 7 Fishing + - Level 7 Foraging + - Level 7 Mining + - Level 7 Socializing + - Mayor's Need + - "Museumsanity: Golden Relic" + - "Museumsanity: Rare Disc" + - Night Fishing Bundle + - Pierre's Prime Produce + - Parrot Express + - Purchase Iridium Rod + - Qi's Challenge + - Qi's Crop + - Qi's Cuisine + - Qi's Kindness + - Qi's Prismatic Grange + - Quality Crops Bundle + - Repair Boat Anchor + - Repair Boat Hull + - Repair Ticket Machine + - Robin's Project + - Robin's Resource Rush + - Rock Rejuvenation + - Strange Note + - The Mines Floor 110 Treasure + - The Mysterious Qi + - The Strong Stuff + - Tractor Garage Blueprint + - Tropical Fish + - Volcano Bridge + - Volcano Caldera Treasure + - Volcano Exit Shortcut + - "Wanted: Lobster" + from_pool: true + world: DragorrodSV + force: true + percentage: 100 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + Farm Computer: 1 + Movement Speed Bonus: 2 + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + goal: + community_center: 50 + grandpa_evaluation: 0 + bottom_of_the_mines: 0 + cryptic_note: 0 + master_angler: 0 + complete_collection: 0 + full_house: 0 + greatest_walnut_hunter: 0 + perfection: 0 + + starting_money: 800 + + profit_margin: 125 + + bundle_randomization: + vanilla: 0 + thematic: 0 + shuffled: 50 + + bundle_price: + # How many items are needed for the community center bundles? + # Very Cheap: Every bundle will require 2 items fewer than usual + # Cheap: Every bundle will require 1 item fewer than usual + # Normal: Every bundle will require the vanilla number of items + # Expensive: Every bundle will require 1 extra item when applicable + very_cheap: 0 + cheap: 0 + normal: 0 + expensive: 50 + + entrance_randomization: + # Should area entrances be randomized? + # Disabled: No entrance randomization is done + # Pelican Town: Only buildings in the main town area are randomized among each other + # Non Progression: Only buildings that are always available are randomized with each other + # Buildings: All Entrances that Allow you to enter a building using a door are randomized with each other + # Chaos: Same as above, but the entrances get reshuffled every single day! + disabled: 50 + pelican_town: 0 + non_progression: 0 + buildings: 0 + chaos: 0 + + season_randomization: + # Should seasons be randomized? + # All settings allow you to choose which season you want to play next (from those unlocked) at the end of a season. + # Disabled: You will start in Spring with all seasons unlocked. + # Randomized: The seasons will be unlocked randomly as Archipelago items. + # Randomized Not Winter: The seasons are randomized, but you're guaranteed not to start with winter. + # Progressive: You will start in Spring and unlock the seasons in their original order. + disabled: 0 + randomized: 50 + randomized_not_winter: 0 + progressive: 0 + + cropsanity: + # Formerly named "Seed Shuffle" + # Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. + # Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops + # Shuffled: Seeds are unlocked as archipelago item, for each seed there is a location check for growing and harvesting that crop + disabled: 0 + shuffled: 50 + + backpack_progression: + # How is the backpack progression handled? + # Vanilla: You can buy them at Pierre's General Store. + # Progressive: You will randomly find Progressive Backpack upgrades. + # Early Progressive: You can expect your first Backpack in sphere 1. + vanilla: 0 + progressive: 0 + early_progressive: 50 + + tool_progression: + # How is the tool progression handled? + # Vanilla: Clint will upgrade your tools with ore. + # Progressive: You will randomly find Progressive Tool upgrades. + vanilla: 0 + progressive: 50 + + skill_progression: + # How is the skill progression handled? + # Vanilla: You will level up and get the normal reward at each level. + # Progressive: The xp will be earned internally, locations will be sent when you earn a level. Your real + # levels will be scattered around the multiworld. + vanilla: 0 + progressive: 50 + + building_progression: + # How is the building progression handled? + # Vanilla: You will buy each building normally. + # Progressive: You will receive the buildings and will be able to build the first one of each type for free, + # once it is received. If you want more of the same building, it will cost the vanilla price. + # Progressive early shipping bin: You can expect your shipping bin in sphere 1. + vanilla: 0 + progressive: 0 + progressive_early_shipping_bin: 50 + + festival_locations: + # Locations for attending and participating in festivals + # With Disabled, you do not need to attend festivals + # With Easy, there are checks for participating in festivals + # With Hard, the festival checks are only granted when the player performs well in the festival + disabled: 0 + easy: 50 + hard: 0 + + elevator_progression: + # How is Elevator progression handled? + # Vanilla: You will unlock new elevator floors for yourself. + # Progressive: You will randomly find Progressive Mine Elevators to go deeper. Locations are sent for reaching + # every elevator level. + # Progressive from previous floor: Same as progressive, but you must reach elevator floors on your own, + # you cannot use the elevator to check elevator locations + vanilla: 0 + progressive: 0 + progressive_from_previous_floor: 50 + + arcade_machine_locations: + # How are the Arcade Machines handled? + # Disabled: The arcade machines are not included in the Archipelago shuffling. + # Victories: Each Arcade Machine will contain one check on victory + # Victories Easy: The arcade machines are both made considerably easier to be more accessible for the average + # player. + # Full Shuffling: The arcade machines will contain multiple checks each, and different buffs that make the game + # easier are in the item pool. Junimo Kart has one check at the end of each level. + # Journey of the Prairie King has one check after each boss, plus one check for each vendor equipment. + disabled: 50 + victories: 0 + victories_easy: 0 + full_shuffling: 0 + + special_order_locations: + # How are the Special Orders handled? + # Disabled: The special orders are not included in the Archipelago shuffling. + # Board Only: The Special Orders on the board in town are location checks + # Board and Qi: The Special Orders from Qi's walnut room are checks, as well as the board in town + disabled: 0 + board_only: 0 + board_qi: 50 + + help_wanted_locations: 40 + + fishsanity: + # Locations for catching fish? + # None: There are no locations for catching fish + # Legendaries: Each of the 5 legendary fish are checks + # Special: A curated selection of strong fish are checks + # Randomized: A random selection of fish are checks + # All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal + # Exclude Legendaries: Every fish except legendaries + # Exclude Hard Fish: Every fish under difficulty 80 + # Only Easy Fish: Every fish under difficulty 50 + none: 0 + legendaries: 0 + special: 0 + randomized: 0 + all: 50 + exclude_legendaries: 0 + exclude_hard_fish: 0 + only_easy_fish: 0 + + museumsanity: + # Locations for museum donations? + # None: There are no locations for donating artifacts and minerals to the museum + # Milestones: The donation milestones from the vanilla game are checks + # Randomized: A random selection of minerals and artifacts are checks + # All: Every single donation will be a check + none: 0 + milestones: 0 + randomized: 0 + all: 50 + + friendsanity: + # Locations for friendships? + # None: There are no checks for befriending villagers + # Bachelors: Each heart of a bachelor is a check + # Starting NPCs: Each heart for npcs that are immediately available is a check + # All: Every heart with every NPC is a check, including Leo, Kent, Sandy, etc + # All With Marriage: Marriage candidates must also be dated, married, and befriended up to 14 hearts. + none: 0 + bachelors: 0 + starting_npcs: 0 + all: 0 + all_with_marriage: 50 + + friendsanity_heart_size: + # If using friendsanity, how many hearts are received per item, and how many hearts must be earned to send a check + # A higher value will lead to fewer heart items in the item pool, reducing bloat + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 1 + # Maximum value is 8 + 3: 50 + random: 0 + random-low: 0 + random-high: 0 + + movement_buff_number: + # Number of movement speed buffs to the player that exist as items in the pool. + # Each movement speed buff is a +25% multiplier that stacks additively + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 12 + 10: 50 + random: 0 + random-low: 0 + random-high: 0 + + luck_buff_number: + # Number of luck buffs to the player that exist as items in the pool. + # Each luck buff is a bonus to daily luck of 0.025 + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 12 + 10: 50 + random: 0 + random-low: 0 + random-high: 0 + + exclude_ginger_island: + # Exclude Ginger Island? + # This option will forcefully exclude everything related to Ginger Island from the slot. + # If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway + false: 50 + true: 0 + + trap_items: + # When rolling filler items, including resource packs, the game can also roll trap items. + # This setting is for choosing if traps will be in the item pool, and if so, how punishing they will be. + no_traps: 0 + easy: 0 + medium: 0 + hard: 0 + hell: 50 + nightmare: 0 + + multiple_day_sleep_enabled: + # Enable the ability to sleep automatically for multiple days straight? + false: 0 + true: 50 + + multiple_day_sleep_cost: + # How much gold it will cost to use MultiSleep. You will have to pay that amount for each day skipped. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 200 + random: 0 + random-low: 0 + random-high: 0 + free: 50 # equivalent to 0 + cheap: 0 # equivalent to 25 + medium: 0 # equivalent to 50 + expensive: 0 # equivalent to 100 + + experience_multiplier: + # How fast you want to earn skill experience. A lower setting mean less experience. + # A higher setting means more experience. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 800 + random: 0 + random-low: 0 + random-high: 0 + half: 0 # equivalent to 50 + vanilla: 0 # equivalent to 100 + double: 0 # equivalent to 200 + triple: 50 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + friendship_multiplier: + # How fast you want to earn friendship points with villagers. + # A lower setting mean less friendship per action. + # A higher setting means more friendship per action. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 800 + random: 0 + random-low: 0 + random-high: 0 + half: 0 # equivalent to 50 + vanilla: 0 # equivalent to 100 + double: 0 # equivalent to 200 + triple: 50 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + debris_multiplier: + # How much debris will spawn on the player's farm? + # Vanilla: debris spawns normally + # Half: debris will spawn at half the normal rate + # Quarter: debris will spawn at one quarter of the normal rate + # None: No debris will spawn on the farm, ever + # Start Clear: debris will spawn at the normal rate, but the farm will be completely clear when starting the game + vanilla: 0 + half: 50 + quarter: 0 + none: 0 + start_clear: 0 + + quick_start: + # Do you want the quick start package? You will get a few items to help early game automation, + # so you can use the multiple day sleep at its maximum. + false: 0 + true: 50 + + gifting: + # Do you want to enable gifting items to and from other Stardew Valley worlds? + false: 0 + true: 50 + + mods: + # List of mods that will be considered for shuffling. + ["Bigger Backpack", "Tractor Mod", "Luck Skill", "Archaeology", "Cooking Skill", "Binning Skill"] + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 50 + true: 0 diff --git a/disabled yamls/Plandark.yaml b/disabled yamls/Plandark.yaml new file mode 100644 index 000000000000..857783a9e78b --- /dev/null +++ b/disabled yamls/Plandark.yaml @@ -0,0 +1,86 @@ +game: Dark Souls III +name: Plandark +description: 'Generated à la sueur de mon front' +Dark Souls III: + progression_balancing: 50 + accessibility: locations + enable_weapon_locations: 'true' + enable_shield_locations: 'true' + enable_armor_locations: 'true' + enable_ring_locations: 'true' + enable_spell_locations: 'true' + enable_key_locations: 'true' + enable_boss_locations: 'true' + enable_npc_locations: 'false' + enable_misc_locations: 'true' + enable_health_upgrade_locations: 'true' + enable_progressive_locations: 'true' + pool_type: shuffle + auto_equip: 'false' + lock_equip: 'false' + no_weapon_requirements: 'true' + randomize_infusion: 'true' + randomize_infusion_percentage: random-range-50-75 + randomize_weapon_level: all + randomize_weapon_level_percentage: 100 + min_levels_in_5: 3 + max_levels_in_5: 5 + min_levels_in_10: 6 + max_levels_in_10: 10 + late_basin_of_vows: 'true' + late_dlc: 'false' + no_spell_requirements: 'true' + no_equip_load: 'true' + death_link: 'false' + enable_dlc: 'false' + plando_items: + # Gotta Fight in Stardew to Fight in Dark Souls + - items: + Storm Ruler: 1 + locations: + - "Cryptic Note" + force: true + world: true # other world + + # Enjoy the art + - items: + "Cinders of a Lord - Abyss Watcher": true + "Cinders of a Lord - Aldrich": true + "Cinders of a Lord - Lothric Prince": true + "Cinders of a Lord - Yhorm the Giant": true + "Lothric War Banner": true + "Small Envoy Banner": true + "Small Lothric Banner": true + locations: + - "Lupini: Red Eagle" + - "Lupini: Portrait Of A Mermaid" + - "Lupini: Solar Kingdom" + - "Lupini: Clouds" + - "Lupini: 1000 Years From Now" + - "Lupini: Three Trees" + - "Lupini: The Serpent" + count: false + force: true + world: true # other world + + # Enjoy the art + - items: + "Small Doll": 1 + "Basin of Vows": 1 + "Mortician's Ashes": 1 + locations: + - "Egg Festival: Strawberry Seeds" + - "Luau Soup" + - "Collect All Rarecrows" + count: false + force: true + world: true # other world + + # No early travelling merchant for you + - items: + Grand Archives Key: 1 + locations: + - "Mermaid Pearl" + force: true + world: true # other world + diff --git a/disabled yamls/Plandew.yaml b/disabled yamls/Plandew.yaml new file mode 100644 index 000000000000..6f63f74efc0f --- /dev/null +++ b/disabled yamls/Plandew.yaml @@ -0,0 +1,489 @@ +game: Stardew Valley +name: Plandew +description: 'Generated mostly manually' +Stardew Valley: + progression_balancing: 50 + accessibility: locations + goal: community_center + starting_money: random + profit_margin: 200 + bundle_randomization: thematic + bundle_price: normal + entrance_randomization: disabled + season_randomization: randomized + cropsanity: shuffled + backpack_progression: early_progressive + tool_progression: progressive + skill_progression: progressive + building_progression: progressive_early_shipping_bin + festival_locations: hard + elevator_progression: progressive + arcade_machine_locations: full_shuffling + special_order_locations: board_only + help_wanted_locations: 7 + fishsanity: exclude_hard_fish + museumsanity: milestones + friendsanity: starting_npcs + friendsanity_heart_size: 4 + movement_buff_number: 5 + luck_buff_number: 8 + exclude_ginger_island: 'true' + trap_items: hard + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 300 + friendship_multiplier: 400 + debris_multiplier: quarter + quick_start: 'true' + gifting: 'true' + mods: ["Bigger Backpack", "Juna - Roommate NPC", "Ayeisha - The Postal Worker (Custom NPC)", "Socializing Skill", "Binning Skill", "Archaeology"] + death_link: 'false' + start_inventory: + Fall: 1 + plando_items: + # Stay away from my waifu + - items: + "Random Teleport": 2 + locations: + - "Friendsanity: Abigail 4 <3" + - "Friendsanity: Abigail 8 <3" + force: true + world: false # own world + + # Fuck your mining runs + - items: + "Burnt": true + "Frozen": true + "Jinxed": true + "Slimed": true + "Weakness": true + locations: + - "Floor 5 Elevator" + - "Floor 15 Elevator" + - "Floor 25 Elevator" + - "Floor 35 Elevator" + - "Floor 45 Elevator" + - "Floor 55 Elevator" + - "Floor 65 Elevator" + - "Floor 75 Elevator" + - "Floor 85 Elevator" + - "Floor 95 Elevator" + - "Floor 105 Elevator" + - "Floor 115 Elevator" + count: false + force: true + world: false # own world + + # Your reward is: A Gambling Addiction! + - items: + "Club Card": 1 + locations: + - "Floor 120 Elevator" + force: true + world: false # own world + + # Fuck your skull cavern dive + - items: + "Nauseated": 1 + locations: + - "Qi's Challenge" + count: false + force: true + world: false # own world + + # Fighting might be harder with this + - items: + "Shuffle": true + "Nauseated": true + "Darkness": true + locations: + - "Level 1 Combat" + - "Level 2 Combat" + - "Level 3 Combat" + - "Level 4 Combat" + - "Level 5 Combat" + - "Level 6 Combat" + - "Level 7 Combat" + - "Level 8 Combat" + - "Level 9 Combat" + count: false + force: true + world: false # own world + + # Gotta Fight in Dark Souls to Fight in Stardew + - items: + "Galaxy Sword": true + "Galaxy Dagger": true + "Galaxy Hammer": true + locations: + - "PC: Soul of Yhorm the Giant" + count: 1 + force: true + world: true # other world + + # Go home and no grow + - items: + "Drought": true + locations: + - "Egg Hunt Victory" + - "Dance with someone" + - "Dance of the Moonlight Jellies" + - "Smashing Stone" + - "Spirit's Eve Maze" + - "Win Fishing Competition" + - "The Legend of the Winter Star" + count: false + force: true + world: false # own world + + # Cleaning your farm will get you stabbed and make it dirty again + - items: + "Monsters": true + "Debris": true + locations: + - "Level 1 Foraging" + - "Level 2 Foraging" + - "Level 3 Foraging" + - "Level 4 Foraging" + - "Level 5 Foraging" + count: false + force: true + world: false # own world + + # Reverse friendship + - items: + "Pariah": true + locations: + - "How To Win Friends" + - "Secret Santa" + count: false + force: true + world: false # own world + + # Fuck your other crops when harvesting something + - items: + "The Crows": true + locations: + - "Getting Started" + - "Harvest Amaranth" + - "Harvest Artichoke" + - "Harvest Beet" + - "Harvest Blue Jazz" + - "Harvest Blueberry" + - "Harvest Bok Choy" + - "Harvest Cauliflower" + - "Harvest Corn" + - "Harvest Cranberries" + - "Harvest Eggplant" + - "Harvest Fairy Rose" + - "Harvest Garlic" + - "Harvest Grape" + - "Harvest Green Bean" + - "Harvest Hops" + - "Harvest Hot Pepper" + - "Harvest Kale" + - "Harvest Melon" + - "Harvest Parsnip" + - "Harvest Poppy" + - "Harvest Potato" + - "Harvest Pumpkin" + - "Harvest Radish" + - "Harvest Rhubarb" + - "Harvest Starfruit" + - "Harvest Strawberry" + - "Harvest Summer Spangle" + - "Harvest Sunflower" + - "Harvest Tomato" + - "Harvest Tulip" + - "Harvest Unmilled Rice" + - "Harvest Wheat" + - "Harvest Yam" + - "Harvest Cactus Fruit" + - "Harvest Pineapple" + - "Harvest Taro Root" + - "Harvest Sweet Gem Berry" + - "Harvest Apple" + - "Harvest Apricot" + - "Harvest Cherry" + - "Harvest Orange" + - "Harvest Pomegranate" + - "Harvest Peach" + - "Harvest Banana" + - "Harvest Mango" + - "Harvest Coffee Bean" + count: false + force: true + world: false # own world + + # No Early Traveling Merchant for you + - items: + "Traveling Merchant: Sunday": 1 + locations: + - "GA: Crystal Scroll" + count: false + force: true + world: true # other world + + # No Traveling Merchant for you + - items: + "Traveling Merchant: Monday": 1 + locations: + - "Traveling Merchant Sunday Item 1" + count: false + force: true + world: false # own world + + # No Traveling Merchant for you + - items: + "Traveling Merchant: Tuesday": 1 + locations: + - "Traveling Merchant Monday Item 1" + count: false + force: true + world: false # own world + + # No Traveling Merchant for you + - items: + "Traveling Merchant: Wednesday": 1 + locations: + - "Traveling Merchant Tuesday Item 1" + count: false + force: true + world: false # own world + + # No Traveling Merchant for you + - items: + "Traveling Merchant: Thursday": 1 + locations: + - "Traveling Merchant Wednesday Item 1" + count: false + force: true + world: false # own world + + # No Traveling Merchant for you + - items: + "Traveling Merchant: Friday": 1 + locations: + - "Traveling Merchant Thursday Item 1" + count: false + force: true + world: false # own world + + # No Traveling Merchant for you + - items: + "Traveling Merchant: Saturday": 1 + locations: + - "Traveling Merchant Friday Item 1" + count: false + force: true + world: false # own world + + # These two seasons will be well hidden + - items: + "Spring": true + "Summer": true + locations: + - "Traveling Merchant Saturday Item 1" + - "Magic Ink" + count: false + force: true + world: false # own world + + # Unlock the hard quests early to bait him into doing them + - items: + "Special Order Board": 1 + locations: + - "Level 1 Farming" + count: false + force: true + world: false # own world + + # Prairie King buffs will be hard-earned + - items: + "JotPK: Progressive Boots": true + "JotPK: Progressive Ammo": true + "JotPK: Increased Drop Rate": true + "JotPK: Progressive Gun": true + locations: + - "Level 10 Fishing" + - "Level 10 Foraging" + - "Level 10 Mining" + - "Level 10 Combat" + - "Level 10 Socializing" + - "Level 10 Binning" + - "Level 10 Archaeology" + - "Friendsanity: Ayeisha 10 <3" + - "Friendsanity: Juna 10 <3" + - "Premium Pack" + count: false + force: true + world: false # own world + + # No Junimo Kart until you win Prairie King + - items: + "Skull Key": 1 + locations: + - "Journey of the Prairie King Victory" + count: false + force: true + world: false # own world + + # The most well-hidden item + - items: + "Winter": 1 + locations: + - "Junimo Kart: Secret Level" + count: false + force: true + world: false # own world + + #Some art is money laundering + - items: + "Taxes": true + locations: + - "Lupini: Land Of Clay" + - "Lupini: 'Tropical Fish #173'" + count: false + force: true + world: false # own world + + #Greenhouse behind the hardest-to-grow crop + - items: + "Greenhouse": 1 + locations: + - "Harvest Sweet Gem Berry" + count: false + force: true + world: false # own world + + # As soon as you switch seasons, here's a good fall seed + - items: + "Rare Seed": 1 + "Pumpkin Seeds": 1 + "Amaranth Seeds": 1 + locations: + - "Summer Foraging Bundle" + - "Spring Foraging Bundle" + - "Winter Foraging Bundle" + count: false + force: true + world: false # own world + + # Got any grapes? + - items: + "Grape Starter": 1 + locations: + - "Big Coop Blueprint" + count: false + force: true + world: false # own world + + # The two ways to make babies + - items: + "Ugly Baby": true + "Cute Baby": true + locations: + - "Mayor's \"Shorts\"" + - "Harvest Red Cabbage" + count: false + force: true + world: false # own world + + # tough to get backpacks + - items: + "Progressive Backpack": 2 + locations: + - "Have Another Baby" + - "Strange Note" + count: false + force: true + world: false # own world + + # tough to get backpacks + - items: + "Rusty Key": 1 + locations: + - "Have a Baby" + count: false + force: true + world: false # own world + + # Try to hide this obelisk a little bit + - items: + "Desert Obelisk": 1 + locations: + - "Dark Talisman" + count: false + force: true + world: false # own world + + # Kids are dwarves + - items: + "Dwarvish Translation Guide": 1 + locations: + - "Friendsanity: Vincent 10 <3" + - "Friendsanity: Jas 10 <3" + count: false + force: true + world: false # own world + + # They're hoeing around + - items: + "Progressive Hoe": 4 + locations: + - "Friendsanity: Caroline 4 <3" + - "Friendsanity: Caroline 8 <3" + - "Friendsanity: Haley 4 <3" + - "Friendsanity: Haley 8 <3" + count: false + force: true + world: false # own world + + # They're hoeing around + - items: + "Progressive Trash Can": 4 + locations: + - "Friendsanity: Pierre 4 <3" + - "Friendsanity: Pierre 8 <3" + - "Friendsanity: Demetrius 4 <3" + - "Friendsanity: Demetrius 8 <3" + count: false + force: true + world: false # own world + + # Self Explanatory + - items: + "Penny <3": 1 + locations: + - "Copper Hoe Upgrade" + count: false + force: true + world: false # own world + + # Self Explanatory + - items: + "Maru <3": 1 + locations: + - "Iron Hoe Upgrade" + count: false + force: true + world: false # own world + + # Self Explanatory + - items: + "Haley <3": 1 + locations: + - "Gold Hoe Upgrade" + count: false + force: true + world: false # own world + + # Self Explanatory + - items: + "Abigail <3": 1 + locations: + - "Iridium Hoe Upgrade" + count: false + force: true + world: false # own world + diff --git a/disabled yamls/Plandow.yaml b/disabled yamls/Plandow.yaml new file mode 100644 index 000000000000..800a42ff5965 --- /dev/null +++ b/disabled yamls/Plandow.yaml @@ -0,0 +1,87 @@ +description: 'Generated by https://archipelago.gg/ for Hollow Knight' +game: Hollow Knight +name: Missing_DLL +Hollow Knight: + progression_balancing: disabled + accessibility: locations + RandomizeDreamers: 'true' + RandomizeSkills: 'true' + RandomizeFocus: 'true' + RandomizeSwim: 'true' + RandomizeCharms: 'true' + RandomizeKeys: 'true' + RandomizeMaskShards: 'true' + RandomizeVesselFragments: 'true' + RandomizeCharmNotches: 'true' + RandomizePaleOre: 'true' + RandomizeGeoChests: 'true' + RandomizeJunkPitChests: 'true' + RandomizeRancidEggs: 'true' + RandomizeRelics: 'true' + RandomizeWhisperingRoots: 'true' + RandomizeBossEssence: 'true' + RandomizeGrubs: 'true' + RandomizeMimics: 'true' + RandomizeMaps: 'true' + RandomizeStags: 'true' + RandomizeLifebloodCocoons: 'true' + RandomizeGrimmkinFlames: 'true' + RandomizeJournalEntries: 'true' + RandomizeNail: 'true' + RandomizeGeoRocks: 'true' + RandomizeBossGeo: 'true' + RandomizeSoulTotems: 'true' + RandomizeLoreTablets: 'true' + RandomizeElevatorPass: 'true' + PreciseMovement: 'true' + ProficientCombat: 'true' + BackgroundObjectPogos: 'true' + EnemyPogos: 'true' + ObscureSkips: 'false' + ShadeSkips: 'true' + InfectionSkips: 'false' + FireballSkips: 'false' + SpikeTunnels: 'false' + AcidSkips: 'true' + DamageBoosts: 'true' + DangerousSkips: 'true' + DarkRooms: 'true' + ComplexSkips: 'false' + DifficultSkips: 'false' + RemoveSpellUpgrades: 'false' + StartLocation: king's_pass + Goal: radiance + WhitePalace: include + StartingGeo: random + DeathLink: off + MinimumGeoPrice: random + MaximumGeoPrice: random + MinimumGrubPrice: random + MaximumGrubPrice: random + MinimumEssencePrice: random + MaximumEssencePrice: random + MinimumCharmPrice: random + MaximumCharmPrice: random + RandomCharmCosts: -2 + MinimumEggPrice: random + MaximumEggPrice: random + EggShopSlots: 7 + SlyShopSlots: 5 + SlyKeyShopSlots: 7 + IseldaShopSlots: 5 + SalubraShopSlots: 6 + SalubraCharmShopSlots: 5 + LegEaterShopSlots: 5 + GrubfatherRewardSlots: 7 + SeerRewardSlots: 5 + ExtraShopSlots: random + SplitCrystalHeart: 'true' + SplitMothwingCloak: 'true' + SplitMantisClaw: 'true' + CostSanity: on + CostSanityHybridChance: 2 + CostSanityEggWeight: 1 + CostSanityGrubWeight: 10 + CostSanityEssenceWeight: 10 + CostSanityCharmWeight: 10 + CostSanityGeoWeight: 8 \ No newline at end of file diff --git a/disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml b/disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml new file mode 100644 index 000000000000..2e1094560bf6 --- /dev/null +++ b/disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml @@ -0,0 +1,670 @@ +############################################################################################################# +# # +# ▄████▄ â–„â–„â–„ ██▓▄▄▄█████▓ ██████ ██▓▄▄▄█████▓ ██░ ██ ▄▄▄█████▓ â–ˆ █░ ▒█████ # +# ▒██▀ ▀█ ▒████▄ ▓██▒▓ ██▒ ▓▒▒██ â–’ ▓██▒▓ ██▒ ▓▒▓██░ ██▒ â–“ ██▒ ▓▒▓█░ â–ˆ ░█░▒██▒ ██▒ # +# â–’â–“â–ˆ â–„ ▒██ ▀█▄ ▒██▒▒ ▓██░ â–’â–‘â–‘ ▓██▄ ▒██▒▒ ▓██░ ▒░▒██▀▀██░ â–’ ▓██░ ▒░▒█░ â–ˆ â–‘â–ˆ ▒██░ ██▒ # +# â–’â–“â–“â–„ ▄██▒░██▄▄▄▄██ ░██░░ ▓██▓ â–‘ â–’ ██▒░██░░ ▓██▓ â–‘ â–‘â–“â–ˆ ░██ â–‘ ▓██▓ â–‘ ░█░ â–ˆ â–‘â–ˆ ▒██ ██░ # +# â–’ ▓███▀ â–‘ â–“â–ˆ ▓██▒░██░ ▒██▒ â–‘ ▒██████▒▒░██░ ▒██▒ â–‘ ░▓█▒░██▓ ▒██▒ â–‘ ░░██▒██▓ â–‘ ████▓▒░ # +# â–‘ â–‘â–’ â–’ â–‘ â–’â–’ ▓▒█░░▓ â–’ â–‘â–‘ â–’ â–’â–“â–’ â–’ â–‘â–‘â–“ â–’ â–‘â–‘ â–’ â–‘â–‘â–’â–‘â–’ â–’ â–‘â–‘ â–‘ â–“â–‘â–’ â–’ â–‘ â–’â–‘â–’â–‘â–’â–‘ # +# â–‘ â–’ â–’ â–’â–’ â–‘ â–’ â–‘ â–‘ â–‘ â–‘â–’ â–‘ â–‘ â–’ â–‘ â–‘ â–’ â–‘â–’â–‘ â–‘ â–‘ â–’ â–‘ â–‘ â–‘ â–’ â–’â–‘ # +# â–‘ â–‘ â–’ â–’ â–‘ â–‘ â–‘ â–‘ â–‘ â–’ â–‘ â–‘ â–‘ â–‘â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–’ # +# â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ # +# â–‘ # +# # +# @ # +# @@@@@ ,@@@@@@ # +# @@@@&@@@ ,@@@&@@@@ # +# %@@@@&&@@@ @@@&&&@@@& # +# @@@@&&&@@@ ,@@@&&&@@@@ # +# @@@@&&&&&@@@ @@@&&&&&@@@@ # +# @@@@&&%&&@@@ @@@@@@@@@@@@@@@@@@@@@& @@@@&&%&&&@@@ # +# @@@@&&%%&&&@@@ @@@@@@@@@@################%@@@@@@@@% @@@&&&%&&&@@@@ # +# @@@@&&&%%&&@@@/ (@@@@@@################################&@@@@@@ @@@&&&%%&&&@@@@ # +# @@@&&&&%%&&&@@@,@@@@@@#########################################%@@@@@ @@@&&&&%&&&&&@@@ # +# @@@&&&&&%%&&&&@@@@@@@################################################&@@@@@@@&&&&%&&&&&&@@@ # +# @@@&&&&&&%&&&&&@@@@@&#####################################################%@/.,&&&&&%&&&&&&&@@% # +# @@@&&&&&&&&&&&&&@@@###########################################################@#../&&&&&&&&&&&@@. # +# @@@&&&&&%%%&&&&&&@######* #####################################################@#...@%&&&&&&@@@ # +# @@@&&&&&&&&&&&&&#########* /###################. (####################@##@%*#@@#(#&@/.../@@&@@@ # +# @@&&&&&&&&&&&###########. ,###############/ ,##################@@@@**/**/@##&..%@&@/.....*@ # +# @@@&&&&&&&&%####. ,/###(/, #* .(####@@#****@###&&@/...,//.., # +# (@@@&&&&&#####* ######&@#####&&&&@@@..*, # +# @@@&&&######. /@@@@@@@@@@@@@/ &@@@@@@@@@@@@% (##########&@@@@@, # +# @@@&######. ,@@@@@%%%%%%%%%&@@@@@ /@@@@@%%%%%%%%%@@@@@& .########&@@@.@.@ # +# @@@#######( %%((%%%&&%%%%%%# @@% @@#.%%%%%%&&&%%#(#%, ########@@@. /@ # +# @@@@######( #(((&&&&&&%%% @ */ *%%%&&&&&(((#. #######@@@@ # +# @@@@###### ((/((#/%%/((((* ((((##%#/#(((( ######@@@@ # +# @@@@##### /((((((((((. ((((((((((( #####&@@@@ # +# @@@@@#### .#####@@@@ # +# @@@@&###. /@ .@#@& ,@ #####@@@@@ # +# @@@@@###. (((((% #####@@@@@ # +# @@@@@#### (%&. #####%@@@@ # +# %@@@@@%### .#####@@@@@ # +# @@@@@@@####(. .####%@@@@@@ # +# @@@@@@@@@&#################/*.... ....,/########%@@@@@@@@@ # +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # +# # +############################################################################################################# + +description: CaitSith2's ALttP YAML 1 of 1 +name: +# CaitSith {NUMBER}: 1 +# Yunica Tovah {NUMBER}: 1 +# Adol Christin {NUMBER}: 1 + Untitled Goose {NUMBER}: 1 +# Boco {NUMBER}: 1 +# Popoi {NUMBER}: 1 +game: + A Link to the Past: 1 +requires: + version: 0.2.3 + plando: bosses +# Shared Options supported by all games: +accessibility: + items: 0 + locations: 50 + none: 0 +progression_balancing: 50 +A Link to the Past: + start_hints: + - Swords + - Lamp + start_location_hints: + - 'Take-Any #1' + - 'Take-Any #2' + - 'Take-Any #3' + - 'Take-Any #4' + - 'Old Man Sword Cave' + start_inventory: + Rupees (300): 33 + Bombs (10): 1 + Arrows (10): 3 + Pegasus Boots: 1 + glitches_required: + none: 50 + minor_glitches: 0 + overworld_glitches: 0 + hybrid_major_glitches: 0 + no_logic: 0 + dark_room_logic: + lamp: 0 + torches: 1 + none: 0 + restrict_dungeon_item_on_boss: + on: 0 + off: 50 + bigkey_shuffle: + original_dungeon: 0 + own_dungeons: 1 + own_world: 0 + any_world: 0 + different_world: 0 + start_with: 0 + smallkey_shuffle: + original_dungeon: 0 + own_dungeons: 1 + own_world: 0 + any_world: 0 + different_world: 0 + universal: 0 + start_with: 0 + compass_shuffle: + original_dungeon: 0 + own_dungeons: 0 + own_world: 0 + any_world: 0 + different_world: 0 + start_with: 1 + map_shuffle: + original_dungeon: 0 + own_dungeons: 0 + own_world: 0 + any_world: 1 + different_world: 0 + start_with: 0 + key_drop_shuffle: + on: 1 + off: 0 + dungeon_counters: + on: 50 + pickup: 0 + default: 0 + off: 0 + progressive: + on: 50 + off: 0 + grouped_random: 0 + local_items: + - Swords + - Moon Pearl + - Lamp + - Bottles + - Flute + - Magic Mirror + - Gloves + - Hammer + - Hookshot + - Flippers + - Magic Powder + - Cane of Somaria + - Bombos + - Fire Rod + - Ice Rod + - Book of Mudora + - Shovel + - Mushroom + entrance_shuffle: + none: 0 + dungeonssimple: 0 + dungeonsfull: 0 + dungeonscrossed: 0 + dungeonscrossed-1000: 1 + simple: 0 + restricted: 0 + full: 0 + crossed: 0 + insanity: 0 + crossed-1000: 0 + crossed-group-myfriends: 0 + goals: + ganon: 0 + crystals: 0 + bosses: 1 + pedestal: 0 + ganon_pedestal: 0 + triforce_hunt: 0 + local_triforce_hunt: 0 + ganon_triforce_hunt: 0 + local_ganon_triforce_hunt: 0 + ice_rod_hunt: 0 + open_pyramid: + goal: 50 + auto: 0 + yes: 0 + no: 0 + triforce_pieces_mode: + extra: 0 + percentage: 0 + available: 50 + triforce_pieces_extra: + 0: 0 + 5: 50 + 10: 50 + 15: 0 + 20: 0 + triforce_pieces_percentage: + 100: 0 + 150: 50 + 200: 0 + triforce_pieces_available: + 25: 0 + 30: 0 + 40: 1 + 60: 0 + triforce_pieces_required: + 15: 0 + 20: 0 + 30: 1 + 40: 0 + 60: 0 + crystals_needed_for_gt: + 0: 50 + 7: 0 + random: 0 + random-low: 0 + random-middle: 0 + random-high: 0 + crystals_needed_for_ganon: + 0: 0 + 3: 0 + 4: 0 + 5: 50 + 6: 50 + 7: 50 + random: 0 + random-low: 0 + random-middle: 0 + random-high: 0 + mode: + standard: 0 + open: 50 + inverted: 0 + retro_bow: + on: 0 + off: 50 + retro_caves: + on: 1 + off: 0 + hints: + 'on': 1 + 'off': 0 + full: 0 + scams: + 'off': 1 + 'king_zora': 0 + 'bottle_merchant': 0 + 'all': 0 + swordless: + on: 0 + off: 1 + item_pool: + easy: 1 + normal: 0 + hard: 0 + expert: 0 + item_functionality: + easy: 50 + normal: 0 + hard: 0 + expert: 0 + tile_shuffle: + on: 50 + off: 0 + misery_mire_medallion: + random: 0 + Ether: 0 + Bombos: 1 + Quake: 0 + turtle_rock_medallion: + random: 0 + Ether: 0 + Bombos: 1 + Quake: 0 + boss_shuffle: + none: 0 + basic: 0 + full: 0 + chaos: 0 + + #I have no desire to fight Trinexx on Ice. The boss that is able to go into all locations is being placed there instead. + Ganons Tower Bottom-Kholdstare;Trinexx;Kholdstare: 1 + Ganons Tower Bottom-Moldorm;Trinexx;Moldorm: 1 + Ganons Tower Bottom-Mothula;Trinexx;Mothula: 1 + Ganons Tower Bottom-Helmasaur King;Trinexx;Helmasaur King: 1 + Ganons Tower Bottom-Vitreous;Trinexx;Vitreous: 1 + #And the rest of the singularity combinations the exclude trinexx entirely. + Armos Knights;Moldorm: 1 + Armos Knights;Helmasaur King: 0 + Armos Knights;Mothula: 1 + Armos Knights;Vitreous: 1 + Armos Knights;Kholdstare: 1 + Lanmolas;Moldorm: 1 + Lanmolas;Helmasaur King: 1 + Lanmolas;Mothula: 1 + Lanmolas;Vitreous: 1 + Lanmolas;Kholdstare: 1 + Arrghus;Moldorm: 1 + Arrghus;Helmasaur King: 1 + Arrghus;Mothula: 1 + Arrghus;Vitreous: 1 + Arrghus;Kholdstare: 1 + Blind;Moldorm: 1 + Blind;Helmasaur King: 1 + Blind;Mothula: 1 + Blind;Vitreous: 1 + Blind;Kholdstare: 1 + Moldorm: 1 + Helmasaur King: 1 + Mothula: 1 + Vitreous: 1 + Kholdstare: 1 + enemy_shuffle: + on: 0 + off: 50 + killable_thieves: + on: 1 + off: 0 + bush_shuffle: + on: 0 + off: 50 + enemy_damage: + default: 50 + shuffled: 0 + chaos: 0 + enemy_health: + default: 50 + easy: 0 + hard: 0 + expert: 0 + pot_shuffle: + 'on': 0 + 'off': 50 + beemizer_total_chance: + 0: 100 + 25: 0 + 50: 0 + 75: 0 + 100: 0 + beemizer_trap_chance: + 0: 100 + 60: 0 + 70: 0 + 80: 0 + 90: 0 + 100: 0 + shop_item_slots: + 0: 1 + 5: 0 + 15: 0 + 30: 0 + random: 0 + shop_price_modifier: + 0: 0 + 400: 0 + random: 0 + random-low: 0 + random-high: 0 + 100: 50 + shop_shuffle: + none: 0 + uw: 50 + g: 0 + f: 0 + i: 0 + p: 0 + w: 0 + ip: 0 + fpu: 0 + uip: 0 + shuffle_prizes: + none: 0 + g: 50 + b: 0 + bg: 0 + timer: + none: 50 + timed: 0 + timed_ohko: 0 + ohko: 0 + timed_countdown: 0 + display: 0 + countdown_start_time: + 0: 0 + 10: 50 + 20: 0 + 30: 0 + 60: 0 + red_clock_time: + -2: 50 + 1: 0 + blue_clock_time: + 1: 0 + 2: 50 + green_clock_time: + 4: 50 + 10: 0 + 15: 0 + glitch_boots: + on: 50 + off: 0 + random_sprite_on_event: + enabled: + on: 1 + off: 0 + on_hit: + on: 1 + off: 0 + on_enter: + on: 1 + off: 1 + on_exit: + on: 1 + off: 1 + on_slash: + on: 1 + off: 1 + on_item: + on: 1 + off: 1 + on_bonk: + on: 1 + off: 1 + on_everything: + on: 0 + off: 1 + use_weighted_sprite_pool: + on: 1 + off: 0 + sprite: + goose: 1 + boco: 1 + yunica tovah: 1 + adol: 1 + popoi: 1 + music: + on: 50 + off: 0 + quickswap: + on: 50 + off: 0 + triforcehud: + normal: 0 + hide_goal: 0 + hide_required: 0 + hide_both: 1 + reduceflashing: + on: 50 + off: 0 + menuspeed: + normal: 0 + instant: 0 + double: 0 + triple: 0 + quadruple: 1 + half: 0 + heartcolor: + red: 0 + blue: 1 + green: 0 + yellow: 0 + random: 0 + heartbeep: + double: 0 + normal: 0 + half: 0 + quarter: 1 + off: 0 + ow_palettes: + default: 50 + good: 0 + blackout: 0 + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + uw_palettes: + default: 50 + good: 0 + blackout: 0 + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + hud_palettes: + default: 50 + good: 0 + blackout: 0 + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + sword_palettes: + default: 50 + good: 0 + blackout: 0 + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + shield_palettes: + default: 50 + good: 0 + blackout: 0 + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + legacy_weapons: + trigger_disabled: 50 + randomized: 0 + assured: 0 + vanilla: 0 + swordless: 0 + death_link: + false: 50 + true: 0 + allow_collect: + false: 0 + true: 1 +linked_options: + - name: crosskeys + options: + A Link to the Past: + entrance_shuffle: crossed + bigkey_shuffle: true + compass_shuffle: true + map_shuffle: true + smallkey_shuffle: true + percentage: 0 + - name: localcrosskeys + options: + A Link to the Past: + entrance_shuffle: crossed + bigkey_shuffle: true + compass_shuffle: true + map_shuffle: true + smallkey_shuffle: true + local_items: + - "Small Keys" + - "Big Keys" + percentage: 0 + - name: enemizer + options: + A Link to the Past: + boss_shuffle: + basic: 1 + full: 1 + chaos: 1 + singularity: 1 + enemy_damage: + shuffled: 1 + chaos: 1 + enemy_health: + easy: 1 + hard: 1 + expert: 1 + percentage: 0 +triggers: + - option_name: legacy_weapons + option_result: randomized + option_category: A Link to the Past + options: + A Link to the Past: + swordless: off + - option_name: legacy_weapons + option_result: assured + option_category: A Link to the Past + options: + A Link to the Past: + swordless: off + start_inventory: + Progressive Sword: 1 + - option_name: legacy_weapons + option_result: vanilla + option_category: A Link to the Past + options: + A Link to the Past: + swordless: off + plando_items: + - items: + Progressive Sword: 4 + locations: + - Master Sword Pedestal + - Pyramid Fairy - Left + - Blacksmith + - Link's Uncle + - items: + Moon Pearl: 1 + Lamp: 1 + locations: + - early_locations + - option_name: legacy_weapons + option_result: swordless + option_category: A Link to the Past + options: + A Link to the Past: + swordless: on + - option_name: enemy_damage + option_category: A Link to the Past + option_result: shuffled + percentage: 0 + options: + A Link to the Past: + swordless: off + - option_name: name + option_result: Yunica Tovah {NUMBER} + option_category: null + options: + A Link to the Past: + sprite: + goose: 1 + boco: 1 + yunica tovah: 28 + adol: 1 + popoi: 1 + - option_name: name + option_result: Adol Christin {NUMBER} + option_category: null + options: + A Link to the Past: + sprite: + goose: 1 + boco: 1 + yunica tovah: 1 + adol: 28 + popoi: 1 + - option_name: name + option_result: Untitled Goose {NUMBER} + option_category: null + options: + A Link to the Past: + sprite: + goose: 28 + boco: 1 + yunica tovah: 1 + adol: 1 + popoi: 1 + - option_name: name + option_result: Boco {NUMBER} + option_category: null + options: + A Link to the Past: + sprite: + goose: 1 + boco: 28 + yunica tovah: 1 + adol: 1 + popoi: 1 + - option_name: name + option_result: Popoi {NUMBER} + option_category: null + options: + A Link to the Past: + sprite: + goose: 1 + boco: 1 + yunica tovah: 1 + adol: 1 + popoi: 28 + diff --git a/disabled yamls/RC1/DOOMBeta.yaml b/disabled yamls/RC1/DOOMBeta.yaml new file mode 100644 index 000000000000..f7414131bc18 --- /dev/null +++ b/disabled yamls/RC1/DOOMBeta.yaml @@ -0,0 +1,164 @@ +# Q. What is this file? +# A. This file contains options which allow you to configure your multiworld experience while allowing +# others to play how they want as well. +# +# Q. How do I use it? +# A. The options in this file are weighted. This means the higher number you assign to a value, the +# more chances you have for that option to be chosen. For example, an option like this: +# +# map_shuffle: +# on: 5 +# off: 15 +# +# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned +# off. +# +# Q. I've never seen a file like this before. What characters am I allowed to use? +# A. This is a .yaml file. You are allowed to use most characters. +# To test if your yaml is valid or not, you can use this website: +# http://www.yamllint.com/ +# You can also verify your Archipelago settings are valid at this site: +# https://archipelago.gg/check + +# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. +# {player} will be replaced with the player's slot number. +# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. +# {number} will be replaced with the counter value of the name. +# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. +name: ForsakenDoom + +# Used to describe your yaml. Useful if you have multiple files. +description: Default DOOM 1993 Template + +game: DOOM 1993 +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +DOOM 1993: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 50 # equivalent to 50 + extreme: 0 # equivalent to 99 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + {} + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + difficulty: + # Choose the difficulty option. Those match DOOM's difficulty options. + # baby (I'm too young to die.) double ammos, half damage, less monsters or strength. + # easy (Hey, not too rough.) less monsters or strength. + # medium (Hurt me plenty.) Default. + # hard (Ultra-Violence.) More monsters or strength. + # nightmare (Nightmare!) Monsters attack more rapidly and respawn. + baby: 0 + easy: 50 + medium: 0 + hard: 0 + nightmare: 0 + + random_monsters: + # Choose how monsters are randomized. + # vanilla: No randomization + # shuffle: Monsters are shuffled within the level + # random_balanced: Monsters are completely randomized, but balanced based on existing ratio in the level. (Small monsters vs medium vs big) + vanilla: 50 + shuffle: 0 + random_balanced: 0 + + random_pickups: + # Choose how pickups are randomized. + # vanilla: No randomization + # shuffle: Pickups are shuffled within the level + # random_balanced: Pickups are completely randomized, but balanced based on existing ratio in the level. (Small pickups vs Big) + vanilla: 0 + shuffle: 50 + random_balanced: 0 + + allow_death_logic: + # Some locations require a timed puzzle that can only be tried once. + # After which, if the player failed to get it, the location cannot be checked anymore. + # By default, no progression items are placed here. There is a way, hovewer, to still get them: + # Get killed in the current map. The map will reset, you can now attempt the puzzle again. + false: 0 + true: 50 + + start_with_computer_area_maps: + # Give the player all Computer Area Map items from the start. + false: 0 + true: 50 + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 0 + true: 50 + + episode1: + # Knee-Deep in the Dead. + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 0 + true: 50 + + episode2: + # The Shores of Hell. + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 0 + true: 50 + + episode3: + # Inferno. + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 50 + true: 0 + + episode4: + # Thy Flesh Consumed. + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 50 + true: 0 diff --git a/disabled yamls/RC1/Dragus_DOOM_world.yaml b/disabled yamls/RC1/Dragus_DOOM_world.yaml new file mode 100644 index 000000000000..566b0b49c36c --- /dev/null +++ b/disabled yamls/RC1/Dragus_DOOM_world.yaml @@ -0,0 +1,53 @@ +DOOM 1993: + progression_balancing: 50 + accessibility: items + difficulty: medium + random_monsters: shuffle + random_pickups: shuffle + allow_death_logic: 'false' + start_with_computer_area_maps: 'false' + death_link: 'false' + episode1: 'false' + episode2: 'false' + episode3: 'true' + episode4: 'false' +description: 'Generated by https://archipelago.gg/ for DOOM 1993' +game: DOOM 1993 +name: Dragus DOOM + + +--- + +Super Mario World: + progression_balancing: 50 + accessibility: items + death_link: 'false' + goal: yoshi_egg_hunt + bosses_required: 7 + number_of_yoshi_eggs: 50 + percentage_of_yoshi_eggs: 70 + dragon_coin_checks: 'false' + bowser_castle_doors: fast + bowser_castle_rooms: random_two_room + level_shuffle: 'true' + exclude_special_zone: 'false' + boss_shuffle: full + swap_donut_gh_exits: 'false' + display_received_item_popups: progression + trap_fill_percentage: 0 + ice_trap_weight: medium + stun_trap_weight: medium + literature_trap_weight: medium + timer_trap_weight: medium + autosave: 'true' + early_climb: 'false' + overworld_speed: fast + music_shuffle: none + mario_palette: waluigi + foreground_palette_shuffle: 'true' + background_palette_shuffle: 'true' + overworld_palette_shuffle: 'true' + starting_life_count: random +description: 'Generated by https://archipelago.gg/ for Super Mario World' +game: Super Mario World +name: DragusSMW diff --git a/disabled yamls/RC1/Fatman_Main.yaml b/disabled yamls/RC1/Fatman_Main.yaml new file mode 100644 index 000000000000..acceef167494 --- /dev/null +++ b/disabled yamls/RC1/Fatman_Main.yaml @@ -0,0 +1,444 @@ +description: 'Me waiting for Silksong in AP (Its coming out this week I swear) :I' +name: Fatman +game: + Hollow Knight: 1 + Minecraft: 0 + Rogue Legacy: 0 + Super Mario 64: 0 + Factorio: 0 + Subnautica: 0 + Timespinner: 0 + The Witness: 0 +Hollow Knight: + RandomizeDreamers: + 'true': 25 + RandomizeSkills: + 'true': 25 + RandomizeFocus: + 'true': 25 + RandomizeSwim: + 'true': 25 + RandomizeElevatorPass: + 'true': 25 + RandomizeCharms: + 'true': 25 + RandomizeKeys: + 'true': 25 + RandomizeMaskShards: + 'true': 25 + RandomizeVesselFragments: + 'true': 25 + RandomizeCharmNotches: + 'true': 25 + RandomizePaleOre: + 'true': 25 + RandomizeGeoChests: + 'true': 25 + RandomizeJunkPitChests: + 'true': 25 + RandomizeRancidEggs: + 'true': 25 + RandomizeRelics: + 'true': 25 + RandomizeWhisperingRoots: + 'true': 25 + RandomizeBossEssence: + 'true': 25 + RandomizeGrubs: + 'true': 25 + RandomizeMimics: + 'true': 25 + RandomizeMaps: + 'true': 25 + RandomizeStags: + 'true': 25 + RandomizeLifebloodCocoons: + 'true': 25 + RandomizeGrimmkinFlames: + 'false': 25 + RandomizeJournalEntries: + 'true': 25 + RandomizeNail: + 'true': 25 + RandomizeGeoRocks: + 'false': 25 + RandomizeBossGeo: + 'true': 25 + RandomizeSoulTotems: + 'false': 25 + RandomizeLoreTablets: + 'false': 25 + PreciseMovement: + 'true': 25 + ProficientCombat: + 'true': 25 + BackgroundObjectPogos: + 'true': 25 + EnemyPogos: + 'true': 25 + ObscureSkips: + 'false': 25 + ShadeSkips: + 'false': 25 + InfectionSkips: + 'false': 25 + FireballSkips: + 'false': 25 + SpikeTunnels: + 'false': 25 + AcidSkips: + 'false': 25 + DamageBoosts: + 'false': 25 + DangerousSkips: + 'false': 25 + DarkRooms: + 'false': 25 + ComplexSkips: + 'false': 25 + DifficultSkips: + 'false': 25 + RemoveSpellUpgrades: + 'false': 25 + SplitCrystalHeart: + 'true': 25 + SplitMothwingCloak: + 'true': 25 + SplitMantisClaw: + 'true': 25 + StartLocation: + king's_pass: 25 + MinimumGrubPrice: + 5: 25 + MaximumGrubPrice: + 25: 25 + MinimumEssencePrice: + 400: 25 + MaximumEssencePrice: + 1600: 25 + MinimumEggPrice: + 3: 25 + MaximumEggPrice: + 10: 25 + MinimumCharmPrice: + 3: 25 + MaximumCharmPrice: + 20: 25 + MinimumGeoPrice: + 15: 1 + MaximumGeoPrice: + random-range-middle-200-750: 1 + RandomCharmCosts: + random-range-middle-60-110 + EggShopSlots: + random-range-middle-4-8 + SlyShopSlots: + random-range-middle-4-8 + SlyKeyShopSlots: + random-range-middle-6-10 + IseldaShopSlots: + random-range-middle-3-7 + SalubraShopSlots: + random-high: 1 + SalubraCharmShopSlots: + 1: 1 + LegEaterShopSlots: + random-range-middle-3-7: 1 + GrubfatherRewardSlots: + random-range-middle-3-10: 1 + SeerRewardSlots: + random: 1 + Goal: + radiance: 2 + hollowknight: 0 + WhitePalace: + include: 2 + kingfragment: 2 + DeathLink: + shade: 0 + off: 1 + progression_balancing: + 0: 1 + CostSanity: + true: 1 + CostSanityHybridChance: + random-range-low-3-20: 1 + CostSanityEggWeight: + random-range-low-15-30: 1 + CostSanityGrubWeight: + random-range-middle-35-65: 1 + CostSanityEssenceWeight: + random-range-middle-35-65: 1 + CostSanityCharmWeight: + random-range-low-15-30: 1 + CostSanityGeoWeight: + random-range-middle-100-160: 1 + accessibility: + items: 25 + priority_locations: [] + StartingGeo: + random-high: 1 + exclude_locations: ["Boss_Essence-Grey_Prince_Zote"] + local_items: ["Void_Heart", "Herrah"] + non_local_items: [] + start_hints: ["Monomon", "Lurien", "Queen_Fragment", "Upslash"] + start_location_hints: [] +Minecraft: + advancement_goal: + random-range-middle-45-55: 20 + egg_shards_required: + random-range-middle-15-20: 25 + egg_shards_available: + 30: 25 + required_bosses: + none: 25 + shuffle_structures: + 'true': 25 + structure_compasses: + 'false': 25 + bee_traps: + 15: 25 + combat_difficulty: + normal: 40 + include_hard_advancements: + 'false': 25 + include_unreasonable_advancements: + 'false': 25 + include_postgame_advancements: + 'false': 25 + send_defeated_mobs: + 'false': 25 + death_link: + 'false': 25 + progression_balancing: + 20: 1 + accessibility: + items: 25 + priority_locations: [] + start_inventory: {} + exclude_locations: + - "Caves & Cliffs" + - "Great View From Up Here" + local_items: [] + non_local_items: [] + start_hints: [] + start_location_hints: [] +Rogue Legacy: + starting_gender: random + starting_class: random + new_game_plus: normal + fairy_chests_per_zone: 5 + chests_per_zone: 18 + universal_fairy_chests: 'true' + universal_chests: 'false' + vendors: random + architect: normal + architect_fee: 70 + disable_charon: 'false' + require_purchasing: 'true' + progressive_blueprints: 'true' + gold_gain_multiplier: normal + number_of_children: 4 + free_diary_on_generation: 'true' + khidr: vanilla + alexander: vanilla + leon: vanilla + herodotus: vanilla + health_pool: 15 + mana_pool: 15 + attack_pool: 15 + magic_damage_pool: 15 + armor_pool: 10 + equip_pool: 10 + crit_chance_pool: 5 + crit_damage_pool: 5 + allow_default_names: 'true' + death_link: 'false' + progression_balancing: 35 + exclude_locations: + - Fairy Chest 7 + - Fairy Chest 8 + - Fairy Chest 9 + - Fairy Chest 10 + - Fairy Chest 11 + - Fairy Chest 12 + - Fairy Chest 13 + - Fairy Chest 14 + - Fairy Chest 15 + - Fairy Chest 16 + - Fairy Chest 17 + - Fairy Chest 18 + - Fairy Chest 19 + - Fairy Chest 20 + accessibility: items +Super Mario 64: + progression_balancing: 25 + accessibility: items + AreaRandomizer: courses_and_secrets + ProgressiveKeys: 'true' + EnableCoinStars: 'false' + AmountOfStars: 120 + StrictCapRequirements: 'true' + StrictCannonRequirements: 'true' + FirstBowserStarDoorCost: random-range-middle-6-15 + BasementStarDoorCost: random-range-middle-20-40 + SecondFloorStarDoorCost: random-range-middle-40-60 + MIPS1Cost: random-range-middle-10-20 + MIPS2Cost: 50 + StarsToFinish: 60 + death_link: 'false' + BuddyChecks: 'true' +Factorio: + accessibility: items + max_science_pack: production_science_pack + goal: rocket + tech_tree_layout: random + tech_cost: kind + silo: randomize_recipe + satellite: randomize_recipe + free_samples: single_craft + tech_tree_information: advancement + recipe_time: normal + recipe_ingredients: science_pack + imported_blueprints: 'true' + progressive: on + evolution_traps: 0 + attack_traps: 0 + evolution_trap_increase: 10 + starting_items: # Mapping of Factorio internal item-name to amount granted on start. + burner-mining-drill: 10 + stone-furnace: 10 + world_gen: # World Generation settings. Overview of options at https://wiki.factorio.com/Map_generator, + # with in-depth documentation at https://lua-api.factorio.com/latest/Concepts.html#MapGenSettings + autoplace_controls: + coal: + frequency: 1 + richness: 6 + size: 3 + copper-ore: + frequency: 1 + richness: 6 + size: 3 + crude-oil: + frequency: 1 + richness: 6 + size: 3 + enemy-base: + frequency: 1 + richness: 1 + size: 1 + iron-ore: + frequency: 1 + richness: 6 + size: 3 + stone: + frequency: 1 + richness: 6 + size: 3 + trees: + frequency: 1 + richness: 1 + size: 1 + uranium-ore: + frequency: 1 + richness: 6 + size: 3 + cliff_settings: + cliff_elevation_0: 10 + cliff_elevation_interval: 40 + name: cliff + richness: 1 + enemy_evolution: + destroy_factor: 0.002 + enabled: true + pollution_factor: 9.0e-07 + time_factor: 4.0e-06 + enemy_expansion: + enabled: true + max_expansion_cooldown: 216000 + max_expansion_distance: 7 + min_expansion_cooldown: 14400 + settler_group_max_size: 20 + settler_group_min_size: 5 + peaceful_mode: false + pollution: + ageing: 1 + diffusion_ratio: 0.02 + enabled: true + enemy_attack_pollution_consumption_modifier: 1 + min_pollution_to_damage_trees: 60 + pollution_restored_per_tree_damage: 10 + property_expression_names: + control-setting:aux:bias: 0 + control-setting:aux:frequency:multiplier: 1 + control-setting:moisture:bias: 0 + control-setting:moisture:frequency:multiplier: 1 + seed: null + starting_area: 1.5 + terrain_segmentation: 0.5 + water: 1.5 + progression_balancing: 30 + death_link: 'false' + energy_link: 'false' +Subnautica: + progression_balancing: 25 + accessibility: items + swim_rule: easy + early_seaglide: 'true' + item_pool: valuable + goal: infected + creature_scans: 15 + creature_scan_logic: either + death_link: 'false' + start_inventory: + Seamoth Fragment: 1 +Timespinner: + progression_balancing: 30 + accessibility: items + StartWithJewelryBox: 'true' + DownloadableItems: 'true' + EyeSpy: 'false' + StartWithMeyef: 'false' + QuickSeed: 'false' + SpecificKeycards: 'true' + Inverted: + random: 1 + GyreArchives: 'false' + Cantoran: 'true' + LoreChecks: 'true' + BossRando: 'true' + BossScaling: 'true' + DamageRando: balanced + HpCap: 999 + BossHealing: 'true' + ShopFill: randomized + ShopWarpShards: 'true' + ShopMultiplier: 1 + LootPool: randomized + DropRateCategory: tiered + FixedDropRate: 5 + LootTierDistro: default_weight + ShowBestiary: 'true' + ShowDrops: 'false' + EnterSandman: 'false' + DeathLink: 'false' +The Witness: + progression_balancing: 50 + accessibility: items + puzzle_randomization: sigma_normal + shuffle_symbols: 'true' + shuffle_doors: doors_complex + shuffle_lasers: 'true' + disable_non_randomized_puzzles: 'false' + shuffle_discarded_panels: 'true' + shuffle_vault_boxes: 'true' + shuffle_postgame: 'false' + victory_condition: mountain_box_short + mountain_lasers: 7 + challenge_lasers: 8 + early_secret_area: 'false' + trap_percentage: 25 + puzzle_skip_amount: 9 + hint_amount: 10 + death_link: 'true' + local_items: ["Lasers"] \ No newline at end of file diff --git a/disabled yamls/RC1/Figment-SDV-4xx-MA.yaml b/disabled yamls/RC1/Figment-SDV-4xx-MA.yaml new file mode 100644 index 000000000000..4e2c20801d93 --- /dev/null +++ b/disabled yamls/RC1/Figment-SDV-4xx-MA.yaml @@ -0,0 +1,190 @@ +description: NO FARM, ONLY FISH! +name: Figment{NUMBER} +game: Stardew Valley +requires: + version: 0.4.2 + plando: items +Stardew Valley: + progression_balancing: 50 + accessibility: items + goal: master_angler + starting_money: -1 + profit_margin: 400 + bundle_randomization: vanilla + bundle_price: very_cheap + entrance_randomization: disabled + season_randomization: randomized + cropsanity: disabled + backpack_progression: vanilla + tool_progression: progressive + skill_progression: progressive + building_progression: vanilla + festival_locations: disabled + elevator_progression: progressive + arcade_machine_locations: disabled + special_order_locations: disabled + help_wanted_locations: 0 + fishsanity: all + museumsanity: milestones + friendsanity: none + friendsanity_heart_size: 4 + movement_buff_number: 0 + luck_buff_number: 12 + exclude_ginger_island: true + trap_items: no_traps + multiple_day_sleep_enabled: true + multiple_day_sleep_cost: 0 + experience_multiplier: 800 + friendship_multiplier: 800 + debris_multiplier: start_clear + quick_start: true + gifting: true + mods: [] + death_link: false + start_inventory: {Return Scepter: 1} + exclude_locations: + - A Soldier's Star + - Animal Bundle + - Artisan Bundle + - Carving Pumpkins + - Chef's Bundle + - Complete Bulletin Board + - Complete Pantry + - Cow's Delight + - Crop Research + - Cryptic Note + - Dye Bundle + - Enchanter's Bundle + - Exotic Spirits + - Fall Crops Bundle + - Floor 105 Elevator + - Floor 110 Elevator + - Fresh Fruit + - Galaxy Sword Shrine + - Have Another Baby + - Have a Baby + - Iridium Axe Upgrade + - Iridium Hoe Upgrade + - Iridium Pickaxe Upgrade + - Iridium Trash Can Upgrade + - Iridium Watering Can Upgrade + - Jodi's Request + - Knee Therapy + - Magic Ink + - Mayor's "Shorts" + - Mayor's Need + - 'Museumsanity: 3 Artifacts' + - 'Museumsanity: 5 Donations' + - 'Museumsanity: 6 Artifacts' + - 'Museumsanity: 9 Artifacts' + - 'Museumsanity: 11 Artifacts' + - 'Museumsanity: 11 Minerals' + - 'Museumsanity: 15 Artifacts' + - 'Museumsanity: 15 Donations' + - 'Museumsanity: 20 Artifacts' + - Old Master Cannoli + - Pam Is Thirsty + - Pam Needs Juice + - Qi's Challenge + - Quality Crops Bundle + - Spring Crops Bundle + - Staff Of Power + - Strange Note + - Summer Crops Bundle + - The Mines Floor 110 Treasure + - The Mysterious Qi + plando_items: + # Skills + - items: + Combat Level: 10 + locations: + - Level 1 Combat + - Level 2 Combat + - Level 3 Combat + - Level 4 Combat + - Level 5 Combat + - Level 6 Combat + - Level 7 Combat + - Level 8 Combat + - Level 9 Combat + - Level 10 Combat + - items: + Farming Level: 10 + locations: + - Level 1 Farming + - Level 2 Farming + - Level 3 Farming + - Level 4 Farming + - Level 5 Farming + - Level 6 Farming + - Level 7 Farming + - Level 8 Farming + - Level 9 Farming + - Level 10 Farming + - items: + Foraging Level: 10 + locations: + - Level 1 Foraging + - Level 2 Foraging + - Level 3 Foraging + - Level 4 Foraging + - Level 5 Foraging + - Level 6 Foraging + - Level 7 Foraging + - Level 8 Foraging + - Level 9 Foraging + - Level 10 Foraging + - items: + Mining Level: 10 + locations: + - Level 1 Mining + - Level 2 Mining + - Level 3 Mining + - Level 4 Mining + - Level 5 Mining + - Level 6 Mining + - Level 7 Mining + - Level 8 Mining + - Level 9 Mining + - Level 10 Mining + # Vanilla Museum + - item: + Ancient Seeds Recipe: 1 + location: 'Museumsanity: Ancient Seed' + - item: + Dwarvish Translation Guide: 1 + location: 'Museumsanity: Dwarf Scrolls' + # Filler Museum + - items: + Ancient Seeds: 5 + Magic Rock Candy: 5 + Traveling Merchant Discount: 8 + locations: + - 'Museumsanity: 20 Donations' + - 'Museumsanity: 21 Minerals' + - 'Museumsanity: 25 Donations' + - 'Museumsanity: 30 Donations' + - 'Museumsanity: 31 Minerals' + - 'Museumsanity: 35 Donations' + - 'Museumsanity: 40 Donations' + - 'Museumsanity: 41 Minerals' + - 'Museumsanity: 50 Donations' + - 'Museumsanity: 50 Minerals' + - 'Museumsanity: 60 Donations' + - 'Museumsanity: 70 Donations' + - 'Museumsanity: 80 Donations' + - 'Museumsanity: 90 Donations' + - 'Museumsanity: 95 Donations' + - 'Museumsanity: Skeleton Back' + - 'Museumsanity: Skeleton Front' + - 'Museumsanity: Skeleton Middle' + # Mines + - item: + Rusty Sword: 1 + location: Floor 115 Elevator + - item: + Slingshot: 1 + location: Floor 120 Elevator + - item: + Master Slingshot: 1 + location: The Mines Floor 120 Treasure \ No newline at end of file diff --git a/disabled yamls/RC1/Forsaken_Terraria.yaml b/disabled yamls/RC1/Forsaken_Terraria.yaml new file mode 100644 index 000000000000..d86ba60d4aea --- /dev/null +++ b/disabled yamls/RC1/Forsaken_Terraria.yaml @@ -0,0 +1,120 @@ +# Q. What is this file? +# A. This file contains options which allow you to configure your multiworld experience while allowing +# others to play how they want as well. +# +# Q. How do I use it? +# A. The options in this file are weighted. This means the higher number you assign to a value, the +# more chances you have for that option to be chosen. For example, an option like this: +# +# map_shuffle: +# on: 5 +# off: 15 +# +# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned +# off. +# +# Q. I've never seen a file like this before. What characters am I allowed to use? +# A. This is a .yaml file. You are allowed to use most characters. +# To test if your yaml is valid or not, you can use this website: +# http://www.yamllint.com/ +# You can also verify your Archipelago settings are valid at this site: +# https://archipelago.gg/check + +# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. +# {player} will be replaced with the player's slot number. +# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. +# {number} will be replaced with the counter value of the name. +# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. +name: Forsaken + +# Used to describe your yaml. Useful if you have multiple files. +description: Default Terraria Template + +game: Terraria +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +Terraria: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 50 # equivalent to 50 + extreme: 0 # equivalent to 99 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + {} + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + goal: + # The victory condition for your run. Stuff after the goal will not be shuffled. + mechanical_bosses: 0 + plantera: 0 + golem: 0 + empress_of_light: 0 + lunatic_cultist: 0 + moon_lord: 50 + zenith: 0 + + achievements: + # Adds checks upon collecting achievements. Achievements for clearing bosses and events are excluded. + # "Exclude Grindy" also excludes fishing achievements. + none: 50 + exclude_grindy: 0 + exclude_fishing: 0 + all: 0 + + fill_extra_checks_with: + # Applies if you have achievements enabled. "Useful Items" helps to make the early game less grindy. + # Items are rewarded to all players in your Terraria world. + coins: 0 + useful_items: 50 + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 50 + true: 0 diff --git a/disabled yamls/RC1/KenderUT_Neutral.yaml b/disabled yamls/RC1/KenderUT_Neutral.yaml new file mode 100644 index 000000000000..c45d150dbc5a --- /dev/null +++ b/disabled yamls/RC1/KenderUT_Neutral.yaml @@ -0,0 +1,17 @@ +Undertale: + progression_balancing: 50 + accessibility: items + route_required: neutral + key_hunt: random + key_pieces: 5 + rando_love: 'false' + rando_stats: 'false' + temy_include: 'true' + no_equips: 'false' + only_flakes: 'false' + prog_armor: 'false' + prog_weapons: 'false' + rando_item_button: 'true' +description: 'Generated by https://archipelago.gg/ for Undertale' +game: Undertale +name: KenderUT diff --git a/disabled yamls/RC1/Parker.yaml b/disabled yamls/RC1/Parker.yaml new file mode 100644 index 000000000000..d17640ebc877 --- /dev/null +++ b/disabled yamls/RC1/Parker.yaml @@ -0,0 +1,24 @@ +The Witness: + progression_balancing: 50 + accessibility: items + puzzle_randomization: sigma_normal + shuffle_symbols: 'true' + shuffle_doors: max + shuffle_lasers: 'false' + disable_non_randomized_puzzles: 'false' + shuffle_discarded_panels: 'true' + shuffle_vault_boxes: 'true' + shuffle_EPs: individual + EP_difficulty: normal + shuffle_postgame: 'true' + victory_condition: challenge + mountain_lasers: 7 + challenge_lasers: 11 + early_secret_area: 'false' + trap_percentage: 0 + puzzle_skip_amount: 30 + hint_amount: 49 + death_link: 'true' +description: 'Generated by https://archipelago.gg/ for The Witness' +game: The Witness +name: Parker diff --git a/disabled yamls/RC1/Phar.yaml b/disabled yamls/RC1/Phar.yaml new file mode 100644 index 000000000000..210f28fbdc52 --- /dev/null +++ b/disabled yamls/RC1/Phar.yaml @@ -0,0 +1,504 @@ +# What is this file? +# This file contains options which allow you to configure your multiworld experience while allowing others +# to play how they want as well. + +# How do I use it? +# The options in this file are weighted. This means the higher number you assign to a value, the more +# chances you have for that option to be chosen. For example, an option like this: +# +# map_shuffle: +# on: 5 +# off: 15 +# +# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned off + +# I've never seen a file like this before. What characters am I allowed to use? +# This is a .yaml file. You are allowed to use most characters. +# To test if your yaml is valid or not, you can use this website: +# http://www.yamllint.com/ + +description: Template Name # Used to describe your yaml. Useful if you have multiple files +name: Phar # Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit +#{player} will be replaced with the player's slot number. +#{PLAYER} will be replaced with the player's slot number if that slot number is greater than 1. +#{number} will be replaced with the counter value of the name. +#{NUMBER} will be replaced with the counter value of the name if the counter value is greater than 1. +game: # Pick a game to play + A Link to the Past: 1 +requires: + version: 0.3.3 # Version of Archipelago required for this yaml to work as expected. +A Link to the Past: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 0 # equivalent to 50 + extreme: 0 # equivalent to 99 + 15: 5 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [ ] + + non_local_items: + # Forces these items to be outside their native world. + [ ] + + start_inventory: + # Start with these items. + { } + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [ ] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [ ] + + exclude_locations: + # Prevent these locations from having an important item + [ ] + + priority_locations: + # Prevent these locations from having an unimportant item + [ ] + + item_links: + # Share part of your item pool with other players. + [ ] + + ### Logic Section ### + glitches_required: # Determine the logic required to complete the seed + none: 0 # No glitches required + minor_glitches: 50 # Puts fake flipper, waterwalk, super bunny shenanigans, and etc into logic + overworld_glitches: 0 # Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches + hybrid_major_glitches: 0 # In addition to overworld glitches, also requires underworld clips between dungeons. + no_logic: 0 # Your own items are placed with no regard to any logic; such as your Fire Rod can be on your Trinexx. + # Other players items are placed into your world under HMG logic + dark_room_logic: # Logic for unlit dark rooms + lamp: 50 # require the Lamp for these rooms to be considered accessible. + torches: 0 # in addition to lamp, allow the fire rod and presence of easily accessible torches for access + none: 0 # all dark rooms are always considered doable, meaning this may force completion of rooms in complete darkness + restrict_dungeon_item_on_boss: # aka ambrosia boss items + on: 0 # prevents unshuffled compasses, maps and keys to be boss drops, they can still drop keysanity and other players' items + off: 50 + ### End of Logic Section ### + bigkey_shuffle: # Big Key Placement + original_dungeon: 0 + own_dungeons: 0 + own_world: 0 + any_world: 50 + different_world: 0 + start_with: 0 + smallkey_shuffle: # Small Key Placement + original_dungeon: 50 + own_dungeons: 0 + own_world: 0 + any_world: 0 + different_world: 0 + universal: 0 + start_with: 0 + compass_shuffle: # Compass Placement + original_dungeon: 0 + own_dungeons: 0 + own_world: 0 + any_world: 0 + different_world: 0 + start_with: 50 + map_shuffle: # Map Placement + original_dungeon: 0 + own_dungeons: 0 + own_world: 0 + any_world: 0 + different_world: 0 + start_with: 50 + dungeon_counters: + on: 0 # Always display amount of items checked in a dungeon + pickup: 50 # Show when compass is picked up + default: 0 # Show when compass is picked up if the compass itself is shuffled + off: 0 # Never show item count in dungeons + progressive: # Enable or disable progressive items (swords, shields, bow) + on: 50 # All items are progressive + off: 0 # No items are progressive + grouped_random: 0 # Randomly decides for all items. Swords could be progressive, shields might not be + entrance_shuffle: + none: 50 # Vanilla game map. All entrances and exits lead to their original locations. You probably want this option + dungeonssimple: 0 # Shuffle just dungeons amongst each other, swapping dungeons entirely, so Hyrule Castle is always 1 dungeon + dungeonsfull: 0 # Shuffle any dungeon entrance with any dungeon interior, so Hyrule Castle can be 4 different dungeons, but keep dungeons to a specific world + dungeonscrossed: 0 # like dungeonsfull, but allow cross-world traversal through a dungeon. Warning: May force repeated dungeon traversal + simple: 0 # Entrances are grouped together before being randomized. Simple uses the most strict grouping rules + restricted: 0 # Less strict than simple + full: 0 # Less strict than restricted + crossed: 0 # Less strict than full + insanity: 0 # Very few grouping rules. Good luck + # you can also define entrance shuffle seed, like so: + crossed-1000: 0 # using this method, you can have the same layout as another player and share entrance information + # however, many other settings like logic, world state, retro etc. may affect the shuffle result as well. + crossed-group-myfriends: 0 # using this method, everyone with "group-myfriends" will share the same seed + goals: + ganon: 0 # Climb GT, defeat Agahnim 2, and then kill Ganon + crystals: 50 # Only killing Ganon is required. However, items may still be placed in GT + bosses: 0 # Defeat the boss of all dungeons, including Agahnim's tower and GT (Aga 2) + pedestal: 0 # Pull the Triforce from the Master Sword pedestal + ganon_pedestal: 0 # Pull the Master Sword pedestal, then kill Ganon + triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then turn them in to Murahadala in front of Hyrule Castle + local_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout your world, then turn them in to Murahadala in front of Hyrule Castle + ganon_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then kill Ganon + local_ganon_triforce_hunt: 50 # Collect 20 of 30 Triforce pieces spread throughout your world, then kill Ganon + ice_rod_hunt: 0 # You start with everything needed to 216 the seed. Find the Ice rod, then kill Trinexx at Turtle rock. + open_pyramid: + goal: 50 # Opens the pyramid if the goal requires you to kill Ganon, unless the goal is Slow Ganon or All Dungeons + auto: 0 # Same as Goal, but also is closed if holes are shuffled and ganon is part of the shuffle pool + open: 0 # Pyramid hole is always open. Ganon's vulnerable condition is still required before he can he hurt + closed: 0 # Pyramid hole is always closed until you defeat Agahnim atop Ganon's Tower + triforce_pieces_mode: #Determine how to calculate the extra available triforce pieces. + extra: 50 # available = triforce_pieces_extra + triforce_pieces_required + percentage: 0 # available = (triforce_pieces_percentage /100) * triforce_pieces_required + available: 0 # available = triforce_pieces_available + triforce_pieces_extra: # Set to how many extra triforces pieces are available to collect in the world. + # Format "pieces: chance" + 0: 0 + 5: 50 + 10: 50 + 15: 0 + 20: 0 + triforce_pieces_percentage: # Set to how many triforce pieces according to a percentage of the required ones, are available to collect in the world. + # Format "pieces: chance" + 100: 0 #No extra + 150: 50 #Half the required will be added as extra + 200: 0 #There are the double of the required ones available. + triforce_pieces_available: # Set to how many triforces pieces are available to collect in the world. Default is 30. Max is 90, Min is 1 + # Format "pieces: chance" + 25: 0 + 30: 50 + 40: 0 + 50: 0 + triforce_pieces_required: # Set to how many out of X triforce pieces you need to win the game in a triforce hunt. Default is 20. Max is 90, Min is 1 + # Format "pieces: chance" + 15: 50 + 20: 50 + 30: 50 + 40: 0 + 50: 0 + crystals_needed_for_gt: # Crystals required to open GT + 0: 0 + random-range-2-5: 50 + random: 0 + random-low: 0 # any valid number, weighted towards the lower end + random-middle: 0 # any valid number, weighted towards the central range + random-high: 0 # any valid number, weighted towards the higher end + crystals_needed_for_ganon: # Crystals required to hurt Ganon + 0: 0 + random-range-4-7: 50 + random: 0 + random-low: 0 + random-middle: 0 + random-high: 0 + mode: + standard: 0 # Begin the game by rescuing Zelda from her cell and escorting her to the Sanctuary + open: 50 # Begin the game from your choice of Link's House or the Sanctuary + inverted: 0 # Begin in the Dark World. The Moon Pearl is required to avoid bunny-state in Light World, and the Light World game map is altered + retro_bow: + on: 0 # Zelda-1 like mode. You have to purchase a quiver to shoot arrows using rupees. + off: 50 + retro_caves: + on: 0 # Zelda-1 like mode. There are randomly placed take-any caves that contain one Sword and choices of Heart Container/Blue Potion. + off: 50 + hints: # On/Full: Put item and entrance placement hints on telepathic tiles and some NPCs, Full removes joke hints. + 'on': 50 + 'off': 0 + full: 0 + scams: # If on, these Merchants will no longer tell you what they're selling. + 'off': 50 + 'king_zora': 0 + 'bottle_merchant': 0 + 'all': 0 + swordless: + on: 2 # Your swords are replaced by rupees. Gameplay changes have been made to accommodate this change + off: 8 + item_pool: + easy: 0 # Doubled upgrades, progressives, and etc + normal: 50 # Item availability remains unchanged from vanilla game + hard: 50 # Reduced upgrade availability (max: 14 hearts, blue mail, tempered sword, fire shield, no silvers unless swordless) + expert: 0 # Minimum upgrade availability (max: 8 hearts, green mail, master sword, fighter shield, no silvers unless swordless) + item_functionality: + easy: 0 # Allow Hammer to damage ganon, Allow Hammer tablet collection, Allow swordless medallion use everywhere. + normal: 50 # Vanilla item functionality + hard: 0 # Reduced helpfulness of items (potions less effective, can't catch faeries, cape uses double magic, byrna does not grant invulnerability, boomerangs do not stun, silvers disabled outside ganon) + expert: 0 # Vastly reduces the helpfulness of items (potions barely effective, can't catch faeries, cape uses double magic, byrna does not grant invulnerability, boomerangs and hookshot do not stun, silvers disabled outside ganon) + tile_shuffle: # Randomize the tile layouts in flying tile rooms + on: 0 + off: 50 + misery_mire_medallion: # required medallion to open Misery Mire front entrance + random: 50 + Ether: 0 + Bombos: 0 + Quake: 0 + turtle_rock_medallion: # required medallion to open Turtle Rock front entrance + random: 50 + Ether: 0 + Bombos: 0 + Quake: 0 + ### Enemizer Section ### + boss_shuffle: + none: 50 # Vanilla bosses + basic: 0 # Existing bosses except Ganon and Agahnim are shuffled throughout dungeons + full: 0 # 3 bosses can occur twice + chaos: 0 # Any boss can appear any amount of times + singularity: 0 # Picks a boss, tries to put it everywhere that works, if there's spaces remaining it picks a boss to fill those + enemy_shuffle: # Randomize enemy placement + on: 0 + off: 50 + killable_thieves: # Make thieves killable + on: 0 # Usually turned on together with enemy_shuffle to make annoying thief placement more manageable + off: 50 + bush_shuffle: # Randomize the chance that bushes have enemies and the enemies under said bush + on: 0 + off: 50 + enemy_damage: + default: 50 # Vanilla enemy damage + shuffled: 0 # Enemies deal 0 to 4 hearts and armor helps + chaos: 0 # Enemies deal 0 to 8 hearts and armor just reshuffles the damage + enemy_health: + default: 50 # Vanilla enemy HP + easy: 0 # Enemies have reduced health + hard: 0 # Enemies have increased health + expert: 0 # Enemies have greatly increased health + pot_shuffle: + 'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile + 'off': 50 # Default pot item locations + ### End of Enemizer Section ### + ### Beemizer ### + # can add weights for any whole number between 0 and 100 + beemizer_total_chance: # Remove items from the global item pool and replace them with single bees (fill bottles) and bee traps + 0: 0 # No junk fill items are replaced (Beemizer is off) + 25: 50 # 25% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees + 50: 0 # 50% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees + 75: 0 # 75% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees + 100: 0 # All junk fill items (rupees, bombs and arrows) are replaced with bees + beemizer_trap_chance: + 60: 50 # 60% chance for each beemizer replacement to be a trap, 40% chance to be a single bee + 70: 0 # 70% chance for each beemizer replacement to be a trap, 30% chance to be a single bee + 80: 0 # 80% chance for each beemizer replacement to be a trap, 20% chance to be a single bee + 90: 0 # 90% chance for each beemizer replacement to be a trap, 10% chance to be a single bee + 100: 0 # All beemizer replacements are traps + ### Shop Settings ### + shop_item_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl) + 0: 50 + 5: 0 + 15: 0 + 30: 0 + random: 0 # 0 to 30 evenly distributed + shop_price_modifier: # Percentage modifier for shuffled item prices in shops + # you can add additional values between minimum and maximum + 0: 0 # minimum value + 400: 0 # maximum value + random: 0 + random-low: 0 + random-high: 0 + 100: 50 + shop_shuffle: + none: 50 + g: 0 # Generate new default inventories for overworld/underworld shops, and unique shops + f: 0 # Generate new default inventories for every shop independently + i: 0 # Shuffle default inventories of the shops around + p: 0 # Randomize the prices of the items in shop inventories + u: 0 # Shuffle capacity upgrades into the item pool (and allow them to traverse the multiworld) + w: 0 # Consider witch's hut like any other shop and shuffle/randomize it too + P: 0 # Prices of the items in shop inventories cost hearts, arrow, or bombs instead of rupees + ip: 0 # Shuffle inventories and randomize prices + fpu: 0 # Generate new inventories, randomize prices and shuffle capacity upgrades into item pool + uip: 0 # Shuffle inventories, randomize prices and shuffle capacity upgrades into the item pool + # You can add more combos + ### End of Shop Section ### + shuffle_prizes: # aka drops + none: 0 # do not shuffle prize packs + g: 50 # shuffle "general" prize packs, as in enemy, tree pull, dig etc. + b: 0 # shuffle "bonk" prize packs + bg: 0 # shuffle both + timer: + none: 50 # No timer will be displayed. + timed: 0 # Starts with clock at zero. Green clocks subtract 4 minutes (total 20). Blue clocks subtract 2 minutes (total 10). Red clocks add two minutes (total 10). Winner is the player with the lowest time at the end. + timed_ohko: 0 # Starts the clock at ten minutes. Green clocks add five minutes (total 25). As long as the clock as at zero, Link will die in one hit. + ohko: 0 # Timer always at zero. Permanent OHKO. + timed_countdown: 0 # Starts the clock with forty minutes. Same clocks as timed mode, but if the clock hits zero you lose. You can still keep playing, though. + display: 0 # Displays a timer, but otherwise does not affect gameplay or the item pool. + countdown_start_time: # For timed_ohko and timed_countdown timer modes, the amount of time in minutes to start with + 0: 0 # For timed_ohko, starts in OHKO mode when starting the game + 10: 50 + 20: 0 + 30: 0 + 60: 0 + red_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a red clock + -2: 50 + 1: 0 + blue_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a blue clock + 1: 0 + 2: 50 + green_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a green clock + 4: 50 + 10: 0 + 15: 0 + glitch_boots: + on: 50 # Start with Pegasus Boots in any glitched logic mode that makes use of them + off: 0 + # rom options section + random_sprite_on_event: # An alternative to specifying randomonhit / randomonexit / etc... in sprite down below. + enabled: # If enabled, sprite down below is ignored completely, (although it may become the sprite pool) + on: 0 + off: 1 + on_hit: # Random sprite on hit. Being hit by things that cause 0 damage still counts. + on: 1 + off: 0 + on_enter: # Random sprite on underworld entry. Note that entering hobo counts. + on: 0 + off: 1 + on_exit: # Random sprite on underworld exit. Exiting hobo does not count. + on: 0 + off: 1 + on_slash: # Random sprite on sword slash. Note, it still counts if you attempt to slash while swordless. + on: 0 + off: 1 + on_item: # Random sprite on getting an item. Anything that causes you to hold an item above your head counts. + on: 0 + off: 1 + on_bonk: # Random sprite on bonk. + on: 0 + off: 1 + on_everything: # Random sprite on ALL currently implemented events, even if not documented at present time. + on: 0 + off: 1 + use_weighted_sprite_pool: # Always on if no sprite_pool exists, otherwise it controls whether to use sprite as a weighted sprite pool + on: 0 + off: 1 + #sprite_pool: # When specified, limits the pool of sprites used for randomon-event to the specified pool. Uncomment to use this. + # - link + # - pride link + # - penguin link + # - random # You can specify random multiple times for however many potentially unique random sprites you want in your pool. + sprite: # Enter the name of your preferred sprite and weight it appropriately + random: 0 + randomonhit: 0 # Random sprite on hit + randomonenter: 0 # Random sprite on entering the underworld. + randomonexit: 0 # Random sprite on exiting the underworld. + randomonslash: 0 # Random sprite on sword slashes + randomonitem: 0 # Random sprite on getting items. + randomonbonk: 0 # Random sprite on bonk. + # You can combine these events like this. randomonhit-enter-exit if you want it on hit, enter, exit. + randomonall: 0 # Random sprite on any and all currently supported events. Refer to above for the supported events. + Lucario: 50 # To add other sprites: open the gui/Creator, go to adjust, select a sprite and write down the name the gui calls it + music: # If "off", all in-game music will be disabled + on: 50 + off: 0 + quickswap: # Enable switching items by pressing the L+R shoulder buttons + on: 50 + off: 0 + triforcehud: # Disable visibility of the triforce hud unless collecting a piece or speaking to Murahadala + normal: 0 # original behavior (always visible) + hide_goal: 0 # hide counter until a piece is collected or speaking to Murahadala + hide_required: 0 # Always visible, but required amount is invisible until determined by Murahadala + hide_both: 50 # Hide both under above circumstances + reduceflashing: # Reduces instances of flashing such as lightning attacks, weather, ether and more. + on: 50 + off: 0 + menuspeed: # Controls how fast the item menu opens and closes + normal: 50 + instant: 0 + double: 0 + triple: 0 + quadruple: 0 + half: 0 + heartcolor: # Controls the color of your health hearts + red: 50 + blue: 0 + green: 0 + yellow: 0 + random: 0 + heartbeep: # Controls the frequency of the low-health beeping + double: 0 + normal: 50 + half: 0 + quarter: 0 + off: 0 + ow_palettes: # Change the colors of the overworld + default: 0 # No changes + good: 50 # Shuffle the colors, with harmony in mind + blackout: 0 # everything black / blind mode + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + uw_palettes: # Change the colors of caves and dungeons + default: 0 # No changes + good: 50 # Shuffle the colors, with harmony in mind + blackout: 0 # everything black / blind mode + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + hud_palettes: # Change the colors of the hud + default: 0 # No changes + good: 50 # Shuffle the colors, with harmony in mind + blackout: 0 # everything black / blind mode + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + sword_palettes: # Change the colors of swords + default: 0 # No changes + good: 50 # Shuffle the colors, with harmony in mind + blackout: 0 # everything black / blind mode + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + shield_palettes: # Change the colors of shields + default: 0 # No changes + good: 50 # Shuffle the colors, with harmony in mind + blackout: 0 # everything black / blind mode + grayscale: 0 + negative: 0 + classic: 0 + dizzy: 0 + sick: 0 + puke: 0 + + death_link: + false: 50 + true: 0 + + allow_collect: # Allows for !collect / co-op to auto-open chests containing items for other players. + # Off by default, because it currently crashes on real hardware. + false: 0 + true: 50 +--- +name: Pharlique +game: Clique +Clique: + hard_mode: true + color: random \ No newline at end of file diff --git a/disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml b/disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml new file mode 100644 index 000000000000..ea413ff7fde8 --- /dev/null +++ b/disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml @@ -0,0 +1,19 @@ +SMZ3: + progression_balancing: 50 + accessibility: items + sm_logic: normal + sword_location: early + morph_location: early + goal: defeatboth + key_shuffle: none + open_tower: 7 + ganon_vulnerable: 7 + open_tourian: 4 + spin_jumps_animation: 'false' + heart_beep_speed: half + heart_color: blue + quick_swap: 'false' + energy_beep: 'true' +description: 'Generated by https://archipelago.gg/' +game: SMZ3 +name: Purple Peak diff --git a/disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml b/disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml new file mode 100644 index 000000000000..5ee2a397c5de --- /dev/null +++ b/disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml @@ -0,0 +1,279 @@ +# Q. What is this file? +# A. This file contains options which allow you to configure your multiworld experience while allowing +# others to play how they want as well. +# +# Q. How do I use it? +# A. The options in this file are weighted. This means the higher number you assign to a value, the +# more chances you have for that option to be chosen. For example, an option like this: +# +# map_shuffle: +# on: 5 +# off: 15 +# +# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned +# off. +# +# Q. I've never seen a file like this before. What characters am I allowed to use? +# A. This is a .yaml file. You are allowed to use most characters. +# To test if your yaml is valid or not, you can use this website: +# http://www.yamllint.com/ +# You can also verify your Archipelago settings are valid at this site: +# https://archipelago.gg/check + +# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. +# {player} will be replaced with the player's slot number. +# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. +# {number} will be replaced with the counter value of the name. +# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. +name: DoomedRivers + +# Used to describe your yaml. Useful if you have multiple files. +description: Default DOOM 1993 Template + +game: DOOM 1993 +requires: + version: 0.4.0 # Version of Archipelago required for this yaml to work as expected. + +DOOM 1993: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 1 # equivalent to 50 + extreme: 0 # equivalent to 99 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + difficulty: + # Choose the difficulty option. Those match DOOM's difficulty options. + # baby (I'm too young to die.) double ammos, half damage, less monsters or strength. + # easy (Hey, not too rough.) less monsters or strength. + # medium (Hurt me plenty.) Default. + # hard (Ultra-Violence.) More monsters or strength. + # nightmare (Nightmare!) Monsters attack more rapidly and respawn. + baby: 0 + easy: 0 + medium: 1 + hard: 0 + nightmare: 0 + + random_monsters: + # Choose how monsters are randomized. + # vanilla: No randomization + # shuffle: Monsters are shuffled within the level + # random_balanced: Monsters are completely randomized, but balanced based on existing ratio in the level. (Small monsters vs medium vs big) + vanilla: 0 + shuffle: 0 + random_balanced: 1 + + random_items: + # Choose how items are randomized. + # vanilla: No randomization + # shuffle: Items are shuffled within the level + # random_balanced: Items are completely randomized, but balanced based on existing ratio in the level. (Small item vs Big) + vanilla: 0 + shuffle: 0 + random_balanced: 1 + + allow_death_logic: + # Some locations require a timed puzzle that can only be tried once. + # After which if the player failed to get it, the location cannot be checked anymore. + # No progression items are placed in those are. There is a way, hovewer, to still get them: + # Get killed in the current map. The map will reset, you can now attempt the puzzle again. + false: 50 + true: 0 + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 50 + true: 0 + + episode1: + # Knee-Deep in the Dead + false: 0 + true: 50 + + episode2: + # The Shores of Hell + false: 0 + true: 1 + + episode3: + # Inferno + false: 1 + true: 0 + + start_with_computer_area_maps: + # Give the player all Computer Area Map items from the start. + false: 0 + true: 1 + +--- + +Muse Dash: + progression_balancing: 0 + accessibility: items + available_trap_types: all + # Activates deathlink... you know you want to. + # Default: off + death_link: off + + # How many songs you can start out with. + # Note: Starting songs are first in line to get 2 items under additional_item_percentage + # Range 3-10. Default: 5 + starting_song_count: 3 + + # How many extra songs that are added in between the starting songs and ending songs. + # Note: This value will be lower if other options limit songs too much. + # Range 15-500. Default: 30 + additional_song_count: 50 + + # Whether or not songs that come with the DLC 'Just As Planned' are included. + # Default: false + allow_just_as_planned_dlc_songs: 'true' + + # Whether or not the songs chosen are available in Streamer Mode. Recommended to only switch this on, if you want to stream Muse Dash. + # Default: false + streamer_mode_enabled: 'false' + + # The number of music sheets placed in the multiworld + # Range 5-35. Default: 20 + music_sheet_count_percentage: 20 + + # The number of music sheets required to win + # Range 50-100. Default: 80 + music_sheet_win_count_percentage: 70 + + # The percentage of songs that get a second reward + # Range 50-100. Default: 80 + additional_item_percentage: 80 + + # The number of traps placed in the multiworld + # Range 0-35. Default: 15 + trap_count_percentage: 35 + + # Sets the grade needed to get rewards. + # Accepts the following: 'any'/0, 'c'/1, 'b'/2, 'a'/3, 'pinks'/4, 'silvers'/5. + # Default: 'any' + grade_needed: 'any' + + # Limits the range of songs chosen, such that at least 1 difficulty is within the chosen range. (Does not include secret difficulties) + # Supports the following: + # 'any' / 0 : Difficulty 1-11 + # 'easy' / 1 : Difficulty 1-3 + # 'medium' / 2 : Difficulty 4-5 + # 'hard' / 3 : Difficulty 6-7 + # 'expert' / 4 : Difficulty 8-9 + # 'master' / 5 : Difficulty 10-11 + # 'manual' / 6 : Allows song_difficulty_min and song_difficulty_max + # Default: 'any' + song_difficulty_mode: 'manual' + + # The following Options are only available under 'manual'" Must be between 1 and 11. Should not be randomised. + song_difficulty_min: 6 + song_difficulty_max: 8 + + # Any Traps or Songs you would want when starting the game. Any songs here will be considered as part of Starting Song Count. + start_inventory: + Bad Apple!! feat. Nomico: 1 + # Bad Apple Trap: 10 + # "Bad Apple!! feat. Nomico": 1 + + # Any songs you would want included within the randomiser. Will count as a song for additional_song_count. + # You will need to use the full name of the song. (i.e. "Bad Apple!! feat. Nomico") You can find this in song select at the bottom right while playing a seed. + # Songs here will not be starting songs. Use start_inventory for that. + include_songs: + - Night of Nights + - Cirno's Perfect Math Class + - Brain Power + - Nyan Cat + - Glimmer + - Magic Spell + - Bang!! + - Bit-alize + - PeroPero in the Universe + - I don't care about Christmas though + - Dandelion's Daydream + - Give Me 5 + - Sand Maze + - Fireflies + - Tenri Kaku Jou + # - "Bad Apple!! feat. Nomico" + + # Any songs you would want excluded within the randomiser. + # You will need to use the full name of the song. (i.e. "Bad Apple!! feat. Nomico") You can find this in song select at the bottom right while playing a seed. + exclude_songs: + - PUPA + - sheep in the light + - -+ + - Marry me, Nightmare + - ManiFesto + + bad_apple_mode: + on: 0 + off: 20 + +# non_local_items: +# - Music Sheet +# - Bad Apple Trap +# - Random Wave Trap +# - Background Freeze Trap +# - Pixelate Trap +# - Gray Scale Trap +# - Chromatic Aberration Trap +# - Shadow Edge Trap +triggers: + - option_name: bad_apple_mode + option_result: on + option_category: Muse Dash + options: + Muse Dash: + start_inventory: + Bad Apple Trap: 150 + Bad Apple!! feat. Nomico: 1 + +description: 'Generated by https://archipelago.gg/' +game: Muse Dash +name: Rivers Dash diff --git a/disabled yamls/RC1/Seto_Undertale.yaml b/disabled yamls/RC1/Seto_Undertale.yaml new file mode 100644 index 000000000000..373bd8f93c04 --- /dev/null +++ b/disabled yamls/RC1/Seto_Undertale.yaml @@ -0,0 +1,93 @@ +name: Seto Undertale + +description: Undertale Genocide + +game: Undertale +requires: + version: 0.4.2 + +Undertale: + progression_balancing: + random: 0 + random-low: 0 + random-high: 0 + disabled: 1 + normal: 0 + extreme: 0 + + accessibility: + locations: 1 + items: 0 + minimal: 0 + + local_items: + [] + + non_local_items: + [] + + start_inventory: + {Butterscotch Pie: 8} + + start_hints: + [] + + start_location_hints: + [] + + exclude_locations: + [] + + priority_locations: + [] + + item_links: + [] + + route_required: + neutral: 0 + pacifist: 0 + genocide: 1 + all_routes: 0 + + key_hunt: + false: 1 + true: 0 + + key_pieces: + 5: 1 + random: 0 + random-low: 0 + random-high: 0 + + rando_love: + false: 50 + true: 0 + + rando_stats: + false: 0 + true: 1 + + temy_include: + false: 0 + true: 1 + + no_equips: + false: 1 + true: 0 + + only_flakes: + false: 1 + true: 0 + + prog_armor: + false: 1 + true: 0 + + prog_weapons: + false: 0 + true: 1 + + rando_item_button: + false: 1 + true: 0 diff --git a/disabled yamls/RC1/Sheen-SDV4.yaml b/disabled yamls/RC1/Sheen-SDV4.yaml new file mode 100644 index 000000000000..53c22f4f5e16 --- /dev/null +++ b/disabled yamls/RC1/Sheen-SDV4.yaml @@ -0,0 +1,155 @@ +description: Stardew Mage Knight +game: Stardew Valley +name: sheen_sdv +Stardew Valley: + progression_balancing: 50 + accessibility: items + goal: greatest_walnut_hunter + # community_center: Complete the community center + # grandpa_evaluation: Get four candles on grandpa's shrine. You do not have to wait for Year3 to get evaluated + # bottom_of_the_mines: Reach the bottom of the local mineshaft + # cryptic_note: Complete the "Cryptic Note" quest, which is to reach level 100 in the Skull Cavern + # master_angler: Catch every fish in the game + # complete_collection: Complete the museum's collection by donating all 95 minerals and artifacts + # full_house: Get married and have two children + # greatest_walnut_hunter: Find all 130 golden walnuts + # perfection: Attain perfection in your world, based on how the vanilla game defines it, using the perfection tracker. This goal is extremely long + starting_money: unlimited + # 0-50000: How much money to start with. The vanilla game starts you with 500, but having more can really streamline Archipelago + # vanilla: 500 + # extra: 2000 + # rich: 5000 + # very rich: 20000 + # filthy rich: 50000 + # unlimited: Play with unlimited money + profit_margin: 200 + # 25-400: Multiplier over all earned money in-game. When below 100, some crops are no longer profitable to grow. + # quarter: 25 + # half: 50 + # normal: 100 + # double: 200 + # triple: 300 + # quadruple: 400 + bundle_randomization: shuffled + # vanilla: The bundles in the Community Center will be the ones from the vanilla game (not remixed) + # thematic: The bundles are randomized while following their original theme. Summer Crops Bundle will contain random summer crops, etc + # shuffled: The bundles are randomized with no regard for their individual themes or even rooms. Any bundle can contain any bundle item + bundle_price: very_cheap + # very_cheap: Every bundle will require two fewer items (capped at 1 item) from their list of accepted items. For Vault bundles, it is a 2/5th discount on the amount + # cheap: Every bundle will require one fewer item (capped at 1 item) from their list of accepted items. For Vault bundles, it is a 1/5th discount on the amount + # normal: Every bundle will require the vanilla number of items. For Vault bundles, it is the vanilla amount + # expensive: Every bundle will require one extra item (capped at the number of possible items) from their list of accepted items. For Vault bundles, it is a 1/5th increase on the amount + entrance_randomization: buildings # This includes entrances from supported mods + # disabled: Entrances are normal + # pelican_town: Entrances in the main Pelican Town map are shuffled with each other + # non_progression: Entrances to all of the areas that are always accessible without needing an archipelago unlock, will be shuffled with each other + # buildings: Every area that is "inside" can be shuffled with one another, included areas that are not immediately accessible + # chaos: Same as "buildings", but entrances are re-shuffled EVERY SINGLE DAY. + season_randomization: randomized # In archipelago, at the end of every in game season, you can choose which season will be next from the ones you have unlocked + # disabled: Seasons are all immediately available and you will start in spring + # randomized: You will start with a random season, and will earn the other 3 in a random order as Archipelago items + # randomized_not_winter: Same as randomized, but you are garanteed not to start in Winter + # progressive: You will start in spring, and unlock season as Archipelago items, but in the vanilla order, as "Progressive Season" items. + cropsanity: disabled # Pierre and Jojamart have been reworked for better lore compatibility and game balance + # disabled: All seeds and saplings can be purchased normally + # shuffled: You need to unlock the ability to purchase individual seed and sapling types as archipelago items. Every unlock comes with a free sample of 1. Growing and harvesting the resulting crop is a check. + backpack_progression: early_progressive # This includes backpacks from supported mods + # vanilla: You buy your backpack upgrades at Pierre's + # progressive: Backpack uprades are in the pool, you can buy two checks at Pierre's + # early_progressive: Backpack uprades are in the pool, but one of them is place early in the multiworld + tool_progression: progressive + # vanilla: You buy your tool upgrades at Clint's + # progressive: Tool upgrades are in the pool, you can go ask Clint for checks using money and metal bars + elevator_progression: progressive # This includes elevators from supported mods + # vanilla: The mineshaft elevator is unlocked normally, as you progress through the mineshaft levels + # progressive: The mineshaft elevator is unlocked by Archipelago progressive items, and every 5 level in the mineshaft is a check. + # progressive_from_previous_floor: Same as progressive, but you need to reach that level by using a ladder from the previous floor. You cannot unlock an elevator check using the elevator + skill_progression: progressive # This includes skills from supported mods + # vanilla: The player skills will gain experience locally, normally + # progressive: The player skills are upgraded through received progressive levels, and earned experience sends checks accordingly + building_progression: progressive # This includes buildings from supported mods + # vanilla: Carpenter buildings are constructed normally + # progressive: Robin sells one-time checks for each buildings, and you receive free buildings as Archipelago items. + # Once received and constructed once, you can pay the vanilla price to construct more iterations of the same building + # progressive_early_shipping_bin: Same as progressive, but the shipping bin will be placed early in the multiworld + festival_locations: disabled + # disabled: There are no checks to be obtained at the festivals + # easy: Participating in the festivals will check locations, but they are easy to do and just showing up is usually enough + # hard: The festival checks are only granted when the player performs well enough in them, so they need to take them seriously + arcade_machine_locations: disabled + # disabled: The Arcade Machines are not included. + # victories: Both Arcade Machines contain one check, obtainable by winning the default gamemode once, with no modifications + # victories_easy: Same as victories, except both arcade machines are made considerably easier through in-game buffs + # Junimo Kart will have 8 Extra lives for every level + # Journey of the Prairie King will start with one of each upgrade, 2 extra lives, and the drop rate of powerups and money is considerable increased + # full_shuffling: Both of the Arcade Machines contain many checks, and many buffs (including the ones from victories_easy) will be received as Archipelago Items, making the games easier over time + special_order_locations: disabled + # disabled: Special orders are not included in the multiworld + # board_only: The Special order board and rewards are items, and completing orders for the first time grants a check + # board_qi: In addition to the board, the difficult Qi Special Orders from the walnut room are also included + help_wanted_locations: 0 + # 0-56 [MUST BE A MULTIPLE OF 7]: The number of help wanted quests that are archipelago checks. For every 7, 4 are item deliveries, and 1 of each [fishing, gathering, slaying] + fishsanity: none + # none: None of the caught fish are AP locations + # legendaries: Catching legendary fish are AP locations + # special: Catching a pre-defined selection of important fish are AP locations + # random_selection: A random selection of fish are chosen and need to be caught as AP locations + # all: Fishsanity! Every single fish being caught is an AP location. + # exclude_legendaries: Every fish except legendary fish + # exclude_hard_fish: Every fish except the ones considered difficult + # only_easy_fish: Only the easy fish are checks + museumsanity: none # On all settings except none, the traveling merchant will assist you in completing your museum + # none: Museum donations are not included in the Archipelago shuffling + # milestones: Every donation milestone that gives a vanilla reward will instead give a check. Museum rewards are in the item pool + # randomized: A random selection of minerals and artifacts are chosen and need to be donated to the museum as AP locations. Museum rewards are in the item pool + # all: Museumsanity! Every single mineral and artifact being donated is an AP location. + friendsanity: all # This includes friendship hearts from supported mod NPCs + # none: Relationships are not included in the Archipelago shuffling + # bachelors: Friendship up to 8 hearts with the town bachelors are shuffled + # starting_npcs: Friendship up to 10 hearts (8 for bachelors) with the starting NPCs are shuffled. This excludes NPCs that require an event or item to be reached, like Sandy, Krobus, Kent, etc. + # all: Friendship up to 10 hearts (8 for bachelors) with every NPC in the game are shuffled. + # all_with_marriage: Same as all, but bachelors must each be befriended up to 14 hearts, which includes marrying every single one in succession. Not recommended for new players + friendsanity_heart_size: 2 # This setting does not do anything if not friendsanity is "none" + # 1-8: How many hearts are granted per heart item, and how many hearts must be earned to send a single check. A higher number reduces heart item clutter in the pool. The last heart is bounded to the relationship maximum. + movement_buff_number: 8 + # 0-12: Number of movement speed buffs in the pool + luck_buff_number: 12 + # 0-12: Number of luck buffs in the pool + exclude_ginger_island: 'false' + # true/false: Forcefully excludes every item and location that is related to Ginger Island, and removes both the Obelisk and the Boat repair from the item pool. + # When activating this setting, you will never need to, nor be able to, go to Ginger Island. This includes island quests, special orders, fish, and Leo's friendsanity hearts. + trap_items: hard # On any setting with traps, the number of traps is semi-random, with a bias towards having one of each, then rolling for more randomly side by side with filler resource packs. + # no_traps: There are no trap items in the pool. Filler items are only resource packs. + # easy: Trap items are intended to be funny and not very punishing + # medium: Trap items are minor annoyances that a competent player will deal with reasonably easily + # hard: Trap items are major annoyances that can be fairly punishing + # hell: trap items are extremely punishing and difficult and will severely impact gameplay + # nightmare: Just, don't. Trust me. + multiple_day_sleep_enabled: 'true' + # true/false: New feature allowing you to sleep several days at once. It is recommended to turn this on to avoid the game taking too long + # It allows the player to quickly skip long periods of time, to reach specific seasons or events. All decay mechanics (friends, animals, fences) will apply. + multiple_day_sleep_cost: 0 + # 0-200: The cost of the multisleep feature, in in-game money, per day skipped. The default value of zero is very strong, so this allows you to customize your experience + experience_multiplier: 800 + # 25-400: Multiplier to the experience gained on player skills. 100 is the vanilla experience gain, 200 is double, and so on. + friendship_multiplier: 800 + # 25-400: Multiplier to the friendship points gained from interactions with NPCs. 100 is vanilla, 200 is double, and so on. + debris_multiplier: half + # vanilla: The farm will start with, and generate over time, the normal amount of debris. Debris are natural grass, weeds, stones, twigs, and trees that are not grown from a seed + # half: Starting and spawned debris are halved + # quarter: Starting and spawned debris are reduced to 25% of their normal rate + # none: The farm will start fully cleared, and no debris will ever spawn on it. You can still plant grass and trees yourself. + # start_clear: The farm is completely cleared at the beginning of the game, but will spawn debris normally afterwards + quick_start: 'true' + # true/false: Starting a new game will give you several quality of life items as gifts when starting the game. + gifting: 'true' + # true/false: Allows sending items as gifts to other Stardew players and receiving gifts from other Stardew players + mods: ["Magic", "Bigger Backpack"] # Choose any combination of the following list of supported mods. Items and locations are added for custom npcs and skills, if using friendsanity and progressive skills. Bigger mods have some unique checks as well. All mod regions can be randomized with the entrance randomizer + # ["DeepWoods", "Tractor Mod", "Bigger Backpack", "Skull Cavern Elevator", + # "Luck Skill", "Magic", "Socializing Skill", "Archaeology", + # "Cooking Skill", "Binning Skill", "Juna - Roommate NPC", + # "Professor Jasper Thomas", "Alec Revisited", "Custom NPC - Yoba", "Custom NPC Eugene", + # "'Prophet' Wellwick", "Mister Ginger (cat npc)", "Shiko - New Custom NPC", "Delores - Custom NPC", + # "Ayeisha - The Postal Worker (Custom NPC)", "Custom NPC - Riley"] + start_inventory: {"Dwarvish Translation Guide": 1, "Rusty Key": 1, "Golden Walnut": 30} + death_link: 'false' diff --git a/disabled yamls/RC1/SilvrisTerraria.yaml b/disabled yamls/RC1/SilvrisTerraria.yaml new file mode 100644 index 000000000000..b5e43c6852df --- /dev/null +++ b/disabled yamls/RC1/SilvrisTerraria.yaml @@ -0,0 +1,120 @@ +# Q. What is this file? +# A. This file contains options which allow you to configure your multiworld experience while allowing +# others to play how they want as well. +# +# Q. How do I use it? +# A. The options in this file are weighted. This means the higher number you assign to a value, the +# more chances you have for that option to be chosen. For example, an option like this: +# +# map_shuffle: +# on: 5 +# off: 15 +# +# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned +# off. +# +# Q. I've never seen a file like this before. What characters am I allowed to use? +# A. This is a .yaml file. You are allowed to use most characters. +# To test if your yaml is valid or not, you can use this website: +# http://www.yamllint.com/ +# You can also verify your Archipelago settings are valid at this site: +# https://archipelago.gg/check + +# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. +# {player} will be replaced with the player's slot number. +# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. +# {number} will be replaced with the counter value of the name. +# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. +name: SilvrisTerraria + +# Used to describe your yaml. Useful if you have multiple files. +description: Default Terraria Template + +game: Terraria +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +Terraria: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 50 # equivalent to 50 + extreme: 0 # equivalent to 99 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + {} + + start_hints: + # Start with these item's locations prefilled into the !hint command. + ["Hardmode"] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + goal: + # The victory condition for your run. Stuff after the goal will not be shuffled. + mechanical_bosses: 50 + plantera: 0 + golem: 0 + empress_of_light: 0 + lunatic_cultist: 0 + moon_lord: 0 + zenith: 0 + + achievements: + # Adds checks upon collecting achievements. Achievements for clearing bosses and events are excluded. + # "Exclude Grindy" also excludes fishing achievements. + none: 0 + exclude_grindy: 50 + exclude_fishing: 0 + all: 0 + + fill_extra_checks_with: + # Applies if you have achievements enabled. "Useful Items" helps to make the early game less grindy. + # Items are rewarded to all players in your Terraria world. + coins: 0 + useful_items: 50 + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 50 + true: 0 diff --git a/disabled yamls/RC1/dennisw100_Terraria.yaml b/disabled yamls/RC1/dennisw100_Terraria.yaml new file mode 100644 index 000000000000..08b544f9900d --- /dev/null +++ b/disabled yamls/RC1/dennisw100_Terraria.yaml @@ -0,0 +1,17 @@ +Terraria: + progression_balancing: 50 + accessibility: items + goal: mechanical_bosses + # mechanical_bosses + # plantera + # golem + # empress_of_light + # lunatic_cultist + # moon_lord + # zenith + achievements: exclude_grindy + fill_extra_checks_with: useful_items + death_link: 'false' +description: 'Generated by https://archipelago.gg/ and edited by dennisw100' +game: Terraria +name: dennisw100 diff --git a/disabled yamls/RC1/speedweedDOOM.yaml b/disabled yamls/RC1/speedweedDOOM.yaml new file mode 100644 index 000000000000..b34f2390f8e4 --- /dev/null +++ b/disabled yamls/RC1/speedweedDOOM.yaml @@ -0,0 +1,178 @@ +# .JYJJ?7~^: .~?~. :^:. +# J55YY5PPGG5PBBBPJ~7YGGGPY?~. +# ^PYYYYY5YJPBBGGGBBBBBBGGBBBBPJ^.. +# ~P5YYJY5PGGBBBBGGGGGGGGGGGGGBBGPP5YYJJ?77~ +# .P5YYY5GBGGGBBBBBBBBBBBBBBGGGPJYYY5555PPGY +# !PY5PGBGGBGGGGGBGBBGGGGGGGGGG5Y55YJJJJYP~ +# ~GGGGPGGP5G5PGPGGGGBGGGGGGGGBP5YJYY5YPJ +# !PGGB#####J!GBP?Y5P5PGGGGPGGGGBPYJYYYPY. +# :J5GG&&&&&&J:Y&#GY?5BPPBGYGYYGGGGGYJ5PP? +# ^~!5PYB&&&&G:?&&&GB#&&&&&B!~P?YGGGGGPB5: +# :P5??JG##&P?#&#BP#&&&&&&7:Y&#JYBGB55GG^ +# .YY??7?GBBBBB#BBBBB#&&&&5:J&&&P?YGB57!J5: +# ~?!~:^?JB##BBBBBB##BBB##JY&&#GJ??5BP?. .: +# :. 7J7!PB##BBBBBBBBBBBBBPYJJ5PGGBBP7. +# .!^. 7??PB####B###BBPYJ?5#########G! +# ~~~J5P5PGPPPYJ?7^7Y############~ +# ^?PBB&&#BBBBG5PPGGJ!YJB##########B! +# .7P#&&BB&&&&#&&&&##&GG#GPGGB#####BBP? +# 5@&#PYY#&&&&&&&&&BB&&&&GYYYYY5P55Y?^ +# !B###P5&&&&&&&&&&PY5GGBB5YY~ .::.. +# YBBB#B&&&&&&&&&BYYY~.:^~~: +# ^B###G#&&&&&&&&#PY5? +# ^####Y?P####BGG5J??!:^:. +# 7PBG7!!7777!!!!!!^^^?J5J^ +# .^~!!!!!!!!!!!!!!^^~!JGBY^ +# ^!!!!!!!!!!!!!!~^^..^?GB? +# ~!!!!!!!!!!!!!!!^^: ^YBY. +# .!!!!!!!!!!!!!!!!^^^. .7B5. +# :!!!!!!!!!!!!!!!!~^^: !BP^ +# ^!!!!!!!!!!!!!!!!!^^^: ~GB7 ?PY^ +# .~!!!!!!!!!!!!!!!!^^:. :YB5!^^YBGY~ +# ^^~~!!!!!!!~~^:^^:. .!5GGGPY7: +# :~~^:...... .^^^. :^^:. +# .:^~~~^: :~^: +# ..:^~~~^:.. .^~~^: +# :!!!~~^^:. .^~~~^. +#:~7~^^:. :~~~^: +# .... :~~~!^:. +# .^~!?~~~. +# .:^^^: +name: speedweed + +# Used to describe your yaml. Useful if you have multiple files. +description: Default DOOM 1993 Template + +game: DOOM 1993 +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +DOOM 1993: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 50 # equivalent to 50 + extreme: 0 # equivalent to 99 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + {} + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + item_links: + # Share part of your item pool with other players. + [] + + difficulty: + # Choose the difficulty option. Those match DOOM's difficulty options. + # baby (I'm too young to die.) double ammos, half damage, less monsters or strength. + # easy (Hey, not too rough.) less monsters or strength. + # medium (Hurt me plenty.) Default. + # hard (Ultra-Violence.) More monsters or strength. + # nightmare (Nightmare!) Monsters attack more rapidly and respawn. + baby: 0 + easy: 0 + medium: 0 + hard: 1 + nightmare: 0 + + random_monsters: + # Choose how monsters are randomized. + # vanilla: No randomization + # shuffle: Monsters are shuffled within the level + # random_balanced: Monsters are completely randomized, but balanced based on existing ratio in the level. (Small monsters vs medium vs big) + vanilla: 0 + shuffle: 50 + random_balanced: 0 + + random_pickups: + # Choose how pickups are randomized. + # vanilla: No randomization + # shuffle: Pickups are shuffled within the level + # random_balanced: Pickups are completely randomized, but balanced based on existing ratio in the level. (Small pickups vs Big) + vanilla: 0 + shuffle: 50 + random_balanced: 0 + + allow_death_logic: + # Some locations require a timed puzzle that can only be tried once. + # After which, if the player failed to get it, the location cannot be checked anymore. + # By default, no progression items are placed here. There is a way, hovewer, to still get them: + # Get killed in the current map. The map will reset, you can now attempt the puzzle again. + false: 50 + true: 0 + + start_with_computer_area_maps: + # Give the player all Computer Area Map items from the start. + false: 50 + true: 0 + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 0 + true: 1 + + episode1: + # Knee-Deep in the Dead. + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 0 + true: 50 + + episode2: + # The Shores of Hell + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 0 + true: 50 + + episode3: + # Inferno + # If none of the episodes are chosen, Episode 1 will be chosen by default. + false: 0 + true: 50 + + episode4: + # Thy Flesh Consumed. + # If none of the episodes are chosen, Episode 1 will be chosen by default. + # This episode is very difficult. + false: 0 + true: 50 diff --git a/disabled yamls/Stardew Valley.yaml b/disabled yamls/Stardew Valley.yaml new file mode 100644 index 000000000000..62fcf783d4a6 --- /dev/null +++ b/disabled yamls/Stardew Valley.yaml @@ -0,0 +1,469 @@ +# Q. What is this file? +# A. This file contains options which allow you to configure your multiworld experience while allowing +# others to play how they want as well. +# +# Q. How do I use it? +# A. The options in this file are weighted. This means the higher number you assign to a value, the +# more chances you have for that option to be chosen. For example, an option like this: +# +# map_shuffle: +# on: 5 +# off: 15 +# +# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned +# off. +# +# Q. I've never seen a file like this before. What characters am I allowed to use? +# A. This is a .yaml file. You are allowed to use most characters. +# To test if your yaml is valid or not, you can use this website: +# http://www.yamllint.com/ +# You can also verify your Archipelago settings are valid at this site: +# https://archipelago.gg/check + +# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. +# {player} will be replaced with the player's slot number. +# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. +# {number} will be replaced with the counter value of the name. +# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. +name: Player{number} + +# Used to describe your yaml. Useful if you have multiple files. +description: Default Stardew Valley Template + +game: Stardew Valley +requires: + version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. + +Stardew Valley: + progression_balancing: + # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. + # A lower setting means more getting stuck. A higher setting means less getting stuck. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 99 + random: 0 + random-low: 0 + random-high: 0 + disabled: 0 # equivalent to 0 + normal: 50 # equivalent to 50 + extreme: 0 # equivalent to 99 + + accessibility: + # Set rules for reachability of your items/locations. + # Locations: ensure everything can be reached and acquired. + # Items: ensure all logically relevant items can be acquired. + # Minimal: ensure what is needed to reach your goal can be acquired. + locations: 0 + items: 50 + minimal: 0 + + local_items: + # Forces these items to be in their native world. + [] + + non_local_items: + # Forces these items to be outside their native world. + [] + + start_inventory: + # Start with these items. + {} + + start_hints: + # Start with these item's locations prefilled into the !hint command. + [] + + start_location_hints: + # Start with these locations and their item prefilled into the !hint command + [] + + exclude_locations: + # Prevent these locations from having an important item + [] + + priority_locations: + # Prevent these locations from having an unimportant item + [] + + goal: + # What's your goal with this play-through? + # Community Center: The world will be completed once you complete the Community Center. + # Grandpa's Evaluation: The world will be completed once 4 candles are lit at Grandpa's Shrine. + # Bottom of the Mines: The world will be completed once you reach level 120 in the mineshaft. + # Cryptic Note: The world will be completed once you complete the quest "Cryptic Note" where Mr Qi asks you to reach floor 100 in the Skull Cavern. + # Master Angler: The world will be completed once you have caught every fish in the game. Pairs well with Fishsanity. + # Complete Collection: The world will be completed once you have completed the museum by donating every possible item. Pairs well with Museumsanity. + # Full House: The world will be completed once you get married and have two kids. Pairs well with Friendsanity. + # Greatest Walnut Hunter: The world will be completed once you find all 130 Golden Walnuts + # Perfection: The world will be completed once you attain Perfection, based on the vanilla definition. + community_center: 50 + grandpa_evaluation: 0 + bottom_of_the_mines: 0 + cryptic_note: 0 + master_angler: 0 + complete_collection: 0 + full_house: 0 + greatest_walnut_hunter: 0 + perfection: 0 + + starting_money: + # Amount of gold when arriving at the farm. + # Set to -1 or unlimited for infinite money in this playthrough + # + # You can define additional values between the minimum and maximum values. + # Minimum value is -1 + # Maximum value is 50000 + random: 0 + random-low: 0 + random-high: 0 + unlimited: 0 # equivalent to -1 + vanilla: 0 # equivalent to 500 + extra: 0 # equivalent to 2000 + rich: 50 # equivalent to 5000 + very rich: 0 # equivalent to 20000 + filthy rich: 0 # equivalent to 50000 + + profit_margin: + # Multiplier over all gold earned in-game by the player. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 400 + random: 0 + random-low: 0 + random-high: 0 + quarter: 0 # equivalent to 25 + half: 0 # equivalent to 50 + normal: 50 # equivalent to 100 + double: 0 # equivalent to 200 + triple: 0 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + bundle_randomization: + # What items are needed for the community center bundles? + # Vanilla: Standard bundles from the vanilla game + # Thematic: Every bundle will require random items compatible with their original theme + # Shuffled: Every bundle will require random items and follow no particular structure + vanilla: 0 + thematic: 50 + shuffled: 0 + + bundle_price: + # How many items are needed for the community center bundles? + # Very Cheap: Every bundle will require 2 items fewer than usual + # Cheap: Every bundle will require 1 item fewer than usual + # Normal: Every bundle will require the vanilla number of items + # Expensive: Every bundle will require 1 extra item when applicable + very_cheap: 0 + cheap: 0 + normal: 50 + expensive: 0 + + entrance_randomization: + # Should area entrances be randomized? + # Disabled: No entrance randomization is done + # Pelican Town: Only buildings in the main town area are randomized among each other + # Non Progression: Only buildings that are always available are randomized with each other + # Buildings: All Entrances that Allow you to enter a building using a door are randomized with each other + # Chaos: Same as above, but the entrances get reshuffled every single day! + disabled: 0 + pelican_town: 0 + non_progression: 0 + buildings: 50 + chaos: 0 + + season_randomization: + # Should seasons be randomized? + # All settings allow you to choose which season you want to play next (from those unlocked) at the end of a season. + # Disabled: You will start in Spring with all seasons unlocked. + # Randomized: The seasons will be unlocked randomly as Archipelago items. + # Randomized Not Winter: The seasons are randomized, but you're guaranteed not to start with winter. + # Progressive: You will start in Spring and unlock the seasons in their original order. + disabled: 0 + randomized: 50 + randomized_not_winter: 0 + progressive: 0 + + cropsanity: + # Formerly named "Seed Shuffle" + # Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. + # Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops + # Shuffled: Seeds are unlocked as archipelago item, for each seed there is a location check for growing and harvesting that crop + disabled: 50 + shuffled: 50 + + backpack_progression: + # How is the backpack progression handled? + # Vanilla: You can buy them at Pierre's General Store. + # Progressive: You will randomly find Progressive Backpack upgrades. + # Early Progressive: You can expect your first Backpack in sphere 1. + vanilla: 0 + progressive: 0 + early_progressive: 50 + + tool_progression: + # How is the tool progression handled? + # Vanilla: Clint will upgrade your tools with ore. + # Progressive: You will randomly find Progressive Tool upgrades. + vanilla: 0 + progressive: 50 + + skill_progression: + # How is the skill progression handled? + # Vanilla: You will level up and get the normal reward at each level. + # Progressive: The xp will be earned internally, locations will be sent when you earn a level. Your real + # levels will be scattered around the multiworld. + vanilla: 0 + progressive: 50 + + building_progression: + # How is the building progression handled? + # Vanilla: You will buy each building normally. + # Progressive: You will receive the buildings and will be able to build the first one of each type for free, + # once it is received. If you want more of the same building, it will cost the vanilla price. + # Progressive early shipping bin: You can expect your shipping bin in sphere 1. + vanilla: 0 + progressive: 0 + progressive_early_shipping_bin: 50 + + festival_locations: + # Locations for attending and participating in festivals + # With Disabled, you do not need to attend festivals + # With Easy, there are checks for participating in festivals + # With Hard, the festival checks are only granted when the player performs well in the festival + disabled: 50 + easy: 0 + hard: 0 + + elevator_progression: + # How is Elevator progression handled? + # Vanilla: You will unlock new elevator floors for yourself. + # Progressive: You will randomly find Progressive Mine Elevators to go deeper. Locations are sent for reaching + # every elevator level. + # Progressive from previous floor: Same as progressive, but you must reach elevator floors on your own, + # you cannot use the elevator to check elevator locations + vanilla: 0 + progressive: 0 + progressive_from_previous_floor: 50 + + arcade_machine_locations: + # How are the Arcade Machines handled? + # Disabled: The arcade machines are not included in the Archipelago shuffling. + # Victories: Each Arcade Machine will contain one check on victory + # Victories Easy: The arcade machines are both made considerably easier to be more accessible for the average + # player. + # Full Shuffling: The arcade machines will contain multiple checks each, and different buffs that make the game + # easier are in the item pool. Junimo Kart has one check at the end of each level. + # Journey of the Prairie King has one check after each boss, plus one check for each vendor equipment. + disabled: 0 + victories: 0 + victories_easy: 0 + full_shuffling: 50 + + special_order_locations: + # How are the Special Orders handled? + # Disabled: The special orders are not included in the Archipelago shuffling. + # Board Only: The Special Orders on the board in town are location checks + # Board and Qi: The Special Orders from Qi's walnut room are checks, as well as the board in town + disabled: 0 + board_only: 00 + board_qi: 50 + + help_wanted_locations: + # How many "Help Wanted" quests need to be completed as Archipelago Locations + # Out of every 7 quests, 4 will be item deliveries, and then 1 of each for: Fishing, Gathering and Slaying Monsters. + # Choosing a multiple of 7 is recommended. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 56 + random: 0 + random-low: 0 + random-high: 0 + none: 0 # equivalent to 0 + minimum: 0 # equivalent to 7 + normal: 0 # equivalent to 14 + lots: 0 # equivalent to 28 + maximum: 50 # equivalent to 56 + + fishsanity: + # Locations for catching fish? + # None: There are no locations for catching fish + # Legendaries: Each of the 5 legendary fish are checks + # Special: A curated selection of strong fish are checks + # Randomized: A random selection of fish are checks + # All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal + # Exclude Legendaries: Every fish except legendaries + # Exclude Hard Fish: Every fish under difficulty 80 + # Only Easy Fish: Every fish under difficulty 50 + none: 0 + legendaries: 0 + special: 0 + randomized: 0 + all: 50 + exclude_legendaries: 0 + exclude_hard_fish: 0 + only_easy_fish: 0 + + museumsanity: + # Locations for museum donations? + # None: There are no locations for donating artifacts and minerals to the museum + # Milestones: The donation milestones from the vanilla game are checks + # Randomized: A random selection of minerals and artifacts are checks + # All: Every single donation will be a check + none: 0 + milestones: 0 + randomized: 0 + all: 50 + + friendsanity: + # Locations for friendships? + # None: There are no checks for befriending villagers + # Bachelors: Each heart of a bachelor is a check + # Starting NPCs: Each heart for npcs that are immediately available is a check + # All: Every heart with every NPC is a check, including Leo, Kent, Sandy, etc + # All With Marriage: Marriage candidates must also be dated, married, and befriended up to 14 hearts. + none: 0 + bachelors: 0 + starting_npcs: 0 + all: 50 + all_with_marriage: 0 + + friendsanity_heart_size: + # If using friendsanity, how many hearts are received per item, and how many hearts must be earned to send a check + # A higher value will lead to fewer heart items in the item pool, reducing bloat + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 1 + # Maximum value is 8 + 2: 50 + random: 0 + random-low: 0 + random-high: 0 + + movement_buff_number: + # Number of movement speed buffs to the player that exist as items in the pool. + # Each movement speed buff is a +25% multiplier that stacks additively + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 12 + 4: 0 + random: 0 + random-low: 0 + random-high: 20 + + luck_buff_number: + # Number of luck buffs to the player that exist as items in the pool. + # Each luck buff is a bonus to daily luck of 0.025 + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 12 + 4: 0 + random: 0 + random-low: 0 + random-high: 50 + + exclude_ginger_island: + # Exclude Ginger Island? + # This option will forcefully exclude everything related to Ginger Island from the slot. + # If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway + false: 50 + true: 0 + + trap_items: + # When rolling filler items, including resource packs, the game can also roll trap items. + # This setting is for choosing if traps will be in the item pool, and if so, how punishing they will be. + no_traps: 0 + easy: 0 + medium: 50 + hard: 0 + hell: 0 + nightmare: 0 + + multiple_day_sleep_enabled: + # Enable the ability to sleep automatically for multiple days straight? + false: 0 + true: 50 + + multiple_day_sleep_cost: + # How much gold it will cost to use MultiSleep. You will have to pay that amount for each day skipped. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 0 + # Maximum value is 200 + random: 0 + random-low: 0 + random-high: 0 + free: 50 # equivalent to 0 + cheap: 0 # equivalent to 25 + medium: 0 # equivalent to 50 + expensive: 0 # equivalent to 100 + + experience_multiplier: + # How fast you want to earn skill experience. A lower setting mean less experience. + # A higher setting means more experience. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 800 + random: 0 + random-low: 0 + random-high: 0 + half: 0 # equivalent to 50 + vanilla: 0 # equivalent to 100 + double: 50 # equivalent to 200 + triple: 0 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + friendship_multiplier: + # How fast you want to earn friendship points with villagers. + # A lower setting mean less friendship per action. + # A higher setting means more friendship per action. + # + # You can define additional values between the minimum and maximum values. + # Minimum value is 25 + # Maximum value is 800 + random: 0 + random-low: 0 + random-high: 0 + half: 0 # equivalent to 50 + vanilla: 0 # equivalent to 100 + double: 50 # equivalent to 200 + triple: 0 # equivalent to 300 + quadruple: 0 # equivalent to 400 + + debris_multiplier: + # How much debris will spawn on the player's farm? + # Vanilla: debris spawns normally + # Half: debris will spawn at half the normal rate + # Quarter: debris will spawn at one quarter of the normal rate + # None: No debris will spawn on the farm, ever + # Start Clear: debris will spawn at the normal rate, but the farm will be completely clear when starting the game + vanilla: 0 + half: 50 + quarter: 0 + none: 0 + start_clear: 0 + + quick_start: + # Do you want the quick start package? You will get a few items to help early game automation, + # so you can use the multiple day sleep at its maximum. + false: 0 + true: 50 + + gifting: + # Do you want to enable gifting items to and from other Stardew Valley worlds? + false: 0 + true: 50 + + mods: + # List of mods that will be considered for shuffling. + [] + + death_link: + # When you die, everyone dies. Of course the reverse is true too. + false: 50 + true: 0 diff --git a/disabled yamls/Stardew allsanity.yaml b/disabled yamls/Stardew allsanity.yaml new file mode 100644 index 000000000000..343dfce67def --- /dev/null +++ b/disabled yamls/Stardew allsanity.yaml @@ -0,0 +1,39 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: items + goal: perfection + starting_money: random + profit_margin: 200 + bundle_randomization: shuffled + bundle_price: expensive + entrance_randomization: chaos + season_randomization: randomized + cropsanity: shuffled + backpack_progression: progressive + tool_progression: progressive + skill_progression: progressive + building_progression: progressive + festival_locations: hard + arcade_machine_locations: full_shuffling + special_order_locations: board_qi + help_wanted_locations: 56 + fishsanity: all + museumsanity: all + friendsanity: all_with_marriage + friendsanity_heart_size: 1 + player_buff_number: 12 + exclude_ginger_island: 'false' + trap_items: nightmare + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 200 + friendship_multiplier: 200 + debris_multiplier: half + quick_start: 'true' + gifting: 'true' + gift_tax: 20 + mods: ["DeepWoods", "Tractor Mod", "Bigger Backpack", "Luck Skill", "Magic", "Socializing Skill", "Archaeology", "Cooking Skill", "Binning Skill", "Juna - Roommate NPC", "Professor Jasper Thomas", "Alec Revisited", "Custom NPC - Yoba", "Custom NPC Eugene", "'Prophet' Wellwick", "Mister Ginger (cat npc)", "Shiko - New Custom NPC", "Delores - Custom NPC", "Ayeisha - The Postal Worker (Custom NPC)"] + death_link: 'true' +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: MyName \ No newline at end of file diff --git a/disabled yamls/StardewRace.yaml b/disabled yamls/StardewRace.yaml new file mode 100644 index 000000000000..2e3f89b9409d --- /dev/null +++ b/disabled yamls/StardewRace.yaml @@ -0,0 +1,42 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: items + goal: community_center + starting_money: rich + profit_margin: 100 + bundle_randomization: thematic + bundle_price: cheap + entrance_randomization: disabled + season_randomization: randomized + cropsanity: shuffled + backpack_progression: early_progressive + tool_progression: progressive + elevator_progression: progressive + skill_progression: progressive + building_progression: progressive + festival_locations: easy + arcade_machine_locations: disabled + special_order_locations: disabled + help_wanted_locations: 0 + fishsanity: none + museumsanity: none + friendsanity: none + friendsanity_heart_size: 4 + movement_buff_number: 4 + luck_buff_number: 4 + exclude_ginger_island: 'true' + trap_items: medium + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 400 + friendship_multiplier: 400 + debris_multiplier: quarter + quick_start: 'true' + gifting: 'true' + mods: [] + start_hints: + [] + death_link: 'true' +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: StardewRacer \ No newline at end of file diff --git a/disabled yamls/StardewTester.yaml b/disabled yamls/StardewTester.yaml new file mode 100644 index 000000000000..11d2b4c54abc --- /dev/null +++ b/disabled yamls/StardewTester.yaml @@ -0,0 +1,48 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: items + goal: community_center + starting_money: rich + profit_margin: 400 + bundle_randomization: thematic + bundle_price: very_cheap + entrance_randomization: disabled + season_randomization: randomized + cropsanity: shuffled + backpack_progression: early_progressive + tool_progression: progressive_very_cheap + elevator_progression: progressive + skill_progression: progressive + building_progression: progressive_very_cheap + festival_locations: easy + arcade_machine_locations: disabled + special_order_locations: disabled + help_wanted_locations: 0 + fishsanity: none + museumsanity: none + monstersanity: one_per_category + shipsanity: everything + cooksanity: all + chefsanity: all + friendsanity: none + friendsanity_heart_size: 4 + movement_buff_number: 4 + luck_buff_number: 4 + exclude_ginger_island: 'true' + trap_items: medium + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 800 + friendship_multiplier: 800 + debris_multiplier: quarter + quick_start: 'true' + gifting: 'true' + mods: [] + start_inventory: + Return Scepter: 1 + Movement Speed Bonus: 4 + "Adventurer's Guild": 1 + death_link: 'true' +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: Tester \ No newline at end of file diff --git a/disabled yamls/Stardew_Valley.yaml b/disabled yamls/Stardew_Valley.yaml new file mode 100644 index 000000000000..dd25859ee9e5 --- /dev/null +++ b/disabled yamls/Stardew_Valley.yaml @@ -0,0 +1,41 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: locations + goal: perfection + starting_money: -1 + profit_margin: 200 + bundle_randomization: thematic + bundle_price: very_cheap + entrance_randomization: buildings + season_randomization: randomized + cropsanity: shuffled + backpack_progression: early_progressive + tool_progression: progressive + skill_progression: progressive + building_progression: progressive_early_shipping_bin + festival_locations: hard + elevator_progression: progressive + arcade_machine_locations: disabled + special_order_locations: board_qi + help_wanted_locations: 0 + fishsanity: only_easy_fish + museumsanity: none + friendsanity: all_with_marriage + friendsanity_heart_size: 4 + movement_buff_number: 4 + luck_buff_number: 4 + exclude_ginger_island: 'false' + trap_items: nightmare + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 800 + friendship_multiplier: 800 + debris_multiplier: none + quick_start: 'true' + gifting: 'true' + death_link: 'false' + start_inventory: + {"Movement Speed Bonus": 4} +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: Tester diff --git a/disabled yamls/Tester - 3.x.x.yaml b/disabled yamls/Tester - 3.x.x.yaml new file mode 100644 index 000000000000..aad69a26b96a --- /dev/null +++ b/disabled yamls/Tester - 3.x.x.yaml @@ -0,0 +1,34 @@ +Stardew Valley: + progression_balancing: 50 + accessibility: items + goal: community_center + starting_money: 5000 + resource_pack_multiplier: 100 + bundle_randomization: thematic + bundle_price: normal + entrance_randomization: disabled + season_randomization: randomized + cropsanity: shuffled + backpack_progression: early_progressive + tool_progression: progressive + skill_progression: progressive + building_progression: progressive_early_shipping_bin + elevator_progression: progressive_from_previous_floor + arcade_machine_locations: full_shuffling + help_wanted_locations: 7 + fishsanity: none + museumsanity: milestones + friendsanity: all + player_buff_number: 4 + multiple_day_sleep_enabled: 'true' + multiple_day_sleep_cost: 0 + experience_multiplier: 200 + friendship_multiplier: 200 + debris_multiplier: half + quick_start: 'true' + gifting: 'true' + gift_tax: 20 + death_link: 'false' +description: 'Generated by https://archipelago.gg/' +game: Stardew Valley +name: Tester diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index e1a4ae56405f..12e9a330fe03 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -180,7 +180,7 @@ def setup_month_events(self): self.create_event_location(month_end, True_(), Event.month_end) continue - self.create_event_location(month_end, self.logic.received(Event.month_end, i).simplify(), Event.month_end) + self.create_event_location(month_end, self.logic.received(Event.month_end, i), Event.month_end) def setup_construction_events(self): can_construct_buildings = LocationData(None, "Carpenter Shop", Event.can_construct_buildings) @@ -189,11 +189,11 @@ def setup_construction_events(self): def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], - self.logic.bundle.can_complete_community_center().simplify(), + self.logic.bundle.can_complete_community_center(), Event.victory) elif self.options.goal == Goal.option_grandpa_evaluation: self.create_event_location(location_table[GoalName.grandpa_evaluation], - self.logic.can_finish_grandpa_evaluation().simplify(), + self.logic.can_finish_grandpa_evaluation(), Event.victory) elif self.options.goal == Goal.option_bottom_of_the_mines: self.create_event_location(location_table[GoalName.bottom_of_the_mines], @@ -201,39 +201,39 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_cryptic_note: self.create_event_location(location_table[GoalName.cryptic_note], - self.logic.quest.can_complete_quest("Cryptic Note").simplify(), + self.logic.quest.can_complete_quest("Cryptic Note"), Event.victory) elif self.options.goal == Goal.option_master_angler: self.create_event_location(location_table[GoalName.master_angler], - self.logic.can_catch_every_fish().simplify(), + self.logic.can_catch_every_fish(), Event.victory) elif self.options.goal == Goal.option_complete_collection: self.create_event_location(location_table[GoalName.complete_museum], - self.logic.museum.can_complete_museum().simplify(), + self.logic.museum.can_complete_museum(), Event.victory) elif self.options.goal == Goal.option_full_house: self.create_event_location(location_table[GoalName.full_house], - (self.logic.relationship.has_children(2) & self.logic.relationship.can_reproduce()).simplify(), + (self.logic.relationship.has_children(2) & self.logic.relationship.can_reproduce()), Event.victory) elif self.options.goal == Goal.option_greatest_walnut_hunter: self.create_event_location(location_table[GoalName.greatest_walnut_hunter], - self.logic.has_walnut(130).simplify(), + self.logic.has_walnut(130), Event.victory) elif self.options.goal == options.Goal.option_protector_of_the_valley: self.create_event_location(location_table[GoalName.protector_of_the_valley], - self.logic.can_complete_all_monster_slaying_goals().simplify(), + self.logic.can_complete_all_monster_slaying_goals(), Event.victory) elif self.options.goal == options.Goal.option_full_shipment: self.create_event_location(location_table[GoalName.full_shipment], - self.logic.shipping.can_ship_everything().simplify(), + self.logic.shipping.can_ship_everything(), Event.victory) elif self.options.goal == options.Goal.option_gourmet_chef: self.create_event_location(location_table[GoalName.gourmet_chef], - self.logic.cooking.can_cook_everything().simplify(), + self.logic.cooking.can_cook_everything(), Event.victory) elif self.options.goal == options.Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], - self.logic.has_everything(self.all_progression_items).simplify(), + self.logic.has_everything(self.all_progression_items), Event.victory) self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player) diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index ed0fc5f22496..b53a8d396bf7 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -58,7 +58,7 @@ def can_catch_fish(self, fish: FishItem) -> StardewRule: if fish.difficulty == -1: difficulty_rule = self.skill.can_crab_pot() else: - difficulty_rule = self.skill.can_fish([], 120 if fish.legendary else fish.difficulty) + difficulty_rule = self.skill.can_fish(difficulty=(120 if fish.legendary else fish.difficulty)) if fish.name == SVEFish.kittyfish: item_rule = self.received("Kittyfish Spell") else: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index cfdc44d6bdb2..7432c24b7ac1 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -78,13 +78,13 @@ def set_rules(world): def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.add_rule(multiworld.get_location("Old Master Cannoli", player), - logic.has("Sweet Gem Berry").simplify()) + logic.has("Sweet Gem Berry")) MultiWorldRules.add_rule(multiworld.get_location("Galaxy Sword Shrine", player), - logic.has("Prismatic Shard").simplify()) + logic.has("Prismatic Shard")) MultiWorldRules.add_rule(multiworld.get_location("Have a Baby", player), - logic.relationship.can_reproduce(1).simplify()) + logic.relationship.can_reproduce(1)) MultiWorldRules.add_rule(multiworld.get_location("Have Another Baby", player), - logic.relationship.can_reproduce(2).simplify()) + logic.relationship.can_reproduce(2)) def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -92,9 +92,9 @@ def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: Stard return MultiWorldRules.add_rule(multiworld.get_location("Purchase Fiberglass Rod", player), - (logic.skill.has_level(Skill.fishing, 2) & logic.money.can_spend(1800)).simplify()) + (logic.skill.has_level(Skill.fishing, 2) & logic.money.can_spend(1800))) MultiWorldRules.add_rule(multiworld.get_location("Purchase Iridium Rod", player), - (logic.skill.has_level(Skill.fishing, 6) & logic.money.can_spend(7500)).simplify()) + (logic.skill.has_level(Skill.fishing, 6) & logic.money.can_spend(7500))) materials = [None, "Copper", "Iron", "Gold", "Iridium"] tool = [Tool.hoe, Tool.pickaxe, Tool.axe, Tool.watering_can, Tool.watering_can, Tool.trash_can] @@ -102,7 +102,7 @@ def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: Stard if previous is None: continue tool_upgrade_location = multiworld.get_location(f"{material} {tool} Upgrade", player) - MultiWorldRules.set_rule(tool_upgrade_location, logic.tool.has_tool(tool, previous).simplify()) + MultiWorldRules.set_rule(tool_upgrade_location, logic.tool.has_tool(tool, previous)) def set_building_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -113,34 +113,34 @@ def set_building_rules(logic: StardewLogic, multiworld, player, world_options: S if building.mod_name is not None and building.mod_name not in world_options.mods: continue MultiWorldRules.set_rule(multiworld.get_location(building.name, player), - logic.buildings.building_rules[building.name.replace(" Blueprint", "")].simplify()) + logic.buildings.building_rules[building.name.replace(" Blueprint", "")]) def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): for bundle in current_bundles.values(): location = multiworld.get_location(bundle.get_name_with_bundle(), player) rules = logic.bundle.can_complete_bundle(bundle.requirements, bundle.number_required) - simplified_rules = rules.simplify() + simplified_rules = rules MultiWorldRules.set_rule(location, simplified_rules) MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), - And(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]).simplify()) + And(*(logic.region.can_reach_location(bundle.name) + for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), - And(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]).simplify()) + And(*(logic.region.can_reach_location(bundle.name) + for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), - And(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]).simplify()) + And(*(logic.region.can_reach_location(bundle.name) + for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), - And(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]).simplify()) + And(*(logic.region.can_reach_location(bundle.name) + for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), And(logic.region.can_reach_location(bundle.name) for bundle - in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]).simplify()) + in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), - And(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]).simplify()) + And(*(logic.region.can_reach_location(bundle.name) + for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]))) def set_skills_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -181,13 +181,13 @@ def get_skill_level_location(multiworld, player, skill: str, level: int): def set_vanilla_skill_rule(logic: StardewLogic, multiworld, player, skill: str, level: int): - rule = logic.skill.can_earn_level(skill, level).simplify() - MultiWorldRules.set_rule(get_skill_level_location(multiworld, player, skill, level), rule.simplify()) + rule = logic.skill.can_earn_level(skill, level) + MultiWorldRules.set_rule(get_skill_level_location(multiworld, player, skill, level), rule) def set_modded_skill_rule(logic: StardewLogic, multiworld, player, skill: str, level: int): - rule = logic.mod.skill.can_earn_mod_skill_level(skill, level).simplify() - MultiWorldRules.set_rule(get_skill_level_location(multiworld, player, skill, level), rule.simplify()) + rule = logic.mod.skill.can_earn_mod_skill_level(skill, level) + MultiWorldRules.set_rule(get_skill_level_location(multiworld, player, skill, level), rule) def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -199,35 +199,35 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S dangerous_mine_rule = logic.mine.has_mine_elevator_to_floor(120) & logic.region.can_reach(Region.qi_walnut_room) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_20, player), - dangerous_mine_rule.simplify()) + dangerous_mine_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_60, player), - dangerous_mine_rule.simplify()) + dangerous_mine_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_100, player), - dangerous_mine_rule.simplify()) + dangerous_mine_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), - logic.received("Beach Bridge") | (logic.mod.magic.can_blink()).simplify()) + logic.received("Beach Bridge") | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), - logic.received("Bridge Repair") | (logic.mod.magic.can_blink()).simplify()) + logic.received("Bridge Repair") | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), - logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink()).simplify()) + logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), - logic.wallet.has_rusty_key().simplify()) + logic.wallet.has_rusty_key()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), - logic.wallet.has_rusty_key().simplify()) + logic.wallet.has_rusty_key()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_abandoned_jojamart, player), - logic.has_abandoned_jojamart().simplify()) - movie_theater_rule = logic.has_movie_theater().simplify() + logic.has_abandoned_jojamart()) + movie_theater_rule = logic.has_movie_theater() MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_movie_theater, player), movie_theater_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.purchase_movie_ticket, player), movie_theater_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.take_bus_to_desert, player), - logic.received("Bus Repair").simplify()) + logic.received("Bus Repair")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_skull_cavern, player), - logic.received(Wallet.skull_key).simplify()) + logic.received(Wallet.skull_key)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_dangerous_skull_cavern, player), - (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room)).simplify()) + (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), @@ -239,21 +239,21 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), logic.time.has_lived_months(2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), - logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink()).simplify()) + logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), - (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink()).simplify()) + (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), ((logic.wallet.has_rusty_key() & logic.region.can_reach(Region.railroad) & - logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()).simplify())) + logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), logic.received("Club Card")) set_bedroom_entrance_rules(logic, multiworld, player, world_options) set_festival_entrance_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen().simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin().simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce)) def set_adventure_guild_entrance_rules(logic, multiworld, player, world_options): @@ -265,9 +265,9 @@ def set_adventure_guild_entrance_rules(logic, multiworld, player, world_options) def set_farm_buildings_entrance_rules(logic, multiworld, player): - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk).simplify()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_coop, player), logic.buildings.has_building(Building.coop)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_barn, player), logic.buildings.has_building(Building.barn)) @@ -278,14 +278,14 @@ def set_farm_buildings_entrance_rules(logic, multiworld, player): def set_bedroom_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink()).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) if ModNames.alec in world_options.mods: - MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink()).simplify()) + MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink())) def set_mines_floor_entrance_rules(logic, multiworld, player): @@ -294,7 +294,7 @@ def set_mines_floor_entrance_rules(logic, multiworld, player): if floor == 5 or floor == 45 or floor == 85: rule = rule & logic.mine.can_progress_in_the_mines_from_floor(floor) entrance = multiworld.get_entrance(dig_to_mines_floor(floor), player) - MultiWorldRules.set_rule(entrance, rule.simplify()) + MultiWorldRules.set_rule(entrance, rule) def set_skull_cavern_floor_entrance_rules(logic, multiworld, player): @@ -303,7 +303,7 @@ def set_skull_cavern_floor_entrance_rules(logic, multiworld, player): if floor == 25 or floor == 75 or floor == 125: rule = rule & logic.mine.can_progress_in_the_skull_cavern_from_floor(floor) entrance = multiworld.get_entrance(dig_to_skull_floor(floor), player) - MultiWorldRules.set_rule(entrance, rule.simplify()) + MultiWorldRules.set_rule(entrance, rule) def set_blacksmith_entrance_rules(logic, multiworld, player): @@ -315,15 +315,15 @@ def set_blacksmith_entrance_rules(logic, multiworld, player): def set_skill_entrance_rules(logic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), - logic.skill.can_get_farming_xp().simplify()) + logic.skill.can_get_farming_xp()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fishing, player), - logic.skill.can_get_fishing_xp().simplify()) + logic.skill.can_get_fishing_xp()) def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, item_name: str, tool_material: str): material_entrance = multiworld.get_entrance(entrance_name, player) upgrade_rule = logic.has(item_name) & logic.money.can_spend(tool_upgrade_prices[tool_material]) - MultiWorldRules.set_rule(material_entrance, upgrade_rule.simplify()) + MultiWorldRules.set_rule(material_entrance, upgrade_rule) def set_festival_entrance_rules(logic, multiworld, player): @@ -349,64 +349,64 @@ def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_optio set_boat_repair_rules(logic, multiworld, player) set_island_parrot_rules(logic, multiworld, player) MultiWorldRules.add_rule(multiworld.get_location("Open Professor Snail Cave", player), - logic.has(Bomb.cherry_bomb).simplify()) + logic.has(Bomb.cherry_bomb)) MultiWorldRules.add_rule(multiworld.get_location("Complete Island Field Office", player), - logic.can_complete_field_office().simplify()) + logic.can_complete_field_office()) def set_boat_repair_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.add_rule(multiworld.get_location("Repair Boat Hull", player), - logic.has(Material.hardwood).simplify()) + logic.has(Material.hardwood)) MultiWorldRules.add_rule(multiworld.get_location("Repair Boat Anchor", player), - logic.has(MetalBar.iridium).simplify()) + logic.has(MetalBar.iridium)) MultiWorldRules.add_rule(multiworld.get_location("Repair Ticket Machine", player), - logic.has(ArtisanGood.battery_pack).simplify()) + logic.has(ArtisanGood.battery_pack)) def set_island_entrances_rules(logic: StardewLogic, multiworld, player): - boat_repaired = logic.received(Transportation.boat_repair).simplify() + boat_repaired = logic.received(Transportation.boat_repair) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fish_shop_to_boat_tunnel, player), boat_repaired) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.boat_to_ginger_island, player), boat_repaired) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_west, player), - logic.received("Island West Turtle").simplify()) + logic.received("Island West Turtle")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_north, player), - logic.received("Island North Turtle").simplify()) + logic.received("Island North Turtle")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_islandfarmhouse, player), - logic.received("Island Farmhouse").simplify()) + logic.received("Island Farmhouse")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_gourmand_cave, player), - logic.received("Island Farmhouse").simplify()) - dig_site_rule = logic.received("Dig Site Bridge").simplify() + logic.received("Island Farmhouse")) + dig_site_rule = logic.received("Dig Site Bridge") MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_dig_site, player), dig_site_rule) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), - logic.received("Open Professor Snail Cave").simplify()) + logic.received("Open Professor Snail Cave")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_island_trader, player), - logic.received("Island Trader").simplify()) + logic.received("Island Trader")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_southeast, player), - logic.received("Island Resort").simplify()) + logic.received("Island Resort")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_resort, player), - logic.received("Island Resort").simplify()) + logic.received("Island Resort")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_qi_walnut_room, player), - logic.received("Qi Walnut Room").simplify()) + logic.received("Qi Walnut Room")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_volcano, player), (logic.tool.can_water(0) | logic.received("Volcano Bridge") | - logic.mod.magic.can_blink()).simplify()) + logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.volcano_to_secret_beach, player), - logic.tool.can_water(2).simplify()) + logic.tool.can_water(2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), - (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) + (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), logic.wallet.can_speak_dwarf()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), - (logic.ability.can_mine_perfectly() & logic.tool.can_water(1)).simplify()) + (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_docks_to_dig_site, Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_volcano_to_dig_site, Entrance.parrot_express_docks_to_jungle, Entrance.parrot_express_dig_site_to_jungle, Entrance.parrot_express_volcano_to_jungle, Entrance.parrot_express_jungle_to_docks, Entrance.parrot_express_dig_site_to_docks, Entrance.parrot_express_volcano_to_docks] - parrot_express_rule = logic.received(Transportation.parrot_express).simplify() + parrot_express_rule = logic.received(Transportation.parrot_express) parrot_express_to_dig_site_rule = dig_site_rule & parrot_express_rule for parrot in parrots: if "Dig Site" in parrot: @@ -416,10 +416,10 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): def set_island_parrot_rules(logic: StardewLogic, multiworld, player): - has_walnut = logic.has_walnut(1).simplify() - has_5_walnut = logic.has_walnut(5).simplify() - has_10_walnut = logic.has_walnut(10).simplify() - has_20_walnut = logic.has_walnut(20).simplify() + has_walnut = logic.has_walnut(1) + has_5_walnut = logic.has_walnut(5) + has_10_walnut = logic.has_walnut(10) + has_20_walnut = logic.has_walnut(20) MultiWorldRules.add_rule(multiworld.get_location("Leo's Parrot", player), has_walnut) MultiWorldRules.add_rule(multiworld.get_location("Island West Turtle", player), @@ -455,14 +455,14 @@ def set_cropsanity_rules(all_location_names: List[str], logic: StardewLogic, mul if harvest_location.name in all_location_names and (harvest_location.mod_name is None or harvest_location.mod_name in world_options.mods): crop_name = harvest_location.name[harvest_prefix_length:] MultiWorldRules.set_rule(multiworld.get_location(harvest_location.name, player), - logic.has(crop_name).simplify()) + logic.has(crop_name)) def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): for quest in locations.locations_by_tag[LocationTags.QUEST]: if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options.mods): MultiWorldRules.set_rule(multiworld.get_location(quest.name, player), - logic.quest.quest_rules[quest.name].simplify()) + logic.quest.quest_rules[quest.name]) def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, @@ -473,7 +473,7 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, for board_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD]: if board_order.name in all_location_names: order_rule = board_rule & logic.special_order.special_order_rules[board_order.name] - MultiWorldRules.set_rule(multiworld.get_location(board_order.name, player), order_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(board_order.name, player), order_rule) if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return @@ -483,7 +483,7 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, for qi_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_QI]: if qi_order.name in all_location_names: order_rule = qi_rule & logic.special_order.special_order_rules[qi_order.name] - MultiWorldRules.set_rule(multiworld.get_location(qi_order.name, player), order_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(qi_order.name, player), order_rule) help_wanted_prefix = "Help Wanted:" @@ -497,7 +497,7 @@ def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_ help_wanted_number = world_options.help_wanted_locations.value for i in range(0, help_wanted_number): set_number = i // 7 - month_rule = logic.time.has_lived_months(set_number).simplify() + month_rule = logic.time.has_lived_months(set_number) quest_number = set_number + 1 quest_number_in_set = i % 7 if quest_number_in_set < 4: @@ -523,12 +523,12 @@ def set_help_wanted_gathering_rule(multiworld, player, month_rule, quest_number) def set_help_wanted_fishing_rule(multiworld, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {fishing} {quest_number}" - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) def set_help_wanted_slay_monsters_rule(multiworld, player, month_rule, quest_number): location_name = f"{help_wanted_prefix} {slay_monsters} {quest_number}" - MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(location_name, player), month_rule) def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): @@ -537,7 +537,7 @@ def set_fishsanity_rules(all_location_names: List[str], logic: StardewLogic, mul if fish_location.name in all_location_names: fish_name = fish_location.name[len(fish_prefix):] MultiWorldRules.set_rule(multiworld.get_location(fish_location.name, player), - logic.has(fish_name).simplify()) + logic.has(fish_name)) def set_museumsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int, @@ -561,7 +561,7 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi required_detectors = counter * 5 // number_donations rule = logic.museum.can_find_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", required_detectors) MultiWorldRules.set_rule(multiworld.get_location(museum_location.name, player), - rule.simplify()) + rule) counter += 1 @@ -591,7 +591,7 @@ def set_museum_milestone_rule(logic: StardewLogic, multiworld: MultiWorld, museu rule = logic.museum.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) if rule is None: return - MultiWorldRules.set_rule(multiworld.get_location(museum_milestone.name, player), rule.simplify()) + MultiWorldRules.set_rule(multiworld.get_location(museum_milestone.name, player), rule) def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, accepted_items, donation_func): @@ -605,13 +605,13 @@ def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, acce def set_backpack_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if world_options.backpack_progression != BackpackProgression.option_vanilla: MultiWorldRules.set_rule(multiworld.get_location("Large Pack", player), - logic.money.can_spend(2000).simplify()) + logic.money.can_spend(2000)) MultiWorldRules.set_rule(multiworld.get_location("Deluxe Pack", player), - (logic.money.can_spend(10000) & logic.received("Progressive Backpack")).simplify()) + (logic.money.can_spend(10000) & logic.received("Progressive Backpack"))) if ModNames.big_backpack in world_options.mods: MultiWorldRules.set_rule(multiworld.get_location("Premium Pack", player), (logic.money.can_spend(150000) & - logic.received("Progressive Backpack", 2)).simplify()) + logic.received("Progressive Backpack", 2))) def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): @@ -621,7 +621,7 @@ def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multi for festival in festival_locations: if festival.name in all_location_names: MultiWorldRules.set_rule(multiworld.get_location(festival.name, player), - logic.festival_rules[festival.name].simplify()) + logic.festival_rules[festival.name]) monster_eradication_prefix = "Monster Eradication: " @@ -653,7 +653,7 @@ def set_monstersanity_monster_rules(all_location_names: List[str], logic: Starde rule = logic.monster.can_kill_max(all_monsters_by_name[monster_name]) else: rule = logic.monster.can_kill(all_monsters_by_name[monster_name]) - MultiWorldRules.set_rule(location, rule.simplify()) + MultiWorldRules.set_rule(location, rule) def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): @@ -680,7 +680,7 @@ def set_monstersanity_progressive_category_rule(all_location_names: List[str], l rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category], goal_index + 1) else: rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], goal_index * 2) - MultiWorldRules.set_rule(location, rule.simplify()) + MultiWorldRules.set_rule(location, rule) def get_monster_eradication_number(location_name, monster_category) -> int: @@ -701,7 +701,7 @@ def set_monstersanity_category_rules(all_location_names: List[str], logic: Stard rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category]) else: rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], 8) - MultiWorldRules.set_rule(location, rule.simplify()) + MultiWorldRules.set_rule(location, rule) def set_shipsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -777,26 +777,26 @@ def set_traveling_merchant_day_rules(logic: StardewLogic, multiworld: MultiWorld def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_junimo_kart, player), - logic.received(Wallet.skull_key).simplify()) + logic.received(Wallet.skull_key)) if world_options.arcade_machine_locations != ArcadeMachineLocations.option_full_shuffling: return MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_junimo_kart, player), - logic.has("Junimo Kart Small Buff").simplify()) + logic.has("Junimo Kart Small Buff")) MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_junimo_kart_2, player), - logic.has("Junimo Kart Medium Buff").simplify()) + logic.has("Junimo Kart Medium Buff")) MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_junimo_kart_3, player), - logic.has("Junimo Kart Big Buff").simplify()) + logic.has("Junimo Kart Big Buff")) MultiWorldRules.add_rule(multiworld.get_location("Junimo Kart: Sunset Speedway (Victory)", player), - logic.has("Junimo Kart Max Buff").simplify()) + logic.has("Junimo Kart Max Buff")) MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.play_journey_of_the_prairie_king, player), - logic.has("JotPK Small Buff").simplify()) + logic.has("JotPK Small Buff")) MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_jotpk_world_2, player), - logic.has("JotPK Medium Buff").simplify()) + logic.has("JotPK Medium Buff")) MultiWorldRules.add_rule(multiworld.get_entrance(Entrance.reach_jotpk_world_3, player), - logic.has("JotPK Big Buff").simplify()) + logic.has("JotPK Big Buff")) MultiWorldRules.add_rule(multiworld.get_location("Journey of the Prairie King Victory", player), - logic.has("JotPK Max Buff").simplify()) + logic.has("JotPK Max Buff")) def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): @@ -811,20 +811,20 @@ def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, m friend_name = friend_location_trimmed[:split_index] num_hearts = int(friend_location_trimmed[split_index + 1:]) MultiWorldRules.set_rule(multiworld.get_location(friend_location.name, player), - logic.relationship.can_earn_relationship(friend_name, num_hearts).simplify()) + logic.relationship.can_earn_relationship(friend_name, num_hearts)) def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.deepwoods in world_options.mods: MultiWorldRules.add_rule(multiworld.get_location("Breaking Up Deep Woods Gingerbread House", player), - logic.tool.has_tool(Tool.axe, "Gold") & logic.mod.deepwoods.can_reach_woods_depth(50).simplify()) + logic.tool.has_tool(Tool.axe, "Gold") & logic.mod.deepwoods.can_reach_woods_depth(50)) MultiWorldRules.add_rule(multiworld.get_location("Chop Down a Deep Woods Iridium Tree", player), - logic.tool.has_tool(Tool.axe, "Iridium").simplify()) + logic.tool.has_tool(Tool.axe, "Iridium")) MultiWorldRules.set_rule(multiworld.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), - logic.received("Woods Obelisk").simplify()) + logic.received("Woods Obelisk")) for depth in range(10, 100 + 10, 10): MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), - logic.mod.deepwoods.can_chop_to_depth(depth).simplify()) + logic.mod.deepwoods.can_chop_to_depth(depth)) def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): @@ -833,51 +833,51 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.set_rule(multiworld.get_entrance(MagicEntrance.store_to_altar, player), (logic.relationship.has_hearts(NPC.wizard, 3) & - logic.region.can_reach(Region.wizard_tower)).simplify()) + logic.region.can_reach(Region.wizard_tower))) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Clear Debris", player), - (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")).simplify()) + (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic"))) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Till", player), - logic.tool.has_tool("Hoe", "Basic").simplify()) + logic.tool.has_tool("Hoe", "Basic")) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Water", player), - logic.tool.has_tool("Watering Can", "Basic").simplify()) + logic.tool.has_tool("Watering Can", "Basic")) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Toil School Locations", player), (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") - & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic"))).simplify()) + & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")))) # Do I *want* to add boots into logic when you get them even in vanilla without effort? idk MultiWorldRules.add_rule(multiworld.get_location("Analyze: Evac", player), - logic.ability.can_mine_perfectly().simplify()) + logic.ability.can_mine_perfectly()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Haste", player), - logic.has("Coffee").simplify()) + logic.has("Coffee")) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Heal", player), - logic.has("Life Elixir").simplify()) + logic.has("Life Elixir")) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Life School Locations", player), (logic.has("Coffee") & logic.has("Life Elixir") - & logic.ability.can_mine_perfectly()).simplify()) + & logic.ability.can_mine_perfectly())) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Descend", player), - logic.region.can_reach(Region.mines).simplify()) + logic.region.can_reach(Region.mines)) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), - logic.has("Fire Quartz").simplify()) + logic.has("Fire Quartz")) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85)).simplify()) + (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85))) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), - (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85)).simplify()) + (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85))) # MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player),) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Tendrils", player), - logic.region.can_reach(Region.farm).simplify()) + logic.region.can_reach(Region.farm)) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Shockwave", player), - logic.has("Earth Crystal").simplify()) + logic.has("Earth Crystal")) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Nature School Locations", player), - (logic.has("Earth Crystal") & logic.region.can_reach("Farm")).simplify()), + (logic.has("Earth Crystal") & logic.region.can_reach("Farm"))), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Meteor", player), - (logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)).simplify()), + (logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12))), MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lucksteal", player), - logic.region.can_reach(Region.witch_hut).simplify()) + logic.region.can_reach(Region.witch_hut)) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Bloodmana", player), - logic.region.can_reach(Region.mines_floor_100).simplify()) + logic.region.can_reach(Region.mines_floor_100)) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Eldritch School Locations", player), (logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & - logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)).simplify()) + logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12))) MultiWorldRules.add_rule(multiworld.get_location("Analyze Every Magic School Location", player), (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & @@ -886,52 +886,52 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i logic.has("Fire Quartz") & logic.skill.can_fish([], 85) & logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & - logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)).simplify()) + logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12))) def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.sve not in world_options.mods: return MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_to_junimo, player), - logic.received("Abandoned House Outskirts Clean-up").simplify()) + logic.received("Abandoned House Outskirts Clean-up")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), - logic.received("Iridium Bomb").simplify()) + logic.received("Iridium Bomb")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), - logic.mod.sve.has_any_rune().simplify()) + logic.mod.sve.has_any_rune()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), - logic.quest.can_complete_quest(Quest.magic_ink).simplify()) + logic.quest.can_complete_quest(Quest.magic_ink)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), - logic.tool.has_tool(Tool.axe, ToolMaterial.iron).simplify()) + logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), - logic.received("Fable Reef Portal").simplify()) + logic.received("Fable Reef Portal")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), - logic.tool.has_tool(Tool.axe, ToolMaterial.iron).simplify()) + logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_aurora, player), - logic.received("Nexus: Aurora Vineyard Runes").simplify()) + logic.received("Nexus: Aurora Vineyard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_farm, player), - logic.mod.sve.has_any_rune().simplify()) + logic.mod.sve.has_any_rune()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_guild, player), - logic.received("Nexus: Adventurer's Guild Runes").simplify()) + logic.received("Nexus: Adventurer's Guild Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_junimo, player), - logic.received("Nexus: Junimo Woods Runes").simplify()) + logic.received("Nexus: Junimo Woods Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_spring, player), - logic.received("Nexus: Sprite Spring Runes").simplify()) + logic.received("Nexus: Sprite Spring Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_outpost, player), - logic.received("Nexus: Outpost Runes").simplify()) + logic.received("Nexus: Outpost Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_wizard, player), - logic.mod.sve.has_any_rune().simplify()) + logic.mod.sve.has_any_rune()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), - logic.relationship.has_hearts(ModNPC.apples, 10).simplify()) + logic.relationship.has_hearts(ModNPC.apples, 10)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.to_grandpa_upstairs, player), - logic.quest.can_complete_quest(ModQuest.GrandpasShed).simplify()) + logic.quest.can_complete_quest(ModQuest.GrandpasShed)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron).simplify()) + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic)).simplify()) + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) for location in logic.mod.sve.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), - logic.mod.sve.sve_location_rules[location].simplify()) + logic.mod.sve.sve_location_rules[location]) set_sve_ginger_island_rules(logic, multiworld, player, world_options) @@ -939,7 +939,7 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.summit_to_boat, player), - logic.received("Marlon's Boat Paddle").simplify()) + logic.received("Marlon's Boat Paddle")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), - logic.received("Fable Reef Portal").simplify()) + logic.received("Fable Reef Portal")) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 5af20e679401..dda0137a1957 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -116,6 +116,7 @@ def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: Star self._simplified = False def __call__(self, state: CollectionState) -> bool: + self.simplify() return any(rule(state) for rule in self.rules) def __repr__(self): @@ -192,6 +193,7 @@ def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: Star self.rules = frozenset(rules_list) def __call__(self, state: CollectionState) -> bool: + self.simplify() result = all(rule(state) for rule in self.rules) return result @@ -240,6 +242,7 @@ def simplify(self) -> StardewRule: class Count(StardewRule): count: int rules: List[StardewRule] + _simplified: bool def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): rules_list: List[StardewRule] @@ -257,8 +260,10 @@ def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], self.rules = rules_list self.count = count + self._simplified = False def __call__(self, state: CollectionState) -> bool: + self.simplify() c = 0 for r in self.rules: if r(state): @@ -276,8 +281,13 @@ def get_difficulty(self): return max(rule.get_difficulty() for rule in easiest_n_rules) def simplify(self): + if self._simplified: + return self + + simplified_rules = [rule.simplify() for rule in self.rules] + self.rules = simplified_rules + self._simplified = True return self - # return Count(self.count, [rule.simplify() for rule in self.rules]) class TotalReceived(StardewRule): @@ -355,15 +365,18 @@ def get_difficulty(self): return 1 -@dataclass(frozen=True) class Has(StardewRule): item: str # For sure there is a better way than just passing all the rules everytime other_rules: Dict[str, StardewRule] + def __init__(self, item: str, other_rules: Dict[str, StardewRule]): + self.item = item + self.other_rules = other_rules + def __call__(self, state: CollectionState) -> bool: - if isinstance(self.item, str): - return self.other_rules[self.item](state) + self.simplify() + return self.other_rules[self.item](state) def __repr__(self): if not self.item in self.other_rules: From 9d5a380a7b5fc6b4f3dd669896bb27cc9bf6f642 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 14 Nov 2023 01:03:18 -0500 Subject: [PATCH 144/482] replace custom cache with lru # Conflicts: # worlds/stardew_valley/__init__.py # worlds/stardew_valley/logic/cached_logic.py # worlds/stardew_valley/rules.py # Conflicts: # worlds/stardew_valley/logic/fishing_logic.py # worlds/stardew_valley/logic/logic.py # worlds/stardew_valley/logic/mine_logic.py # worlds/stardew_valley/logic/monster_logic.py # worlds/stardew_valley/logic/region_logic.py # worlds/stardew_valley/logic/relationship_logic.py # worlds/stardew_valley/logic/season_logic.py --- worlds/stardew_valley/__init__.py | 9 ++- worlds/stardew_valley/data/crops_data.py | 20 ++--- worlds/stardew_valley/data/monster_data.py | 20 ++--- worlds/stardew_valley/data/recipe_source.py | 7 +- worlds/stardew_valley/logic/action_logic.py | 9 ++- worlds/stardew_valley/logic/arcade_logic.py | 8 +- worlds/stardew_valley/logic/building_logic.py | 37 +++++---- worlds/stardew_valley/logic/bundle_logic.py | 19 +++-- worlds/stardew_valley/logic/cached_logic.py | 21 ++--- worlds/stardew_valley/logic/combat_logic.py | 18 +++-- worlds/stardew_valley/logic/cooking_logic.py | 27 ++++--- worlds/stardew_valley/logic/crafting_logic.py | 35 +++++--- worlds/stardew_valley/logic/crop_logic.py | 7 +- worlds/stardew_valley/logic/fishing_logic.py | 16 ++-- worlds/stardew_valley/logic/gift_logic.py | 10 ++- worlds/stardew_valley/logic/has_logic.py | 10 +-- worlds/stardew_valley/logic/logic.py | 79 ++++++++++--------- worlds/stardew_valley/logic/mine_logic.py | 15 ++-- worlds/stardew_valley/logic/money_logic.py | 20 ++--- worlds/stardew_valley/logic/monster_logic.py | 21 ++--- worlds/stardew_valley/logic/museum_logic.py | 12 +-- worlds/stardew_valley/logic/quest_logic.py | 14 ++-- worlds/stardew_valley/logic/received_logic.py | 10 +-- worlds/stardew_valley/logic/region_logic.py | 24 +++--- .../logic/relationship_logic.py | 22 +++--- worlds/stardew_valley/logic/season_logic.py | 9 ++- worlds/stardew_valley/logic/shipping_logic.py | 12 +-- worlds/stardew_valley/logic/skill_logic.py | 56 +++++++------ worlds/stardew_valley/logic/time_logic.py | 7 +- worlds/stardew_valley/logic/tool_logic.py | 20 ++--- .../logic/traveling_merchant_logic.py | 4 +- .../mods/logic/mod_skills_levels.py | 7 +- worlds/stardew_valley/rules.py | 14 ++-- worlds/stardew_valley/strings/crop_names.py | 3 + 34 files changed, 339 insertions(+), 283 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 12e9a330fe03..880930b2b529 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -4,20 +4,20 @@ from BaseClasses import Region, Entrance, Location, Item, Tutorial, CollectionState, ItemClassification, MultiWorld, Group as ItemLinkGroup from Options import PerGameCommonOptions from worlds.AutoWorld import World, WebWorld +from worlds.generic.Rules import set_rule from . import rules from .bundles import get_all_bundles, Bundle from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData +from .logic.bundle_logic import BundleLogic from .logic.cached_logic import function_total_times, function_call_numbers from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS -from .logic.bundle_logic import BundleLogic from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \ BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems from .presets import sv_options_presets from .regions import create_regions from .rules import set_rules -from worlds.generic.Rules import set_rule from .stardew_rule import True_, StardewRule from .strings.ap_names.event_names import Event from .strings.goal_names import Goal as GoalName @@ -100,7 +100,8 @@ def force_change_options_if_incompatible(self): self.options.exclude_ginger_island.value = ExcludeGingerIsland.option_false goal_name = self.options.goal.current_key player_name = self.multiworld.player_name[self.player] - logging.warning(f"Goal '{goal_name}' requires Ginger Island. Exclude Ginger Island setting forced to 'False' for player {self.player} ({player_name})") + logging.warning( + f"Goal '{goal_name}' requires Ginger Island. Exclude Ginger Island setting forced to 'False' for player {self.player} ({player_name})") def create_regions(self): def create_region(name: str, exits: Iterable[str]) -> Region: @@ -233,7 +234,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == options.Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], - self.logic.has_everything(self.all_progression_items), + self.logic.has_everything(frozenset(self.all_progression_items)).simplify(), Event.victory) self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player) diff --git a/worlds/stardew_valley/data/crops_data.py b/worlds/stardew_valley/data/crops_data.py index e798235060f2..f540246dfdf6 100644 --- a/worlds/stardew_valley/data/crops_data.py +++ b/worlds/stardew_valley/data/crops_data.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List +from typing import Tuple from .. import data @@ -7,14 +7,14 @@ @dataclass(frozen=True) class SeedItem: name: str - seasons: List[str] - regions: List[str] + seasons: Tuple[str] + regions: Tuple[str] @dataclass(frozen=True) class CropItem: name: str - farm_growth_seasons: List[str] + farm_growth_seasons: Tuple[str] seed: SeedItem @@ -32,13 +32,13 @@ def load_crop_csv(): for item in reader: seeds.append(SeedItem(item["seed"], - [season for season in item["seed_seasons"].split(",")] - if item["seed_seasons"] else [], - [region for region in item["seed_regions"].split(",")] - if item["seed_regions"] else [])) + tuple(season for season in item["seed_seasons"].split(",")) + if item["seed_seasons"] else tuple(), + tuple(region for region in item["seed_regions"].split(",")) + if item["seed_regions"] else tuple())) crops.append(CropItem(item["crop"], - [season for season in item["farm_growth_seasons"].split(",")] - if item["farm_growth_seasons"] else [], + tuple(season for season in item["farm_growth_seasons"].split(",")) + if item["farm_growth_seasons"] else (), seeds[-1])) return crops, seeds diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 42546e5653e3..45538ebdaad7 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -1,8 +1,6 @@ from dataclasses import dataclass -from typing import List, Tuple, Union, Optional +from typing import List, Tuple -from . import season_data as season -from .game_item import GameItem from ..strings.monster_names import Monster, MonsterCategory from ..strings.performance_names import Performance from ..strings.region_names import Region @@ -65,7 +63,7 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu bat_dangerous = create_monster(Monster.bat_dangerous, MonsterCategory.bats, dangerous_mines_20, Performance.galaxy) frost_bat = create_monster(Monster.frost_bat, MonsterCategory.bats, mines_floor_60, Performance.decent) frost_bat_dangerous = create_monster(Monster.frost_bat_dangerous, MonsterCategory.bats, dangerous_mines_60, Performance.galaxy) -lava_bat = create_monster(Monster.lava_bat, MonsterCategory.bats,mines_floor_100, Performance.good) +lava_bat = create_monster(Monster.lava_bat, MonsterCategory.bats, mines_floor_100, Performance.good) iridium_bat = create_monster(Monster.iridium_bat, MonsterCategory.bats, skull_cavern_high, Performance.great) skeleton = create_monster(Monster.skeleton, MonsterCategory.skeletons, mines_floor_100, Performance.good) @@ -80,8 +78,9 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu grub_dangerous = create_monster(Monster.grub_dangerous, MonsterCategory.cave_insects, dangerous_mines_60, Performance.galaxy) mutant_fly = create_monster(Monster.mutant_fly, MonsterCategory.cave_insects, mutant_bug_lair, Performance.good) mutant_grub = create_monster(Monster.mutant_grub, MonsterCategory.cave_insects, mutant_bug_lair, Performance.good) -armored_bug = create_monster(Monster.armored_bug, MonsterCategory.cave_insects, skull_cavern, Performance.basic) # Requires 'Bug Killer' enchantment -armored_bug_dangerous = create_monster(Monster.armored_bug_dangerous, MonsterCategory.cave_insects, skull_cavern, Performance.good) # Requires 'Bug Killer' enchantment +armored_bug = create_monster(Monster.armored_bug, MonsterCategory.cave_insects, skull_cavern, Performance.basic) # Requires 'Bug Killer' enchantment +armored_bug_dangerous = create_monster(Monster.armored_bug_dangerous, MonsterCategory.cave_insects, skull_cavern, + Performance.good) # Requires 'Bug Killer' enchantment duggy = create_monster(Monster.duggy, MonsterCategory.duggies, mines_floor_20, Performance.basic) duggy_dangerous = create_monster(Monster.duggy_dangerous, MonsterCategory.duggies, dangerous_mines_20, Performance.great) @@ -96,8 +95,9 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu lava_crab_dangerous = create_monster(Monster.lava_crab_dangerous, MonsterCategory.rock_crabs, dangerous_mines_100, Performance.galaxy) iridium_crab = create_monster(Monster.iridium_crab, MonsterCategory.rock_crabs, skull_cavern, Performance.great) -mummy = create_monster(Monster.mummy, MonsterCategory.mummies, skull_cavern, Performance.great) # Requires bombs or "Crusader" enchantment -mummy_dangerous = create_monster(Monster.mummy_dangerous, MonsterCategory.mummies, skull_cavern_dangerous, Performance.maximum) # Requires bombs or "Crusader" enchantment +mummy = create_monster(Monster.mummy, MonsterCategory.mummies, skull_cavern, Performance.great) # Requires bombs or "Crusader" enchantment +mummy_dangerous = create_monster(Monster.mummy_dangerous, MonsterCategory.mummies, skull_cavern_dangerous, + Performance.maximum) # Requires bombs or "Crusader" enchantment pepper_rex = create_monster(Monster.pepper_rex, MonsterCategory.pepper_rex, skull_cavern, Performance.great) @@ -111,5 +111,5 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu all_monsters_by_category = {} for monster in all_monsters: if monster.category not in all_monsters_by_category: - all_monsters_by_category[monster.category] = [] - all_monsters_by_category[monster.category].append(monster) + all_monsters_by_category[monster.category] = () + all_monsters_by_category[monster.category] = () + (monster,) diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index 0e259a4134d6..f02685628fb8 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -1,4 +1,4 @@ -from typing import Iterable, Union, List +from typing import Union, List, Tuple class RecipeSource: @@ -14,12 +14,12 @@ def __repr__(self): class ArchipelagoSource(RecipeSource): - ap_item: List[str] + ap_item: Tuple[str] def __init__(self, ap_item: Union[str, List[str]]): if isinstance(ap_item, str): ap_item = [ap_item] - self.ap_item = ap_item + self.ap_item = tuple(ap_item) def __repr__(self): return f"ArchipelagoSource {self.ap_item}" @@ -119,6 +119,5 @@ class SpecialOrderSource(RecipeSource): def __init__(self, special_order: str): self.special_order = special_order - def __repr__(self): return f"SpecialOrderSource from {self.special_order}" diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index a005dfe850d5..c2aba35b4c8a 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule, profile_rule +from functools import lru_cache + +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -13,7 +15,8 @@ class ActionLogic(CachedLogic): has: HasLogic region: RegionLogic - def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, has: HasLogic, region: RegionLogic): + def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, has: HasLogic, + region: RegionLogic): super().__init__(player, cached_rules) self.received = received self.has = has @@ -31,7 +34,7 @@ def can_pan(self) -> StardewRule: def can_pan_at(self, region: str) -> StardewRule: return self.region.can_reach(region) & self.can_pan() - @cache_rule + @lru_cache(maxsize=None) def can_open_geode(self, geode: str) -> StardewRule: blacksmith_access = self.region.can_reach(Region.blacksmith) geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index aed6498eaba0..8298c2cff691 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,9 +1,8 @@ -from .cached_logic import profile_rule +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic from .. import options from ..options import ArcadeMachineLocations from ..stardew_rule import StardewRule, True_ -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic from ..strings.region_names import Region @@ -22,8 +21,7 @@ def __init__(self, player: int, arcade_option: ArcadeMachineLocations, received: def has_jotpk_power_level(self, power_level: int) -> StardewRule: if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: return True_() - jotpk_buffs = ["JotPK: Progressive Boots", "JotPK: Progressive Gun", - "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate"] + jotpk_buffs = ("JotPK: Progressive Boots", "JotPK: Progressive Gun", "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate") return self.received(jotpk_buffs, power_level) def has_junimo_kart_power_level(self, power_level: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index c11065d6b74b..76daa01f6b66 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,14 +1,15 @@ +from functools import lru_cache from typing import Dict -from .cached_logic import cache_rule, CachedLogic, profile_rule +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..options import BuildingProgression from ..stardew_rule import StardewRule, True_, False_, Has -from ..strings.artisan_good_names import ArtisanGood from ..strings.ap_names.event_names import Event +from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building from ..strings.fish_names import WaterItem from ..strings.material_names import Material @@ -25,7 +26,8 @@ class BuildingLogic(CachedLogic): money: MoneyLogic building_rules: Dict[str, StardewRule] - def __init__(self, player: int, cached_rules: CachedRules, building_option: BuildingProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + def __init__(self, player: int, cached_rules: CachedRules, building_option: BuildingProgression, + received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): super().__init__(player, cached_rules) self.player = player self.building_option = building_option @@ -37,24 +39,26 @@ def __init__(self, player: int, cached_rules: CachedRules, building_option: Buil def initialize_rules(self): self.building_rules.update({ - Building.barn: self.money.can_spend_at(Region.carpenter, 6000) & self.has([Material.wood, Material.stone]), - Building.big_barn: self.money.can_spend_at(Region.carpenter, 12000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.barn), - Building.deluxe_barn: self.money.can_spend_at(Region.carpenter, 25000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.big_barn), - Building.coop: self.money.can_spend_at(Region.carpenter, 4000) & self.has([Material.wood, Material.stone]), - Building.big_coop: self.money.can_spend_at(Region.carpenter, 10000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.coop), - Building.deluxe_coop: self.money.can_spend_at(Region.carpenter, 20000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.big_coop), - Building.fish_pond: self.money.can_spend_at(Region.carpenter, 5000) & self.has([Material.stone, WaterItem.seaweed, WaterItem.green_algae]), - Building.mill: self.money.can_spend_at(Region.carpenter, 2500) & self.has([Material.stone, Material.wood, ArtisanGood.cloth]), + # @formatter:off + Building.barn: self.money.can_spend_at(Region.carpenter, 6000) & self.has((Material.wood, Material.stone)), + Building.big_barn: self.money.can_spend_at(Region.carpenter, 12000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.barn), + Building.deluxe_barn: self.money.can_spend_at(Region.carpenter, 25000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_barn), + Building.coop: self.money.can_spend_at(Region.carpenter, 4000) & self.has((Material.wood, Material.stone)), + Building.big_coop: self.money.can_spend_at(Region.carpenter, 10000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.coop), + Building.deluxe_coop: self.money.can_spend_at(Region.carpenter, 20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_coop), + Building.fish_pond: self.money.can_spend_at(Region.carpenter, 5000) & self.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), + Building.mill: self.money.can_spend_at(Region.carpenter, 2500) & self.has((Material.stone, Material.wood, ArtisanGood.cloth)), Building.shed: self.money.can_spend_at(Region.carpenter, 15000) & self.has(Material.wood), - Building.big_shed: self.money.can_spend_at(Region.carpenter, 20000) & self.has([Material.wood, Material.stone]) & self.has_building(Building.shed), - Building.silo: self.money.can_spend_at(Region.carpenter, 100) & self.has([Material.stone, Material.clay, MetalBar.copper]), - Building.slime_hutch: self.money.can_spend_at(Region.carpenter, 10000) & self.has([Material.stone, MetalBar.quartz, MetalBar.iridium]), - Building.stable: self.money.can_spend_at(Region.carpenter, 10000) & self.has([Material.hardwood, MetalBar.iron]), + Building.big_shed: self.money.can_spend_at(Region.carpenter, 20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.shed), + Building.silo: self.money.can_spend_at(Region.carpenter, 100) & self.has((Material.stone, Material.clay, MetalBar.copper)), + Building.slime_hutch: self.money.can_spend_at(Region.carpenter, 10000) & self.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), + Building.stable: self.money.can_spend_at(Region.carpenter, 10000) & self.has((Material.hardwood, MetalBar.iron)), Building.well: self.money.can_spend_at(Region.carpenter, 1000) & self.has(Material.stone), Building.shipping_bin: self.money.can_spend_at(Region.carpenter, 250) & self.has(Material.wood), Building.kitchen: self.money.can_spend_at(Region.carpenter, 10000) & self.has(Material.wood) & self.has_house(0), Building.kids_room: self.money.can_spend_at(Region.carpenter, 50000) & self.has(Material.hardwood) & self.has_house(1), Building.cellar: self.money.can_spend_at(Region.carpenter, 100000) & self.has_house(2), + # @formatter:on }) def update_rules(self, new_rules: Dict[str, StardewRule]): @@ -76,7 +80,7 @@ def has_building(self, building: str) -> StardewRule: building = " ".join(["Progressive", *building.split(" ")[1:]]) return self.received(f"{building}", count) & carpenter_rule - @cache_rule + @lru_cache(maxsize=None) def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level < 1: return True_() @@ -95,4 +99,3 @@ def has_house(self, upgrade_level: int) -> StardewRule: # if upgrade_level == 3: return Has(Building.cellar, self.building_rules) - diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 1f6fb0eb4066..a47f0269c4d9 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,11 +1,12 @@ -from typing import List +from functools import lru_cache +from typing import Tuple -from .cached_logic import profile_rule, cache_rule, CachedLogic, CachedRules -from ..data.bundle_data import BundleItem +from .cached_logic import CachedLogic, CachedRules from .farming_logic import FarmingLogic from .has_logic import HasLogic from .money_logic import MoneyLogic from .region_logic import RegionLogic +from ..data.bundle_data import BundleItem from ..stardew_rule import StardewRule from ..strings.region_names import Region @@ -16,15 +17,16 @@ class BundleLogic(CachedLogic): money: MoneyLogic farming: FarmingLogic - def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic, region: RegionLogic, money: MoneyLogic, farming: FarmingLogic): + def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic, region: RegionLogic, money: MoneyLogic, + farming: FarmingLogic): super().__init__(player, cached_rules) self.has = has self.region = region self.money = money self.farming = farming - @cache_rule - def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_required: int) -> StardewRule: + @lru_cache(maxsize=None) + def can_complete_bundle(self, bundle_requirements: Tuple[BundleItem], number_required: int) -> StardewRule: item_rules = [] highest_quality_yet = 0 can_speak_junimo = self.region.can_reach(Region.wizard_tower) @@ -35,9 +37,10 @@ def can_complete_bundle(self, bundle_requirements: List[BundleItem], number_requ item_rules.append(bundle_item.item.name) if bundle_item.quality > highest_quality_yet: highest_quality_yet = bundle_item.quality - return can_speak_junimo & self.has(item_rules, number_required) & self.farming.can_grow_crop_quality(highest_quality_yet) + return can_speak_junimo & self.has(tuple(item_rules), number_required) & self.farming.can_grow_crop_quality( + highest_quality_yet) - @cache_rule + @lru_cache(maxsize=None) def can_complete_community_center(self) -> StardewRule: return (self.region.can_reach_location("Complete Crafts Room") & self.region.can_reach_location("Complete Pantry") & diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py index cea431118c07..df0f8a8bcb13 100644 --- a/worlds/stardew_valley/logic/cached_logic.py +++ b/worlds/stardew_valley/logic/cached_logic.py @@ -1,7 +1,7 @@ import functools import random import time -from typing import Dict, Callable +from typing import Dict, Callable, Hashable, Iterable from ..stardew_rule import StardewRule @@ -11,7 +11,7 @@ class CachedRules: - cached_rules: Dict[str, StardewRule] + cached_rules: Dict[Hashable, StardewRule] def __init__(self): self.cached_rules = dict() @@ -21,10 +21,10 @@ def try_get_rule(self, key: str, create_rule, *args, **kwargs) -> StardewRule: self.cached_rules[key] = create_rule(*args, **kwargs) return self.cached_rules[key] - def try_get_rule_without_cache(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + def try_get_rule_without_cache(self, key: Hashable, create_rule: Callable[[], StardewRule]) -> StardewRule: return create_rule() - def try_get_rule_with_stats(self, key: str, create_rule: Callable[[], StardewRule]) -> StardewRule: + def try_get_rule_with_stats(self, key: Hashable, create_rule: Callable[[], StardewRule]) -> StardewRule: global rule_calls, rule_creations, time_creating_rules rule_calls += 1 if key not in self.cached_rules: @@ -38,8 +38,9 @@ def try_get_rule_with_stats(self, key: str, create_rule: Callable[[], StardewRul percent_cached_calls = round((cached_calls / rule_calls) * 100) percent_real_calls = 100 - percent_cached_calls time_saved = (time_creating_rules / percent_real_calls) * 100 - print(f"Rule Creations/Calls: {rule_creations}/{rule_calls} ({cached_calls} cached calls [{percent_cached_calls}%] saving {time_saved}s" - f" for a total of {time_creating_rules}s creating rules)") + print( + f"Rule Creations/Calls: {rule_creations}/{rule_calls} ({cached_calls} cached calls [{percent_cached_calls}%] saving {time_saved}s" + f" for a total of {time_creating_rules}s creating rules)") return self.cached_rules[key] @@ -52,8 +53,9 @@ def __init__(self, player: int, cached_rules: CachedRules): self.cached_rules = cached_rules self.name = type(self).__name__ - def get_cache_key(self, method: Callable, *parameters, **kwargs) -> str: - return f"{self.name} {method.__name__} {parameters} {kwargs}" + def get_cache_key(self, method: Callable, *parameters) -> Hashable: + assert not any(isinstance(p, Iterable) for p in parameters) + return self.name, method.__name__, str(parameters) # return f"{type(self).__name__} {method.__name__} {' '.join(map(str, parameters))}" @@ -84,6 +86,7 @@ def wrapper(self, *args, **kwargs): print(f"Time Getting Keys: {time_getting_keys} seconds") print(f"Time Getting Rules: {time_getting_rules} seconds") return rule + return wrapper @@ -117,5 +120,5 @@ def wrapper(self, *args, **kwargs): function_total_times[key_params] += time_used return result - return wrapper + return wrapper diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 8b101f465803..7192959dd038 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule, CachedRules +from functools import lru_cache + +from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..mods.logic.magic_logic import MagicLogic @@ -6,7 +8,7 @@ from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.performance_names import Performance -valid_weapons = [APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger] +valid_weapons = (APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger) class CombatLogic(CachedLogic): @@ -22,7 +24,7 @@ def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLog def set_magic(self, magic: MagicLogic): self.magic = magic - @cache_rule + @lru_cache(maxsize=None) def can_fight_at_level(self, level: str) -> StardewRule: if level == Performance.basic: return self.has_any_weapon() | self.magic.has_any_spell() @@ -38,22 +40,22 @@ def can_fight_at_level(self, level: str) -> StardewRule: return self.has_galaxy_weapon() | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP return False_() - @cache_rule + @lru_cache(maxsize=None) def has_any_weapon(self) -> StardewRule: return self.received(valid_weapons, 1) - @cache_rule + @lru_cache(maxsize=None) def has_decent_weapon(self) -> StardewRule: return Or(self.received(weapon, 2) for weapon in valid_weapons) - @cache_rule + @lru_cache(maxsize=None) def has_good_weapon(self) -> StardewRule: return Or(self.received(weapon, 3) for weapon in valid_weapons) - @cache_rule + @lru_cache(maxsize=None) def has_great_weapon(self) -> StardewRule: return Or(self.received(weapon, 4) for weapon in valid_weapons) - @cache_rule + @lru_cache(maxsize=None) def has_galaxy_weapon(self) -> StardewRule: return Or(self.received(weapon, 5) for weapon in valid_weapons) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 7f5eaeb331c7..d30fdc5852a0 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,6 +1,8 @@ +from functools import lru_cache + from .action_logic import ActionLogic from .building_logic import BuildingLogic -from .cached_logic import CachedLogic, cache_rule, profile_rule +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -9,12 +11,13 @@ from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .time_logic import TimeLogic -from ..options import ExcludeGingerIsland, Mods -from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, QueenOfSauceSource, CookingRecipe, \ +from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \ + QueenOfSauceSource, CookingRecipe, \ all_cooking_recipes_by_name from ..data.recipe_source import CutsceneSource, ShopTradeSource from ..locations import locations_by_tag, LocationTags from ..options import Chefsanity +from ..options import ExcludeGingerIsland, Mods from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region from ..strings.skill_names import Skill @@ -36,8 +39,10 @@ class CookingLogic(CachedLogic): relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, - has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, + def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanity_option: Chefsanity, + exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): super().__init__(player, cached_rules) self.mods = mods @@ -54,11 +59,11 @@ def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanit self.relationship = relationship self.skill = skill - @cache_rule + @lru_cache(maxsize=None) def can_cook_in_kitchen(self) -> StardewRule: return self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) - @cache_rule + @lru_cache(maxsize=None) def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: cook_rule = self.region.can_reach(Region.kitchen) if recipe is None: @@ -70,7 +75,7 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: time_rule = self.time.has_lived_months(number_ingredients) return cook_rule & recipe_rule & ingredients_rule & time_rule - @cache_rule + @lru_cache(maxsize=None) def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: if self.chefsanity_option == Chefsanity.option_none: return self.can_learn_recipe(source) @@ -90,7 +95,7 @@ def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: return self.received_recipe(meal_name) return self.can_learn_recipe(source) - @cache_rule + @lru_cache(maxsize=None) def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() @@ -109,11 +114,11 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule return False_() - @cache_rule + @lru_cache(maxsize=None) def received_recipe(self, meal_name: str): return self.received(f"{meal_name} Recipe") - @cache_rule + @lru_cache(maxsize=None) def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " all_recipes_names = [] diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 709a8d2a2cb1..fd81566106e0 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import profile_rule, cache_rule, CachedLogic, CachedRules +from functools import lru_cache + +from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -9,8 +11,9 @@ from .time_logic import TimeLogic from .. import options from ..data.craftable_data import CraftingRecipe -from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource -from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource +from ..data.recipe_data import StarterSource, ShopSource, SkillSource, FriendshipSource +from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, \ + FestivalShopSource from ..options import Craftsanity, FestivalLocations, SpecialOrderLocations from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region @@ -29,9 +32,12 @@ class CraftingLogic(CachedLogic): skill: SkillLogic special_orders: SpecialOrderLogic - def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: Craftsanity, festivals_option: FestivalLocations, - special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, - money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): + def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: Craftsanity, + festivals_option: FestivalLocations, + special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, + region: RegionLogic, time: TimeLogic, + money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, + special_orders: SpecialOrderLogic): super().__init__(player, cached_rules) self.craftsanity_option = craftsanity_option self.festivals_option = festivals_option @@ -45,7 +51,7 @@ def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: C self.skill = skill self.special_orders = special_orders - @cache_rule + @lru_cache(maxsize=None) def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: craft_rule = True_() if recipe is None: @@ -57,7 +63,7 @@ def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: time_rule = self.time.has_lived_months(number_ingredients) return craft_rule & learn_rule & ingredients_rule & time_rule - @cache_rule + @lru_cache(maxsize=None) def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, ArchipelagoSource): return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) @@ -68,13 +74,15 @@ def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: return self.received_recipe(recipe.item) if self.craftsanity_option == Craftsanity.option_none: return self.can_learn_recipe(recipe) - if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance(recipe.source, ShopSource): + if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance( + recipe.source, ShopSource): return self.received_recipe(recipe.item) - if isinstance(recipe.source, SpecialOrderSource) and self.special_orders_option != SpecialOrderLocations.option_disabled: + if isinstance(recipe.source, + SpecialOrderSource) and self.special_orders_option != SpecialOrderLocations.option_disabled: return self.received_recipe(recipe.item) return self.can_learn_recipe(recipe) - @cache_rule + @lru_cache(maxsize=None) def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, StarterSource): return True_() @@ -87,7 +95,8 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, SkillSource): return self.skill.has_level(recipe.source.skill, recipe.source.level) if isinstance(recipe.source, CutsceneSource): - return self.region.can_reach(recipe.source.region) & self.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) + return self.region.can_reach(recipe.source.region) & self.relationship.has_hearts(recipe.source.friend, + recipe.source.hearts) if isinstance(recipe.source, FriendshipSource): return self.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) if isinstance(recipe.source, SpecialOrderSource): @@ -100,6 +109,6 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: return False_() - @cache_rule + @lru_cache(maxsize=None) def received_recipe(self, item_name: str): return self.received(f"{item_name} Recipe") diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index ac48b769bd91..f71b8fd9fa79 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,6 +1,7 @@ +from functools import lru_cache from typing import Union, Iterable -from .cached_logic import CachedLogic, cache_rule, profile_rule +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -41,7 +42,7 @@ def __init__(self, player: int, cached_rules: CachedRules, cropsanity_option: Cr self.money = money self.tool = tool - @cache_rule + @lru_cache(maxsize=None) def can_grow(self, crop: CropItem) -> StardewRule: season_rule = self.season.has_any(crop.farm_growth_seasons) seed_rule = self.has(crop.seed.name) @@ -61,7 +62,7 @@ def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> Stardew def has_island_farm(self) -> StardewRule: return self.region.can_reach(Region.island_south) - @cache_rule + @lru_cache(maxsize=None) def can_buy_seed(self, seed: SeedItem) -> StardewRule: if self.cropsanity_option == Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index b53a8d396bf7..9b913fca107b 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,12 +1,14 @@ -from .cached_logic import cache_rule, CachedLogic, CachedRules, profile_rule +from functools import lru_cache + +from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .tool_logic import ToolLogic -from ..options import ExcludeGingerIsland from ..data import FishItem from ..data.fish_data import legendary_fish +from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, False_, And from ..strings.fish_names import SVEFish @@ -23,7 +25,8 @@ class FishingLogic(CachedLogic): tool: ToolLogic skill: SkillLogic - def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, + def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, + special_order_locations: SpecialOrderLocations, received: ReceivedLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): super().__init__(player, cached_rules) self.exclude_ginger_island = exclude_ginger_island @@ -35,7 +38,7 @@ def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island self.skill = skill def can_fish_in_freshwater(self) -> StardewRule: - return self.skill.can_fish() & self.region.can_reach_any([Region.forest, Region.town, Region.mountain]) + return self.skill.can_fish() & self.region.can_reach_any((Region.forest, Region.town, Region.mountain)) def has_max_fishing(self) -> StardewRule: skill_rule = self.skill.has_level(Skill.fishing, 10) @@ -48,7 +51,7 @@ def can_fish_chests(self) -> StardewRule: def can_fish_at(self, region: str) -> StardewRule: return self.skill.can_fish() & self.region.can_reach(region) - @cache_rule + @lru_cache(maxsize=None) def can_catch_fish(self, fish: FishItem) -> StardewRule: quest_rule = True_() if fish.extended_family: @@ -70,4 +73,5 @@ def can_start_extended_family_quest(self) -> StardewRule: return False_() if self.special_order_locations != SpecialOrderLocations.option_board_qi: return False_() - return self.region.can_reach(Region.qi_walnut_room) & And([self.can_catch_fish(fish) for fish in legendary_fish]) + return self.region.can_reach(Region.qi_walnut_room) & And( + *(self.can_catch_fish(fish) for fish in legendary_fish)) diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 2eeff874a647..79079a722c81 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule +from functools import lru_cache + +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct @@ -12,7 +14,7 @@ def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic): super().__init__(player, cached_rules) self.has = has - @cache_rule + @lru_cache(maxsize=None) def has_any_universal_love(self) -> StardewRule: - return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) - + return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has( + AnimalProduct.rabbit_foot) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 9d24c0ddc2ae..972db3f1ea68 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,6 +1,7 @@ -from typing import Dict, Union, Optional, List +from functools import lru_cache +from typing import Dict, Union, Optional, Tuple -from .cached_logic import CachedLogic, cache_rule, CachedRules +from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, True_, And, Or, Has, Count @@ -17,8 +18,8 @@ def __call__(self, *args, **kwargs) -> StardewRule: count = args[1] return self.has(args[0], count) - @cache_rule - def has(self, items: Union[str, List[str]], count: Optional[int] = None) -> StardewRule: + @lru_cache(maxsize=None) + def has(self, items: Union[str, Tuple[str]], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): return Has(items, self.item_rules) @@ -32,4 +33,3 @@ def has(self, items: Union[str, List[str]], count: Optional[int] = None) -> Star return Or(self.has(item) for item in items) return Count(count, (self.has(item) for item in items)) - diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 7871046a4b97..a1c58b698ee2 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -1,8 +1,9 @@ from __future__ import annotations from dataclasses import field, dataclass -from typing import Dict, Set +from typing import Dict +from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from .ability_logic import AbilityLogic from .action_logic import ActionLogic from .arcade_logic import ArcadeLogic @@ -16,6 +17,7 @@ from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic from .gift_logic import GiftLogic, CachedRules +from .has_logic import HasLogic from .mine_logic import MineLogic from .money_logic import MoneyLogic from .monster_logic import MonsterLogic @@ -23,7 +25,6 @@ from .pet_logic import PetLogic from .quest_logic import QuestLogic from .received_logic import ReceivedLogic -from .has_logic import HasLogic from .region_logic import RegionLogic from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic @@ -34,14 +35,14 @@ from .tool_logic import ToolLogic from .traveling_merchant_logic import TravelingMerchantLogic from .wallet_logic import WalletLogic +from ..data import all_fish, all_purchasable_seeds, all_crops from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name -from ..data.monster_data import all_monsters_by_category, all_monsters_by_name -from ..mods.logic.mod_logic import ModLogic -from ..data import all_fish, all_purchasable_seeds, all_crops from ..data.fish_data import island_fish, extended_family, get_fish_for_mods +from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes +from ..mods.logic.mod_logic import ModLogic from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions from ..regions import vanilla_regions from ..stardew_rule import False_, Or, True_, Count, And, StardewRule @@ -52,7 +53,6 @@ from ..strings.ap_names.community_upgrade_names import CommunityUpgrade from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building -from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.decoration_names import Decoration @@ -60,15 +60,15 @@ from ..strings.festival_check_names import FestivalCheck from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest from ..strings.flower_names import Flower +from ..strings.food_names import Meal, Beverage from ..strings.forageable_names import Forageable from ..strings.fruit_tree_names import Sapling from ..strings.generic_names import Generic from ..strings.geode_names import Geode from ..strings.gift_names import Gift from ..strings.ingredient_names import Ingredient -from ..strings.material_names import Material from ..strings.machine_names import Machine -from ..strings.food_names import Meal, Beverage +from ..strings.material_names import Material from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil from ..strings.monster_drop_names import Loot from ..strings.monster_names import Monster @@ -123,8 +123,7 @@ def __post_init__(self): mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island self.buildings = BuildingLogic(self.player, self.cached_rules, self.options.building_progression, self.received, self.has, self.region, self.money) - self.shipping = ShippingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.has, - self.region, self.buildings) + self.shipping = ShippingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.has, self.region, self.buildings) self.relationship = RelationshipLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.cached_rules, self.options.museumsanity, self.received, self.has, self.region, self.action) @@ -133,14 +132,18 @@ def __post_init__(self): self.monster = MonsterLogic(self.player, self.cached_rules, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, self.cached_rules, tool_option, self.received, self.has, self.region, self.season, self.money) self.pet = PetLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) - self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, self.received, self.has, self.region, self.traveling_merchant, self.season, self.money, self.tool) - self.skill = SkillLogic(self.player, self.cached_rules, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) + self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, self.received, self.has, self.region, self.traveling_merchant, + self.season, self.money, self.tool) + self.skill = SkillLogic(self.player, self.cached_rules, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, + self.combat, self.crop) self.farming = FarmingLogic(self.player, self.has, self.skill) self.bundle = BundleLogic(self.player, self.cached_rules, self.has, self.region, self.money, self.farming) - self.fishing = FishingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, self.tool, self.skill) + self.fishing = FishingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, + self.tool, self.skill) self.mine = MineLogic(self.player, self.cached_rules, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.cached_rules, mods_option, self.options.chefsanity, exclude_ginger_island, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) + self.cooking = CookingLogic(self.player, self.cached_rules, mods_option, self.options.chefsanity, exclude_ginger_island, self.received, self.has, + self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, @@ -150,9 +153,9 @@ def __post_init__(self): self.crafting = CraftingLogic(self.player, self.cached_rules, self.options.craftsanity, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, self.season, self.money, - self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, - self.time, self.quest, self.crafting, self.crop) + self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, + self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, + self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in all_fish}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) @@ -201,9 +204,10 @@ def __post_init__(self): self.crop_rules.update({ Seed.coffee: (self.season.has(Season.spring) | self.season.has(Season.summer)) & self.crop.can_buy_seed(crops_by_name[Seed.coffee].seed), Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & - self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), + self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), }) + # @formatter:off self.item_rules.update({ "Energy Tonic": self.money.can_spend_at(Region.hospital, 1000), WaterChest.fishing_chest: self.fishing.can_fish_chests(), @@ -235,7 +239,7 @@ def __post_init__(self): Animal.sheep: self.can_buy_animal(Animal.sheep), AnimalProduct.any_egg: self.has(AnimalProduct.chicken_egg) | self.has(AnimalProduct.duck_egg), AnimalProduct.brown_egg: self.has_animal(Animal.chicken), - AnimalProduct.chicken_egg: self.has([AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg], 1), + AnimalProduct.chicken_egg: self.has((AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg), 1), AnimalProduct.cow_milk: self.has(AnimalProduct.milk) | self.has(AnimalProduct.large_milk), AnimalProduct.duck_egg: self.has_animal(Animal.duck), AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), @@ -319,7 +323,7 @@ def __post_init__(self): Forageable.hay: self.buildings.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), Forageable.hazelnut: self.tool.can_forage(Season.fall), Forageable.holly: self.tool.can_forage(Season.winter), - Forageable.journal_scrap: self.region.can_reach_all([Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10]) & self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), + Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), Forageable.leek: self.tool.can_forage(Season.spring), Forageable.magma_cap: self.tool.can_forage(Generic.any, Region.volcano_floor_5), Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods), @@ -390,7 +394,7 @@ def __post_init__(self): Machine.enricher: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 20), Machine.pressure_nozzle: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 20), Material.cinder_shard: self.region.can_reach(Region.volcano_floor_5), - Material.clay: self.region.can_reach_any([Region.farm, Region.beach, Region.quarry]) & self.tool.has_tool(Tool.hoe), + Material.clay: self.region.can_reach_any((Region.farm, Region.beach, Region.quarry)) & self.tool.has_tool(Tool.hoe), Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.action.can_pan(), Material.fiber: True_(), Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_west)), @@ -415,7 +419,7 @@ def __post_init__(self): Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), - Seed.mixed: self.tool.has_tool(Tool.scythe) & self.region.can_reach_all([Region.farm, Region.forest, Region.town]), + Seed.mixed: self.tool.has_tool(Tool.scythe) & self.region.can_reach_all((Region.farm, Region.forest, Region.town)), Trash.broken_cd: self.skill.can_crab_pot(), Trash.broken_glasses: self.skill.can_crab_pot(), Trash.driftwood: self.skill.can_crab_pot(), @@ -437,6 +441,7 @@ def __post_init__(self): WaterItem.seaweed: self.skill.can_fish(Region.beach) | self.region.can_reach(Region.tide_pools), WaterItem.white_algae: self.skill.can_fish(Region.mines_floor_20), }) + # @formatter:on self.item_rules.update(self.fish_rules) self.item_rules.update(self.museum_rules) self.item_rules.update(self.sapling_rules) @@ -595,13 +600,13 @@ def can_win_egg_hunt(self) -> StardewRule: def can_succeed_luau_soup(self) -> StardewRule: if self.options.festival_locations != FestivalLocations.option_hard: return True_() - eligible_fish = [Fish.blobfish, Fish.crimsonfish, "Ice Pip", Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish, - Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, "Super Cucumber"] + eligible_fish = [Fish.blobfish, Fish.crimsonfish, "Ice Pip", Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish, Fish.mutant_carp, + Fish.spookfish, Fish.stingray, Fish.sturgeon, "Super Cucumber"] fish_rule = [self.has(fish) for fish in eligible_fish] - eligible_kegables = [Fruit.ancient_fruit, Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, - Fruit.melon, Fruit.orange, Fruit.peach, Fruit.pineapple, Fruit.pomegranate, Fruit.rhubarb, - Fruit.starfruit, Fruit.strawberry, Forageable.cactus_fruit, - Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, Vegetable.hops, Vegetable.wheat] + eligible_kegables = [Fruit.ancient_fruit, Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.melon, + Fruit.orange, Fruit.peach, Fruit.pineapple, Fruit.pomegranate, Fruit.rhubarb, Fruit.starfruit, Fruit.strawberry, + Forageable.cactus_fruit, Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, + Vegetable.hops, Vegetable.wheat] keg_rules = [self.artisan.can_keg(kegable) for kegable in eligible_kegables] aged_rule = self.has(Machine.cask) & Or(keg_rules) # There are a few other valid items but I don't feel like coding them all @@ -613,11 +618,10 @@ def can_succeed_grange_display(self) -> StardewRule: animal_rule = self.has_animal(Generic.any) artisan_rule = self.artisan.can_keg(Generic.any) | self.artisan.can_preserves_jar(Generic.any) cooking_rule = self.money.can_spend_at(Region.saloon, 220) # Salads at the bar are good enough - fish_rule = self.skill.can_fish([], 50) - forage_rule = self.region.can_reach_any([Region.forest, Region.backwoods]) # Hazelnut always available since the grange display is in fall + fish_rule = self.skill.can_fish(difficulty=50) + forage_rule = self.region.can_reach_any((Region.forest, Region.backwoods)) # Hazelnut always available since the grange display is in fall mineral_rule = self.action.can_open_geode(Generic.any) # More than half the minerals are good enough - good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, - Fruit.pomegranate, + good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, Fruit.pomegranate, Fruit.strawberry, Fruit.melon, Fruit.rhubarb, Fruit.pineapple, Fruit.ancient_fruit, Fruit.starfruit, ] fruit_rule = Or([self.has(fruit) for fruit in good_fruits]) good_vegetables = [Vegetable.amaranth, Vegetable.artichoke, Vegetable.beet, Vegetable.cauliflower, Forageable.fiddlehead_fern, Vegetable.kale, @@ -625,10 +629,10 @@ def can_succeed_grange_display(self) -> StardewRule: vegetable_rule = Or([self.has(vegetable) for vegetable in good_vegetables]) return animal_rule & artisan_rule & cooking_rule & fish_rule & \ - forage_rule & fruit_rule & mineral_rule & vegetable_rule + forage_rule & fruit_rule & mineral_rule & vegetable_rule def can_win_fishing_competition(self) -> StardewRule: - return self.skill.can_fish([], 60) + return self.skill.can_fish(difficulty=60) def can_buy_animal(self, animal: str) -> StardewRule: price = 0 @@ -724,10 +728,10 @@ def has_walnut(self, number: int) -> StardewRule: return reach_entire_island gems = [Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz] return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ - self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) + self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) - def has_everything(self, all_progression_items: Set[str]) -> StardewRule: - all_regions = [region.name for region in vanilla_regions] + def has_everything(self, all_progression_items: frozenset[str]) -> StardewRule: + all_regions = tuple(region.name for region in vanilla_regions) rules = self.received(all_progression_items, len(all_progression_items)) & \ self.region.can_reach_all(all_regions) return rules @@ -751,4 +755,3 @@ def has_movie_theater(self) -> StardewRule: def can_use_obelisk(self, obelisk: str) -> StardewRule: return self.region.can_reach(Region.wizard_tower) & self.received(obelisk) - diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 67359ddfe5c4..9847cf53efe1 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule, profile_rule +from functools import lru_cache + +from .cached_logic import CachedLogic from .combat_logic import CombatLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -25,7 +27,9 @@ class MineLogic(CachedLogic): skill: SkillLogic mod_elevator: ModElevatorLogic - def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, region: RegionLogic, + def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, + skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, + region: RegionLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): super().__init__(player, cached_rules) self.tool_option = tool_option @@ -65,7 +69,7 @@ def get_weapon_rule_for_floor_tier(self, tier: int): return self.combat.can_fight_at_level(Performance.decent) return self.combat.can_fight_at_level(Performance.basic) - @cache_rule + @lru_cache(maxsize=None) def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: tier = floor // 40 rules = [] @@ -79,7 +83,7 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: rules.append(self.skill.has_level(Skill.mining, skill_tier)) return And(rules) - @cache_rule + @lru_cache(maxsize=None) def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: if floor < 0: floor = 0 @@ -87,7 +91,7 @@ def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: return self.received("Progressive Mine Elevator", floor // 5) return True_() - @cache_rule + @lru_cache(maxsize=None) def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: tier = floor // 50 rules = [] @@ -100,4 +104,3 @@ def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule rules.extend({self.skill.has_level(Skill.combat, skill_tier), self.skill.has_level(Skill.mining, skill_tier)}) return And(rules) - diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 14f9f8aa5cc2..14662bf46518 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule +from functools import lru_cache + +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -10,7 +12,8 @@ MONEY_PER_MONTH = 15000 DISPOSABLE_INCOME_DIVISOR = 5 -qi_gem_rewards = ["100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", "25 Qi Gems", "20 Qi Gems", "10 Qi Gems"] +qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", + "25 Qi Gems", "20 Qi Gems", "10 Qi Gems") class MoneyLogic(CachedLogic): @@ -20,7 +23,8 @@ class MoneyLogic(CachedLogic): region: RegionLogic time: TimeLogic - def __init__(self, player: int, cached_rules: CachedRules, starting_money_option: StartingMoney, received: ReceivedLogic, + def __init__(self, player: int, cached_rules: CachedRules, starting_money_option: StartingMoney, + received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): super().__init__(player, cached_rules) self.starting_money_option = starting_money_option @@ -29,23 +33,23 @@ def __init__(self, player: int, cached_rules: CachedRules, starting_money_option self.region = region self.time = time - @cache_rule + @lru_cache(maxsize=None) def can_have_earned_total(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() return self.time.has_lived_months(amount // MONEY_PER_MONTH) - @cache_rule + @lru_cache(maxsize=None) def can_spend(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() return self.time.has_lived_months(amount // (MONEY_PER_MONTH // DISPOSABLE_INCOME_DIVISOR)) - @cache_rule + @lru_cache(maxsize=None) def can_spend_at(self, region: str, amount: int) -> StardewRule: return self.region.can_reach(region) & self.can_spend(amount) - @cache_rule + @lru_cache(maxsize=None) def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() @@ -56,5 +60,3 @@ def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: return self.received(qi_gem_rewards, number_rewards) return self.region.can_reach(region) & self.has(currency) - - diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index b980ef219c1e..d6040875831f 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,6 +1,7 @@ -from typing import Iterable, Union +from functools import lru_cache +from typing import Iterable, Union, Hashable -from .cached_logic import CachedLogic, CachedRules, cache_rule +from .cached_logic import CachedLogic, CachedRules from .combat_logic import CombatLogic from .region_logic import RegionLogic from .time_logic import TimeLogic, MAX_MONTHS @@ -13,13 +14,14 @@ class MonsterLogic(CachedLogic): time: TimeLogic combat: CombatLogic - def __init__(self, player: int, cached_rules: CachedRules, region: RegionLogic, time: TimeLogic, combat: CombatLogic): + def __init__(self, player: int, cached_rules: CachedRules, region: RegionLogic, time: TimeLogic, + combat: CombatLogic): super().__init__(player, cached_rules) self.region = region self.time = time self.combat = combat - @cache_rule + @lru_cache(maxsize=None) def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): monster = all_monsters_by_name[monster] @@ -30,17 +32,16 @@ def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> time_rule = self.time.has_lived_months(amount_tier * 2) return region_rule & combat_rule & time_rule - @cache_rule + @lru_cache(maxsize=None) def can_kill_max(self, monster: StardewMonster) -> StardewRule: return self.can_kill(monster, MAX_MONTHS) - @cache_rule - def can_kill_any(self, monsters: Iterable[StardewMonster], amount_tier: int = 0) -> StardewRule: + @lru_cache(maxsize=None) + def can_kill_any(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] return Or(rules) - @cache_rule - def can_kill_all(self, monsters: Iterable[StardewMonster], amount_tier: int = 0) -> StardewRule: + @lru_cache(maxsize=None) + def can_kill_all(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] return And(rules) - diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 9857114bb655..8f069c66223a 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -1,14 +1,15 @@ +from functools import lru_cache from typing import List from .action_logic import ActionLogic -from .cached_logic import CachedLogic, cache_rule, profile_rule +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules +from .received_logic import ReceivedLogic +from .region_logic import RegionLogic from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals from ..options import Museumsanity from ..stardew_rule import StardewRule, And, False_, Count -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic from ..strings.region_names import Region @@ -20,7 +21,8 @@ class MuseumLogic(CachedLogic): region: RegionLogic action: ActionLogic - def __init__(self, player: int, cached_rules: CachedRules, museum_option: Museumsanity, received: ReceivedLogic, has: HasLogic, + def __init__(self, player: int, cached_rules: CachedRules, museum_option: Museumsanity, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, action: ActionLogic): super().__init__(player, cached_rules) self.museum_option = museum_option @@ -35,7 +37,7 @@ def can_donate_museum_items(self, number: int) -> StardewRule: def can_donate_museum_artifacts(self, number: int) -> StardewRule: return self.region.can_reach(Region.museum) & self.can_find_museum_artifacts(number) - @cache_rule + @lru_cache(maxsize=None) def can_find_museum_item(self, item: MuseumItem) -> StardewRule: region_rule = self.region.can_reach_all_except_one(item.locations) geodes_rule = And([self.action.can_open_geode(geode) for geode in item.geodes]) diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 780be49ed189..62ac54fe280b 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -1,9 +1,7 @@ from typing import Dict -from dataclasses import field from .action_logic import ActionLogic from .building_logic import BuildingLogic -from .cached_logic import profile_rule from .combat_logic import CombatLogic from .cooking_logic import CookingLogic from .fishing_logic import FishingLogic @@ -18,7 +16,8 @@ from .time_logic import TimeLogic from .tool_logic import ToolLogic from .wallet_logic import WalletLogic -from ..options import SkillProgression, Mods +from ..options import Mods +from ..stardew_rule import StardewRule, Has, True_ from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building from ..strings.craftable_names import Craftable @@ -27,16 +26,15 @@ from ..strings.food_names import Meal from ..strings.forageable_names import Forageable from ..strings.machine_names import Machine -from ..strings.monster_drop_names import Loot from ..strings.material_names import Material from ..strings.metal_names import MetalBar, Ore, Mineral +from ..strings.monster_drop_names import Loot +from ..strings.quest_names import Quest from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.tool_names import Tool -from ..strings.quest_names import Quest from ..strings.villager_names import NPC from ..strings.wallet_item_names import Wallet -from ..stardew_rule import StardewRule, Has, True_ class QuestLogic: @@ -89,7 +87,7 @@ def initialize_rules(self): Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.building.has_building(Building.coop), Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), Quest.archaeology: self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish(), - Quest.rat_problem: self.region.can_reach_all([Region.town, Region.community_center]), + Quest.rat_problem: self.region.can_reach_all((Region.town, Region.community_center)), Quest.meet_the_wizard: self.can_complete_quest(Quest.rat_problem), Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), Quest.smelting: self.has(MetalBar.copper), @@ -107,7 +105,7 @@ def initialize_rules(self): Quest.knee_therapy: self.season.has(Season.summer) & self.has(Fruit.hot_pepper) & self.relationship.can_meet(NPC.george), Quest.robins_request: self.season.has(Season.winter) & self.has(Material.hardwood) & self.relationship.can_meet(NPC.robin), Quest.qis_challenge: True_(), # The skull cavern floor 25 already has rules - Quest.the_mysterious_qi: self.region.can_reach_all([Region.bus_tunnel, Region.railroad, Region.mayor_house]) & + Quest.the_mysterious_qi: self.region.can_reach_all((Region.bus_tunnel, Region.railroad, Region.mayor_house)) & self.has(ArtisanGood.battery_pack) & self.has(Forageable.rainbow_shell) & self.has(Vegetable.beet) & self.has(Loot.solar_essence), Quest.carving_pumpkins: self.season.has(Season.fall) & self.has(Vegetable.pumpkin) & self.relationship.can_meet(NPC.caroline), diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 96938b48f33c..389c4c3b9880 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,6 +1,7 @@ -from typing import Iterable, Union, Optional +from functools import lru_cache +from typing import Union, Optional, Tuple -from .cached_logic import CachedLogic, cache_rule, CachedRules +from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived @@ -15,8 +16,8 @@ def __call__(self, *args, **kwargs) -> StardewRule: count = args[1] return self.received(args[0], count) - @cache_rule - def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) -> StardewRule: + @lru_cache(maxsize=None) + def received(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = 1) -> StardewRule: if count <= 0 or not items: return True_() @@ -30,4 +31,3 @@ def received(self, items: Union[str, Iterable[str]], count: Optional[int] = 1) - return Or(self.received(item) for item in items) return TotalReceived(count, items, self.player) - diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index d6a1e1faa4e4..f91beb519920 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,6 +1,7 @@ -from typing import Iterable, List +from functools import lru_cache +from typing import Tuple -from .cached_logic import CachedLogic, cache_rule, CachedRules +from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, And, Or, Reach, Count @@ -9,31 +10,30 @@ class RegionLogic(CachedLogic): def __init__(self, player: int, cached_rules: CachedRules): super().__init__(player, cached_rules) - @cache_rule + @lru_cache(maxsize=None) def can_reach(self, region_name: str) -> StardewRule: return Reach(region_name, "Region", self.player) - @cache_rule - def can_reach_any(self, region_names: Iterable[str]) -> StardewRule: + @lru_cache(maxsize=None) + def can_reach_any(self, region_names: Tuple[str, ...]) -> StardewRule: return Or(self.can_reach(spot) for spot in region_names) - @cache_rule - def can_reach_all(self, region_names: Iterable[str]) -> StardewRule: + @lru_cache(maxsize=None) + def can_reach_all(self, region_names: Tuple[str, ...]) -> StardewRule: return And(self.can_reach(spot) for spot in region_names) - @cache_rule - def can_reach_all_except_one(self, region_names: Iterable[str]) -> StardewRule: + @lru_cache(maxsize=None) + def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule: region_names = list(region_names) num_required = len(region_names) - 1 if num_required <= 0: num_required = len(region_names) return Count(num_required, [self.can_reach(spot) for spot in region_names]) - @cache_rule + @lru_cache(maxsize=None) def can_reach_location(self, location_names: str) -> StardewRule: return Reach(location_names, "Location", self.player) - @cache_rule + @lru_cache(maxsize=None) def can_reach_entrance(self, entrance_name: str) -> StardewRule: return Reach(entrance_name, "Entrance", self.player) - diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index f2e1573e9681..34ee0645aafe 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -1,5 +1,5 @@ import math - +from functools import lru_cache from typing import Iterable, Union from .building_logic import BuildingLogic @@ -16,8 +16,10 @@ from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic from ..strings.gift_names import Gift -from ..strings.villager_names import NPC, ModNPC from ..strings.region_names import Region +from ..strings.villager_names import NPC, ModNPC + +possible_kids = ("Cute Baby", "Ugly Baby") class RelationshipLogic(CachedLogic): @@ -32,7 +34,8 @@ class RelationshipLogic(CachedLogic): buildings: BuildingLogic mods_option: Mods - def __init__(self, player: int, cached_rules: CachedRules, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, + def __init__(self, player: int, cached_rules: CachedRules, friendsanity_option: Friendsanity, + heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): super().__init__(player, cached_rules) @@ -59,16 +62,16 @@ def can_get_married(self) -> StardewRule: def has_children(self, number_children: int) -> StardewRule: if number_children <= 0: return True_() - possible_kids = ["Cute Baby", "Ugly Baby"] return self.received(possible_kids, number_children) & self.buildings.has_house(2) def can_reproduce(self, number_children: int = 1) -> StardewRule: if number_children <= 0: return True_() - baby_rules = [self.can_get_married(), self.buildings.has_house(2), self.has_hearts(Generic.bachelor, 12), self.has_children(number_children - 1)] + baby_rules = [self.can_get_married(), self.buildings.has_house(2), self.has_hearts(Generic.bachelor, 12), + self.has_children(number_children - 1)] return And(baby_rules) - @cache_rule + @lru_cache(maxsize=None) def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() @@ -111,11 +114,11 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) return self.received_hearts(villager.name, hearts) - @cache_rule + @lru_cache(maxsize=None) def received_hearts(self, npc: str, hearts: int) -> StardewRule: return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) - @cache_rule + @lru_cache(maxsize=None) def can_meet(self, npc: str) -> StardewRule: if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): return True_() @@ -140,7 +143,7 @@ def can_give_loved_gifts_to_everyone(self) -> StardewRule: loved_gifts_rules = And(rules) & self.gifts.has_any_universal_love() return loved_gifts_rules - @cache_rule + @lru_cache(maxsize=None) def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: if hearts <= 0: return True_() @@ -176,4 +179,3 @@ def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): return f"{npc} <3" return self.heart(npc.name) - diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 3b494e9df5f0..182ebd80c7bd 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,6 +1,7 @@ +from functools import lru_cache from typing import Iterable -from .cached_logic import cache_rule, CachedLogic, CachedRules +from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .time_logic import TimeLogic from ..options import SeasonRandomization @@ -14,13 +15,14 @@ class SeasonLogic(CachedLogic): received: ReceivedLogic time: TimeLogic - def __init__(self, player: int, cached_rules: CachedRules, season_option: SeasonRandomization, received_logic: ReceivedLogic, time: TimeLogic): + def __init__(self, player: int, cached_rules: CachedRules, season_option: SeasonRandomization, + received_logic: ReceivedLogic, time: TimeLogic): super().__init__(player, cached_rules) self.season_option = season_option self.received = received_logic self.time = time - @cache_rule + @lru_cache(maxsize=None) def has(self, season: str) -> StardewRule: if season == Generic.any: return True_() @@ -45,4 +47,3 @@ def has_all(self, seasons: Iterable[str]): if not seasons: return True_() return And([self.has(season) for season in seasons]) - diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index f1d27bde93cd..df95ba1e3e76 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,10 +1,11 @@ +from functools import lru_cache from .building_logic import BuildingLogic -from .cached_logic import profile_rule, CachedLogic, CachedRules, cache_rule +from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic from .region_logic import RegionLogic -from ..options import ExcludeGingerIsland from ..locations import LocationTags, locations_by_tag +from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, And from ..strings.building_names import Building @@ -18,7 +19,8 @@ class ShippingLogic(CachedLogic): region: RegionLogic buildings: BuildingLogic - def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations, + def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, + special_orders_option: SpecialOrderLocations, has: HasLogic, region: RegionLogic, buildings: BuildingLogic): super().__init__(player, cached_rules) self.exclude_ginger_island = exclude_ginger_island @@ -30,7 +32,7 @@ def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island def can_use_shipping_bin(self, item: str = "") -> StardewRule: return self.buildings.has_building(Building.shipping_bin) - @cache_rule + @lru_cache(maxsize=None) def can_ship(self, item: str = "") -> StardewRule: shipping_rule = self.region.can_reach(Region.shipping) if item == "": @@ -44,6 +46,6 @@ def can_ship_everything(self) -> StardewRule: include_qi = self.special_orders_option == SpecialOrderLocations.option_board_qi for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ - (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): + (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): all_items_to_ship.append(location.name[len(shipsanity_prefix):]) return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index e9b85c427da1..de6cdf058f00 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -1,6 +1,8 @@ -from typing import Iterable, List, Union +from functools import lru_cache +from typing import Union, Tuple -from .cached_logic import CachedLogic, cache_rule +from worlds.stardew_valley.strings.craftable_names import Fishing +from .cached_logic import CachedLogic from .combat_logic import CombatLogic from .crop_logic import CropLogic from .has_logic import HasLogic, CachedRules @@ -15,7 +17,6 @@ from ..mods.logic.mod_skills_levels import get_mod_skill_levels from ..options import SkillProgression, Mods from ..stardew_rule import StardewRule, True_, Or -from worlds.stardew_valley.strings.craftable_names import Craftable, Fishing from ..strings.generic_names import Generic from ..strings.machine_names import Machine from ..strings.performance_names import Performance @@ -23,7 +24,7 @@ from ..strings.skill_names import Skill from ..strings.tool_names import ToolMaterial, Tool -fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] +fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west) class SkillLogic(CachedLogic): @@ -39,7 +40,8 @@ class SkillLogic(CachedLogic): magic: MagicLogic mods: Mods - def __init__(self, player: int, cached_rules: CachedRules, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, + def __init__(self, player: int, cached_rules: CachedRules, skill_option: SkillProgression, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): super().__init__(player, cached_rules) self.skill_option = skill_option @@ -56,7 +58,7 @@ def set_mod_logic(self, magic: MagicLogic, mods: Mods): self.magic = magic self.mods = mods - @cache_rule + @lru_cache(maxsize=None) def can_earn_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -72,9 +74,13 @@ def can_earn_level(self, skill: str, level: int) -> StardewRule: elif skill == Skill.farming: xp_rule = self.tool.has_tool(Tool.hoe, tool_material) & self.tool.can_water(tool_level) elif skill == Skill.foraging: - xp_rule = self.tool.has_tool(Tool.axe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level) + xp_rule = self.tool.has_tool(Tool.axe, + tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level( + tool_level) elif skill == Skill.mining: - xp_rule = self.tool.has_tool(Tool.pickaxe, tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level(tool_level) + xp_rule = self.tool.has_tool(Tool.pickaxe, + tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level( + tool_level) elif skill == Skill.combat: combat_tier = Performance.tiers[tool_level] xp_rule = self.combat.can_fight_at_level(combat_tier) @@ -83,7 +89,7 @@ def can_earn_level(self, skill: str, level: int) -> StardewRule: return previous_level_rule & months_rule & xp_rule - @cache_rule + @lru_cache(maxsize=None) def has_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -93,20 +99,19 @@ def has_level(self, skill: str, level: int) -> StardewRule: return self.can_earn_level(skill, level) - @cache_rule + @lru_cache(maxsize=None) def has_farming_level(self, level: int) -> StardewRule: return self.has_level(Skill.farming, level) - @cache_rule + @lru_cache(maxsize=None) def has_total_level(self, level: int, allow_modded_skills: bool = False) -> StardewRule: if level <= 0: return True_() if self.skill_option == options.SkillProgression.option_progressive: - skills_items = ["Farming Level", "Mining Level", "Foraging Level", - "Fishing Level", "Combat Level"] + skills_items = ("Farming Level", "Mining Level", "Foraging Level", "Fishing Level", "Combat Level") if allow_modded_skills: - skills_items.extend(get_mod_skill_levels(self.mods)) + skills_items += get_mod_skill_levels(self.mods) return self.received(skills_items, level) months_with_4_skills = max(1, (level // 4) - 1) @@ -116,43 +121,43 @@ def has_total_level(self, level: int, allow_modded_skills: bool = False) -> Star return rule_with_fishing return self.time.has_lived_months(months_with_4_skills) | rule_with_fishing - @cache_rule + @lru_cache(maxsize=None) def can_get_farming_xp(self) -> StardewRule: crop_rules = [] for crop in all_crops: crop_rules.append(self.crop.can_grow(crop)) return Or(crop_rules) - @cache_rule + @lru_cache(maxsize=None) def can_get_foraging_xp(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.axe) tree_rule = self.region.can_reach(Region.forest) & self.season.has_any_not_winter() stump_rule = self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.copper) return tool_rule & (tree_rule | stump_rule) - @cache_rule + @lru_cache(maxsize=None) def can_get_mining_xp(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.pickaxe) - stone_rule = self.region.can_reach_any([Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5]) + stone_rule = self.region.can_reach_any((Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5)) return tool_rule & stone_rule - @cache_rule + @lru_cache(maxsize=None) def can_get_combat_xp(self) -> StardewRule: tool_rule = self.combat.has_any_weapon() - enemy_rule = self.region.can_reach_any([Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5]) + enemy_rule = self.region.can_reach_any((Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5)) return tool_rule & enemy_rule - @cache_rule + @lru_cache(maxsize=None) def can_get_fishing_xp(self) -> StardewRule: if self.skill_option == options.SkillProgression.option_progressive: return self.can_fish() | self.can_crab_pot() return self.can_fish() - @cache_rule - def can_fish(self, regions: Union[str, List[str]] = None, difficulty: int = 0) -> StardewRule: + @lru_cache(maxsize=None) + def can_fish(self, regions: Union[str, Tuple[str, ...]] = None, difficulty: int = 0) -> StardewRule: if isinstance(regions, str): - regions = [regions] + regions = regions, if regions is None or len(regions) == 0: regions = fishing_regions skill_required = min(10, max(0, int((difficulty / 10) - 1))) @@ -163,7 +168,7 @@ def can_fish(self, regions: Union[str, List[str]] = None, difficulty: int = 0) - number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule - @cache_rule + @lru_cache(maxsize=None) def can_crab_pot(self, region: str = Generic.any) -> StardewRule: crab_pot_rule = self.has(Fishing.bait) if self.skill_option == options.SkillProgression.option_progressive: @@ -176,4 +181,3 @@ def can_crab_pot(self, region: str = Generic.any) -> StardewRule: water_region_rules = self.region.can_reach_any(fishing_regions) return crab_pot_rule & water_region_rules - diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 3f4c1a2b27d0..bd4611e94d7d 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule, CachedRules, profile_rule +from functools import lru_cache + +from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule from ..strings.ap_names.event_names import Event @@ -13,7 +15,7 @@ def __init__(self, player: int, cached_rules: CachedRules, received_logic: Recei super().__init__(player, cached_rules) self.received = received_logic - @cache_rule + @lru_cache(maxsize=None) def has_lived_months(self, number: int) -> StardewRule: number = max(0, min(number, MAX_MONTHS)) return self.received(Event.month_end, number) @@ -26,4 +28,3 @@ def has_year_two(self) -> StardewRule: def has_year_three(self) -> StardewRule: return self.has_lived_months(8) - diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 0fcc0cc76649..03d30e4d42d7 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,4 +1,6 @@ -from .cached_logic import CachedLogic, cache_rule +from functools import lru_cache + +from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -12,7 +14,6 @@ from ..strings.spells import MagicSpell from ..strings.tool_names import ToolMaterial, Tool - tool_materials = { ToolMaterial.copper: 1, ToolMaterial.iron: 2, @@ -37,7 +38,8 @@ class ToolLogic(CachedLogic): money: MoneyLogic magic: MagicLogic - def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, season: SeasonLogic, money: MoneyLogic): super().__init__(player, cached_rules) self.tool_option = tool_option @@ -50,7 +52,7 @@ def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProg def set_magic(self, magic: MagicLogic): self.magic = magic - @cache_rule + @lru_cache(maxsize=None) def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: if material == ToolMaterial.basic or tool == Tool.scythe: return True_() @@ -60,7 +62,7 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) - @cache_rule + @lru_cache(maxsize=None) def has_fishing_rod(self, level: int) -> StardewRule: if self.tool_option & ToolProgression.option_progressive: return self.received(f"Progressive {Tool.fishing_rod}", level) @@ -71,7 +73,7 @@ def has_fishing_rod(self, level: int) -> StardewRule: level = min(level, 4) return self.money.can_spend_at(Region.fish_shop, prices[level]) - @cache_rule + @lru_cache(maxsize=None) def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: season_rule = self.season.has(season) region_rule = self.region.can_reach(region) @@ -79,9 +81,9 @@ def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = return season_rule & region_rule & self.has_tool(Tool.hoe) return season_rule & region_rule - @cache_rule + @lru_cache(maxsize=None) def can_water(self, level: int) -> StardewRule: tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) - spell_rule = self.received(MagicSpell.water) & self.magic.can_use_altar() & self.received(f"{ModSkill.magic} Level", level) + spell_rule = self.received(MagicSpell.water) & self.magic.can_use_altar() & self.received( + f"{ModSkill.magic} Level", level) return tool_rule | spell_rule - diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index b70847c60c27..4b8bf0583c12 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,4 +1,3 @@ -from .cached_logic import profile_rule from .received_logic import ReceivedLogic from ..stardew_rule import True_ from ..strings.calendar_names import Weekday @@ -16,6 +15,5 @@ def has_days(self, number_days: int = 1): if number_days <= 0: return True_() tier = min(7, max(1, number_days)) - traveling_merchant_days = [f"Traveling Merchant: {day}" for day in Weekday.all_days] + traveling_merchant_days = tuple(f"Traveling Merchant: {day}" for day in Weekday.all_days) return self.received(traveling_merchant_days, tier) - diff --git a/worlds/stardew_valley/mods/logic/mod_skills_levels.py b/worlds/stardew_valley/mods/logic/mod_skills_levels.py index c1b2c305ec17..18402283857b 100644 --- a/worlds/stardew_valley/mods/logic/mod_skills_levels.py +++ b/worlds/stardew_valley/mods/logic/mod_skills_levels.py @@ -1,9 +1,10 @@ -from typing import List, Iterable +from typing import Tuple + from ...mods.mod_data import ModNames from ...options import Mods -def get_mod_skill_levels(mods: Mods) -> List[str]: +def get_mod_skill_levels(mods: Mods) -> Tuple[str]: skills_items = [] if ModNames.luck_skill in mods: skills_items.append("Luck Level") @@ -17,4 +18,4 @@ def get_mod_skill_levels(mods: Mods) -> List[str]: skills_items.append("Binning Level") if ModNames.cooking_skill in mods: skills_items.append("Cooking Level") - return skills_items + return tuple(skills_items) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 7432c24b7ac1..ecbc47c141a0 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -5,7 +5,6 @@ from worlds.generic import Rules as MultiWorldRules from worlds.stardew_valley.strings.craftable_names import Bomb from . import locations -from .options import StardewValleyOptions from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals, \ @@ -15,6 +14,7 @@ from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices from .mods.mod_data import ModNames +from .options import StardewValleyOptions from .options import ToolProgression, BuildingProgression, ExcludeGingerIsland, SpecialOrderLocations, Museumsanity, BackpackProgression, Shipsanity, \ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And @@ -119,7 +119,7 @@ def set_building_rules(logic: StardewLogic, multiworld, player, world_options: S def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): for bundle in current_bundles.values(): location = multiworld.get_location(bundle.get_name_with_bundle(), player) - rules = logic.bundle.can_complete_bundle(bundle.requirements, bundle.number_required) + rules = logic.bundle.can_complete_bundle(tuple(bundle.requirements), bundle.number_required) simplified_rules = rules MultiWorldRules.set_rule(location, simplified_rules) MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), @@ -559,7 +559,8 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi if museum_location.name in all_location_names: donation_name = museum_location.name[len(museum_prefix):] required_detectors = counter * 5 // number_donations - rule = logic.museum.can_find_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", required_detectors) + rule = logic.museum.can_find_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", + required_detectors) MultiWorldRules.set_rule(multiworld.get_location(museum_location.name, player), rule) counter += 1 @@ -858,9 +859,9 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), logic.has("Fire Quartz")) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85))) + (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)).simplify()) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), - (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish([], 85))) + (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)).simplify()) # MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player),) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Tendrils", player), logic.region.can_reach(Region.farm)) @@ -883,7 +884,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & logic.has("Coffee") & logic.has("Life Elixir") & logic.ability.can_mine_perfectly() & logic.has("Earth Crystal") & - logic.has("Fire Quartz") & logic.skill.can_fish([], 85) & + logic.has("Fire Quartz") & logic.skill.can_fish(difficulty=85) & logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12))) @@ -942,4 +943,3 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla logic.received("Marlon's Boat Paddle")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), logic.received("Fable Reef Portal")) - diff --git a/worlds/stardew_valley/strings/crop_names.py b/worlds/stardew_valley/strings/crop_names.py index 2ae8eb2cbc62..c6a34c02c30d 100644 --- a/worlds/stardew_valley/strings/crop_names.py +++ b/worlds/stardew_valley/strings/crop_names.py @@ -71,3 +71,6 @@ class SVEVegetable: void_root = "Void Root" ancient_fiber = "Ancient Fiber" + +all_vegetables = tuple(all_vegetables) +all_fruits = tuple(all_fruits) From 3aead3f61033772d07b25e866eb1a1f677049d33 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:12:01 -0500 Subject: [PATCH 145/482] - Fix test options with the rename --- worlds/stardew_valley/test/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 415bc058343f..ff95453c3ce1 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -64,7 +64,7 @@ def minimal_locations_maximal_items(): BundleRandomization.internal_name: BundleRandomization.option_vanilla, BundlePrice.internal_name: BundlePrice.option_very_cheap, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_shuffled, + Cropsanity.internal_name: Cropsanity.option_enabled, BackpackProgression.internal_name: BackpackProgression.option_vanilla, ToolProgression.internal_name: ToolProgression.option_vanilla, SkillProgression.internal_name: SkillProgression.option_vanilla, @@ -99,7 +99,7 @@ def allsanity_options_without_mods(): BundleRandomization.internal_name: BundleRandomization.option_thematic, BundlePrice.internal_name: BundlePrice.option_expensive, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_shuffled, + Cropsanity.internal_name: Cropsanity.option_enabled, BackpackProgression.internal_name: BackpackProgression.option_progressive, ToolProgression.internal_name: ToolProgression.option_progressive, SkillProgression.internal_name: SkillProgression.option_progressive, From 04f3dea993d2f18ae540d5cdd07df7c283c8de49 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 14 Nov 2023 07:42:49 -0500 Subject: [PATCH 146/482] - Removed files I added accidentally --- disabled yamls/AP_13458270422501645045.zip | Bin 71036 -> 0 bytes disabled yamls/DLCPlayer.yaml | 14 - disabled yamls/DLCTester.yaml | 13 - disabled yamls/DragorrodSV.yaml | 528 -------------- disabled yamls/GiftReceiver.yaml | 41 -- disabled yamls/GiftSender.yaml | 41 -- disabled yamls/Kat.yaml | 40 -- disabled yamls/NevaSV.yaml | 527 -------------- disabled yamls/Plandark.yaml | 86 --- disabled yamls/Plandew.yaml | 489 ------------- disabled yamls/Plandow.yaml | 87 --- .../RC1/CaitSith2-ALttP_-_Copy.yaml | 670 ------------------ disabled yamls/RC1/DOOMBeta.yaml | 164 ----- disabled yamls/RC1/Dragus_DOOM_world.yaml | 53 -- disabled yamls/RC1/Fatman_Main.yaml | 444 ------------ disabled yamls/RC1/Figment-SDV-4xx-MA.yaml | 190 ----- disabled yamls/RC1/Forsaken_Terraria.yaml | 120 ---- disabled yamls/RC1/KenderUT_Neutral.yaml | 17 - disabled yamls/RC1/Parker.yaml | 24 - disabled yamls/RC1/Phar.yaml | 504 ------------- ...k_SMZ3_early_sword_early_sword_normal.yaml | 19 - .../RC1/RiversHappyMusicAndViciousDemons.yaml | 279 -------- disabled yamls/RC1/Seto_Undertale.yaml | 93 --- disabled yamls/RC1/Sheen-SDV4.yaml | 155 ---- disabled yamls/RC1/SilvrisTerraria.yaml | 120 ---- disabled yamls/RC1/dennisw100_Terraria.yaml | 17 - disabled yamls/RC1/speedweedDOOM.yaml | 178 ----- disabled yamls/Stardew Valley.yaml | 469 ------------ disabled yamls/Stardew allsanity.yaml | 39 - disabled yamls/StardewRace.yaml | 42 -- disabled yamls/StardewTester.yaml | 48 -- disabled yamls/Stardew_Valley.yaml | 41 -- disabled yamls/Tester - 3.x.x.yaml | 34 - 33 files changed, 5586 deletions(-) delete mode 100644 disabled yamls/AP_13458270422501645045.zip delete mode 100644 disabled yamls/DLCPlayer.yaml delete mode 100644 disabled yamls/DLCTester.yaml delete mode 100644 disabled yamls/DragorrodSV.yaml delete mode 100644 disabled yamls/GiftReceiver.yaml delete mode 100644 disabled yamls/GiftSender.yaml delete mode 100644 disabled yamls/Kat.yaml delete mode 100644 disabled yamls/NevaSV.yaml delete mode 100644 disabled yamls/Plandark.yaml delete mode 100644 disabled yamls/Plandew.yaml delete mode 100644 disabled yamls/Plandow.yaml delete mode 100644 disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml delete mode 100644 disabled yamls/RC1/DOOMBeta.yaml delete mode 100644 disabled yamls/RC1/Dragus_DOOM_world.yaml delete mode 100644 disabled yamls/RC1/Fatman_Main.yaml delete mode 100644 disabled yamls/RC1/Figment-SDV-4xx-MA.yaml delete mode 100644 disabled yamls/RC1/Forsaken_Terraria.yaml delete mode 100644 disabled yamls/RC1/KenderUT_Neutral.yaml delete mode 100644 disabled yamls/RC1/Parker.yaml delete mode 100644 disabled yamls/RC1/Phar.yaml delete mode 100644 disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml delete mode 100644 disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml delete mode 100644 disabled yamls/RC1/Seto_Undertale.yaml delete mode 100644 disabled yamls/RC1/Sheen-SDV4.yaml delete mode 100644 disabled yamls/RC1/SilvrisTerraria.yaml delete mode 100644 disabled yamls/RC1/dennisw100_Terraria.yaml delete mode 100644 disabled yamls/RC1/speedweedDOOM.yaml delete mode 100644 disabled yamls/Stardew Valley.yaml delete mode 100644 disabled yamls/Stardew allsanity.yaml delete mode 100644 disabled yamls/StardewRace.yaml delete mode 100644 disabled yamls/StardewTester.yaml delete mode 100644 disabled yamls/Stardew_Valley.yaml delete mode 100644 disabled yamls/Tester - 3.x.x.yaml diff --git a/disabled yamls/AP_13458270422501645045.zip b/disabled yamls/AP_13458270422501645045.zip deleted file mode 100644 index a77f5f46d438756fe35d2f3d155cdd214eb5936e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71036 zcmV(%K;pkpO9KQH000080Ay@FR~K%y3GUGV014Ls03!eZ06|b+F*7tZI5IadG%_+Z zFfleXH833N$}!w2L&Y6 zbXJw^wortO)_pjC8iS~oR;iiN1NgJ2&ozG~Z@kam*vJm1y4`=M1z4wXuP8`x`AWcn->hom($z{`tJ9yZ zEd$1K*#VOCu_4``a_9USX zhUW|~6BT_qyZAWD9F20aS}iI`M;ZcjL+otBtp9vCNh;_|ix=XwG?V-Ow)byRfsST^ zJF|IN%|%nLX{}bf_!kck@4e@Y+9A{h0SBq(qDNn5W|tu2XRQ~Gi!o*ic*pdLAzwHN zfC5AZ;-FC=^$~PXaR52+INWiNa-eb$c3{f`{l{r^>nrfMXH2<+1ktuNeM`1+! zmHI2iS9%M80?3CCEr|36YLX-XIjAit73gjQrvdK3004arWetlF{Ra>mARf+=ck4C< zA7BK&4%B{3^_koWpbO9i4gbBadW5R>GG6Fp6cmA0$2kXmR8UJPdFNIwZl7_<+$s zWE4CGKqOV62`0q|q9u{*Z~=fJC>Nwc8%&N7MJpmt;mm+HKnai?sGTO53?qz|Mef1n z0p6fhP&;if1x6hG2zdji2XKQ_K@b`&DMkn_jogL@z$F0opiU5k7E6v1L)*j8;k590 z_z{2;egw<{WC5)K)<7@-N{S=J%HMy}_?Y>zIg$?U1?L2=03QJ!0XqN-@Kv}foa3?h zefrPzf`Bu!Gm^WYj{rQ71n>(U0e=GThUWm3NdkfURD!^L@_Ei03I{`^Hy{ic4TuI^ zknfYsGuLoCusFbwK97YQNb_in=vZ#Ckg?FRkg!m*P$&R=?xXJ`yWwhp7*HR{L%>7O zL*PS_Vn8vd7$^*w0;a-Q;TdpCcn_c+XbSHE`U7U*E$|Td6`Tyt3(y25fN)Gk6d1rK zz$f52TrdwfPWb_t3GjUk8mCd<`b=5~aC=N%Lt1mUhGrb30K_OGW8ujF0TKgXHkAUc zj}n>&c?5I;rIAjKk(;uJVmA2PHATm)zitRlA|`N8DFi4H~D1LXl;q|2l~SbeC`-f&sCHL$sMCnu_y zVxIdy4kIcSpdd*Ki3Ugms6o;P=mYfu=>Qy*3Y0$op>HGe;m3gA$*C})&8;6)KC*e% zB1)2Z%6Sxd0(s1NT(`+&0Bk_X$Bg&sv;djFev&WnyZ31a0BL|UP#Q3oOobwt3j=Zx zL#rco;pxC?fE`&oc`zr29IcPEhBpI`0IOu}6v5mWAX*Kn2~Pwf0IFmVax6y;9fl08 zi!_H<15toZG8}acR}HX+%%~LB|_E&LWd7Oo8+gbTsT;BIg#kCo97BpI9<$P5%Gw*g@p(Jzp%;ln@}xeX9Yjn+Y$ z!pnhkfGRQ@iXU7Ub0jUC9Vid)4mY;pxoA9D01TpBnG ztc2f#r@~F)^#D(JJrD+f0I;_)3}{EB0NfCW0IE{xsj~Ob{y)rB0NuEmb-wVfwY4x^ z$2Y0TE2iR@i2BJ){DdyQ|MuvDJIc!zN_(+SdO`Kmh@^;IgZ(S8l$68SK`xK#zd0m` zq@NJ;fbpFGjmo`u3B<0R-Ggq$r6~VqifvE&#eZuMi1{sunILTAfga{0pxz+}&E0)H zbvi$5RCPHh*#RqU9u$7SkS7BaXR=1Fc?y(m?DG_bP+j7ZpNZ8hb$tmlC9}OcEB}hRk+{D(?IUNa||V*BHt4|E$Rc9pHClV%oq9L z;xfL~n&E3}{K6ZNnF}v&_QXeoDr~~uBUj9++l~3_HaYBIuD4}>9NqdB--Wlfggm+E z9-4D{em?SFQU_m>s)0TT4#Em;sk zGpJmiN_2_OXPH}EqM|~HK(sK z7wDJrt%?lE@4B01&7*02N4HB`H68ZxppslcegaLW7XoHT{zS!9tFXCE zb6>VjTjwC>LnC6CxGXF}!Yh%xzd*xmWU609^zSD;Y;Dr<1E-B_8#Kf*aP*ZweGW!nb4Z;jIv8$zr>aZ5J^UaK z`k2)us&%dTfGm~F#}%rjH2;S3Sn~cJ-C*}E4#&9x^E5l9K*;7Fz03Lc-=-sXTV9SG zr}DG&U6#mcDI%;SO_cTp`n5#}b^kE5>Wh4LsQT<=PDQ)jDT*_0`V~u+KfPuvg_c-_ zcHEbmA^{iEDzz`N6;?*)d1iCmJe*BpW+owc_lTJT(6IQO0i{zi%SE2Fikr5(rd45D z4hIFGAh3`RCC`9xGC7Xwqz+8A_L04i;_NYdiH|cmY5cHDJK!A2_L07wawh?Nuo^j(??SaveRqD6 z9Q(M_kE`o%##fV7gBN^7)I~W}VxI=6A}4rD)*r8Y!YD5%%y_a1cudd?}H)?-| z&M!PmIc|o`H2eMa1YHGDd9-Mv^P5biGUG$kGB0_``bv`WV_J39P49oNX7DEnvto3H zozNi+l3g)|u3Y@@{Y5|eKh?Wkz>E=`-+@WgG4cmW07}kb~>Y2Z=ZG}_u zU?ZwEg8`jGaW4B1{?f)CzDAMUwAq$xn%K9DUpR;#8uEKSM>R7HW495{NY!pk={gMW z6Q4wg(Nq79Ngq?NfZkWzD54Bo{xzw@ZFQe^L(qV(G(&(v_W`c5!-DD?Xh)o+?Hc6v z&K#$|I5Y8?Hb+AC2TM0J(P5o>RQNlG72jvDk;AY7XpcT+GWgc9?S$^6MOR__r@1s2 zCO3cH!C!W4ZyH!F-5=Y#r15b)Hu&$m{5D?`Z|F;E^m3>ra~HTBQ+tA`WHEkd zXtu|cypap~Xxl+p#pITytLyd`c0OU)yw#5_miYW^YQf(zYrPS1R2o@#rZaA}%sa6g zM=SV#cc}UrmVn;h`>NlYGr1;`I65h0t_uC*t0a42c;ULmKGYv4iZj;smDxZJ4Y_=t za6ayRl2~4?ro(q*7U5#yOevlBtZ(Q2!LgKaqzSO|zfTs$h9l7<3AE9kiFQhH!W{_V zR`u>{2&-87p@;ojw25@GePO0x7F7x7Xm4EbYE{qL% z-jnN2VlosD%p?NDMv>W0ED`|#C}YVBLE$^mJ-7P>#6J?m9b33XwspwSk9$Xl)aQ>( z$$a8s2;yfU#V-(MVqc{HBe5@qjLA@y&OjB7>-LQ0bIT!X1)F2W)L&B%zh867Udsxg z8a#{j-uZVcIt!s*GI_-X=U8&S{C+Ir(x{W*2$qdyHl4LxHQ_0b+%uqCwV8aL`mOj) zmP(51t&yS!vN1Bw0|CVc31D;bpy>R_F_Y3k-_lMlMvi(diA0C#60dRF%`a5RI}dq` z7Mbrd(Y4rTytU9Wk?^cu3j~>F=L;+C{&^c|P_8>6!6MlA)c!9lb380#llgSy7wb7~ zRc(Iw$awNBv=}idAe+PF3XaQ677maao#q(Km$^FEGBo*7Cb#pvE(`U`Bs*I>gKRgQ zMve0rQXgGX{A`AqsuSNyWtlL5P^o`}++P%XxLf_bHSdFJz{`R|n(VDoe`#qGZ2rIv zYhu7akaO!id9UnPt+Rm63>&-XOp|%ru5aW=?HB}ij{H^6`Ta8wWhU64X@-a1Z>9eV zj8~oAmw-u0UAfy|7zWjI9bhO*Ln|D`&sxqcn+ladjx13xF5!Vs6hE<86^$>;_E1sq z18F;LQW&ql%|5Cwx$;W8Ec&j@T>#3ml?lzGYe+bl82xOR5s~CRMP{o9`EC0s&ECXf zerlnxwyv90$+|zqwusUNzNO<5EhdoK`8R~GvnG{{b`BwvSc{sZcV}U=7T7Zu>!lje zR^JS*&A3%^{#M|&=#$Mce_Q?RxoiIchV6r5J`0cEKEKLSOor^1=e&$t9?>z3(YcoULDC>oWgv#v@o{k6ltc3zlrSd0nT1 z@vkwO5&A^6XOc4%nd@v~?ls1&yHNIss&q|uXr+yAL?hnBpg{J#&-=Pn>x^TC_L~Ly z3vQfW%;PLf)I1D2hf&VADrYJ;c^E71LDh6pQj03TZ^PWaFthTqMCFpfvTQHoV>x(t z#3s|{?-5pq>G}3efHc8v&WjZ{fx?KZY*HQQCwanD#Cr4o#R*H;PUD# zHA(^diXD6)%?x&4{NbFPb)xIyo0FrI0Cdf<7e~(uy#mF)c3!6WwdQvh772E1ynp)) z{5f3hep~N=LCm(9k$FaxPOcDvRrShP>O;SNu|HSB?5!Rq->w=XJSDz3Sb%VA#&CX?WmDn7QGVJ{0WGuP+2 zBhLea%a1}EV~_Bu(1?RUe>bD;lR&ukWu6)8lw=sMc3hHv^IUB6vgtZjdaR4WB$MWm zBS)1K+3`a(suDUIJRZhH|5x8#Gehsh3Fmrx^?PRIp>S?6%vJa;nF`A5`_0{&%btK$ zVQ}Y2@%@L@XWlRGW-O5pKM;{SJ_dDnY~{7zqjP~P#c%I@IK!ku|BL=X?t{41G<5ga zu)6?5ha~maSankM$rEC}D4+9{t#SD}-Y&eeSlN zHsRiFX*(7n3G0T+vm*$uU25DT#PKzM=^WboLzz_Tq5D%6=Sd59uNS@g3sbuHsu%Na zZ%2B1)5@H+S>p??snW`{qtyLE#{H?$h4%U{;! zzf%chN#MroN4s|GM=ArmdTm6y>0A%Rfy1eG)k!w3AW>__E8e-dWdAYtEZ|Y8c=7Y2i0QOSOno=Ic1b2v*zxI!8@}e{sEvd9UJ)ivA8ZM0mPR8v+Z=vti*g~UxaqrI*?X1r z>NAP`ny+$zZzA|NvW9u@xU3HCsjgQy&U~l%8J!yh?f#&`9)y+c=nd;9yR<4gNO+vz zuz%WkSVQtSUQVssZwkNl^-1WpFgWxf0p|yfbPRsuq3+Y_6Vb_q6BI|bhw`S$i zr8pO*{kh%5T5W&H??jz0vudyNHa5rAm;kp{>T2A|$r z?=43w*Gp&Si_<-QHJ6EV`#%EEYPSP$7FPH+>b0}erq&NSBXSl;Di>zP?qO%h%ZEqm z^Z9wJa*wV^k{g{FckmBk?JHPezZqAZFQ;ccTf&PSA|$Otti?F!t1O$%`oP5|HK6yl zEc`l~q`>XlkxyjdPnYY?gWF@`mzHurg*=eO46CnStn;@ArBOH+FH}MiT)l3yy%5oA zp-g%wWikOX%~ zSPP8$Qm{~YSZ1km82_~->pA+8a_Ju7VU`A#7e^~cb_|RH%CRm?Y<)pXICQCtmNZ@K zfE+s`irSXvo?toKhlh7I*39f%Zp0M`2c16=f#mROCI*O`Y5>EO>$zz?m4M$=4KuI~m zh>p0O9CMJXjAJ(7+>h;n5!>_Yr=p2JEu$W}QRYa$Ghii@yU^^C_;%(E6(!fdClbmc z{e8uPzhS_NhFI8!%!9XS|3Yob9A1SmY`cx4!EFNdHU%+xD(WDY6PIX6XYyM?7E7PY z`p$r+Da_8nkm_j(sj$S>J7g~1d_6EsDo>cc1Z1#Il}j;S4+s#dw#LXgV@Q#QgryEx z+o^XD{s7uFgy@ibb8&TVX^@UseRNPB_N+bSr{7j3e>7U3c81wU`q%zq%*Eb}?RWc? z0(0};V9uDJqZ)x~apJt+%ct`(&B~aZgRXL_O?B#3Ua6adoP)-gz{LacwiU-_<^A2j z`Rc<8fBTig@8vR)VLSObZ#Uh;+80E&4O*xoY)?i52M!Lg)kpD5;l76-%kRjC{n=He z@^`;Ln(jHVweLG!w5zqP?CSgp*&-K`=&Z@F{~P>gOF-JEzHutzK{48$+S}-PUy{%F zmdIZsBBC62-yBKX-(lO!RP5fZukfsrz52!dN=ZO^$L3?nw|Bbk?VfT=ca^u@R@2<& zqQ1|Vnq{3Vofk!m28<1^HZ@*iOqqWc$*($X&uH0veooiU`fJ#teei95tlh{;%zm}V z>w=c|&BK-ge>Dbf+zNxk->`b+EoAJ7+pIbww&EpMwVh1b!Tr`rxW`RV&+&XOR`DCM zBg4Oo-0bu=9?98ZUvY2Hj;#OQheQZ{X!gk;gAxpNYK5k!MEkW@xs(pqlb5-!r@Buz zDPG%F)61~#+_%|>+%YfCl@tqWWYzeaC{Gb`{BdTWO{cwGevyW&ndtb6IpFojq?3p9 zqW-{Lp;Ho&oHWxhz-IVWRj|L$z^O?6^ttXT+Sv9EGu>D}t&E+Ga^G3_s>sHpUjfc> zg0l8k@2;8z#j9+cquDi(>_KsxzvL4KzgP5xS2~^+@t$08OQhB=tVU2r#$8d`h`m-k z?c=OoJEnW!_$T!TUOy-72yeF5)3|z7>=Ru5DgAaxPVyW+cr#F9DmLWSvDNZrj(4Ak zUG?VMx>tE;M#4ce-N%W{lL`kI16zhF6|=81gR5#vg&%xH{7SFFDX8^Uk~iWxk6^&eSMmX78Zx38_PI=vlf7nUQAi+-8OvFa0NKZ~{ed}UTu*R?G=wFG#N zt-SLcY`+PGf~pY@B7deZYjrc=wfk!i62Z4l#WWlCf|lBNg0cOAb!G8m`|HNqI47eaSnbAx%*aRa z7xz3DUeJzEx72BHL}g0VzHMOLQsfb%HkKTFV^_K#fINj8*t}sZYmkzvt5{GYFEnUu zE=~79G$J4cqZZ)}is%Nb??t2K+8V}H79U$Kk26ZAMXbN@EjjwWWw1*5ypnk*pzH#y z6E&Q{65p?G@gn}Cr?*I{L0(*efI=NKH6yst$zm}3*|##GFBdv=<(bo~a&Mo05>Tg( zX*svkPK7+?GpoCw(vQjuhmys5beEPi zOyqlH^alB4j{fv$#^WIjOn&u0c?jF`i zp9othO}aj^xYr&xK`RjymEPD)i(rfWg+uacmNpFcmC6j8W`0S3PGhr0F7E9uqO8KJ zp6ewUn|P;-|Mgl|Hf&f!q|;;C700Q{7J8JPt&nc;~3GKBY zdS?U*fFT>0=W;v`92uQ{C#5BRO&Rm!oEmt(es)>z$MWc#&FN4FB!w`Yq-0a($8D>s zGaMci&8_+h`}d-0S$lBc+uM({Z?GTytYeHB2Ps?UF@JbX{9X&6QKnif{FrE>i%R<7 z0Jcq*`;t_oWW3(D+f@+2pBB@j`yi!OcxAkmQYV0s5R ze?HNw^kSU&anV#zEUH^r&}b0d_qUZ@`svKUSEY z-XqiK$S*BP!MwWx*zCV|Agu$1Ir}FEYS1oxa|E(Gh9~e+6w&;2j1Ld z@%#^3HZU|(!z0$A!eQaphLTBGpD~&bf(8~OT(s9xsjMUpS!%}M=weW{K z{24#uo)>&Rop3bK<(3X@@Y*TBGYRB}jwTK`$+zqInbS4`XDOCuhpGU z)5*88_WUOGy0f<<59jxl25;F7^pDm{qB90 z`@4yskuk|>1>={*sZh3R{Z2x3%JJ`4DO>Y(oTM4OcY#SxYW!K&z+Zz`qCHw<)b9NL zDih~Us*O3XO_z=(NkXaoiy-2ts)75fv9egDiBmr15BVw2wR}cjIUc9?1Qm-lo1NtZ zhvvsAnD8zIaNjG3kP z7|!9)mP<1ckg7EqJlmOC+9Qt7GLHINXFfWXDj3c<@L#+%Xhu97GR5!adp>g2AF&qp zY_)nTny<4pJpEuX6n}M=<~CfW-@9(-8TwLXvd|>$Izqb6`K{%u9V`iV&}xG_tGoX0 zt!HRypVi^${qL=B-n2>eM(_DcxBeculPkC2Q&$j@>C%QeX_yX7I5#Zt6tE0h^nTN% zqTe#oOmLeypcyu#EYh_0{*hl2k{KSh*g6GTb|0Q%Sr#0g5?_8GtkRkIa811S@LoPf zh9jtTgx+(Y(JCl2xozmAL3D2AL`Ev8V$;q0kUOnpr{zIf$-Pz=F~g|0@6$>=TTRnS zGFn$W2(Gn_rRRr>DeeC16zrKAQy|vqWlZ3y@*81+-TC6`7<|TpM(+c z2(?|;gQXy_qzSi-61E^d@q*&0_9|cKXP5P*uG&>e#836KlFFxJCoSbGU^pzFc+>$#kl)e%*O_VH6tlZYV~M{iso8M1IyH zH;p4bNc!Nt1}CfrynMe!ZxybxoFH)-^RGY;l#3A^1XZm*Ku{+{ns^ENm_EkL z&&yL=iL-p(bp$ty6B}i&@xBeEJz}g;$i&IU6FH*c`xDKu6#DrKt*Mmsd8}*EiQ68* z=I@PLn_tcxn z_L|FW51}C~QG48VZ-`#s&7k2b-*jXm4JMzm8kSGcug~(f%4Jd@dJeDm7~Ooc9o-f+ zWX#!KI4Nly?V86;`fNk25s3G@r>EnPdhrbdUc?&@oPBg>dNDY$iO@xNzU}?=;8W8R z?fI+*Ymj-Px3e?Zpnpb-sN<=N-)BYkN>60f-Q2aOkI~;O)OOs#qzIW zHM9+D|F|K}pjq6R!Z|Me2*lG(O_JiQO4y=Qz%|K8ra_a6SazoaerkS4Fw1`NkyzbT z{;lbqC7qe_8dQS8Afcm<{ZCIbK{j$iJw;5V_Yl`A3u?? z4a*iA!>geTqnZqeg`P|G9yl5QJf5&$v2OX78hZwg z9Z?=PMJskLDn++YT}pdBGuO?0nFyvKL-kUe>tXZHf8*zDvj_hCk2{|6E-d_q73zHY zz|HLM4L$X-3`_fLbjbml-2+z4`X_bt+NY85{8N{zO(hKVZ7PfXdv!?unQM5k`5x@a zKm4`#E9etwQU%2BNi^qeq<~*%Em$HdXS-M@Rm9{Z8V+SvaT0BvMV#B=l{eb?Shtmy@=dqDEfZJd-tCr`z?gr~X2s2b@P zb2_I^WS)cFel9 z_-5Cj8xE z8lIxODU(w3B88rgQ zmjce51}|O{MN?L{9}xHcvE%e+Gp&T5@W~S&es5QzVGQ+h_$F%>9jsT5XV1pd5{d`5 zVw!LTqXdm|LPkXw5zvXemND54*8k`o2r3(zb26vzLkKOA& zj+CI7w#-eWG_is%e{_ItO@R`X*9Bmc9{AI4U}B<3N0?i%pRRZt}fSEmVbs7!LaR(qW;+LR-~Je-bf&xT6o=n z?bUr|r6Kq82mAV)@2J*X{i(mTZE?9E5_yoCD6}z8_=PaCcb!^KRLD8^IRA)-AY+)l z>IhflJwkGi7U@{g*(Jy3Sxp_M0`-a3M4TeQbq`@EAJ=pU`StSM=2c!)0qoQ>=GH8J z?Oyj)W}jG94Z*F>p`{Y_uiCFC-&S70iqofZbAR;d6X|6A^S1}0`f~>b(SDV{d306U zE5)9Bq^q!PKUYDy149#C@l#GiFK59puD|pXm|_wFmKu4k?!5F--az3s@M{SVFE!Adpv8~0eE!7-ihxk(yuF}0jy1_&c zF(W>)3kv;t(r~ukFjrzue(p`^B);7vRCtd)X*=ECzg)QJX*Pj64kwO%SHP!ARB$-% zB_>wdxURSn(3CFVpj0`QeEg|wTG=mWmGvIcQRsgt*Q<7W@=== z7A8I#{IkSXB@4k&9(nM-Ycuc=hB-*5%i>;4^PLrdFl@HC`o{~qHN8h46uTI^*HCGaP%|B*euScmHgd87y`zoCqGZZ7irnu*; z>ebLDor@@<9mcMQl&a)X7LCPxKCC%D)-RkA9otU2sK5H7t34X>&(hdD{+WURf2A_w z#qOW%%SN|yxy)@6-O*6Ex0tQxaMqZ(;!PMNVo*pzwQu80zH@kES_0v^*uRCSmOb!1 z9gfK&x44v6JA{nxjG4jE!v+bRy_&h=^#_SZj}))j5KzBGX8Q>Dx}D=ErPlkGC!VEG z_Yh;x;{7iu78~NZIdc;=@w2U`oI)-tYsoK0u|MaEO z=lGGne$BEi#l2tkQG4{Nrsp5(?NpTK30QdQRM%D73@ZCn7SlKz?mPhIZu1*$yE>eS zZ&JA;on0Bl`UlpiVE>za{x52h`?OKbJVrOF>92Ox&ucY$ZGvB{ItgPiS#@$;Atg|< z?>S=(s+!^4UU+Y^qy3LW03mdkNJ&szqK1M{{n14EV3)aF7fhRSITa>>>2sr`^+M2z z`8{-w-SoZof?tP#Rm<}LlB3_k%8@~VwyjZPfoAv6hBftGhL{`6OFMLqZS{V9H|~NQ zG4u-SWnl^*vru($tbzDfTOdYo#+_Fe;>Km#LOJo^}DH+2g7Yi z#CHcZ7YqR~x)ou*fB&_vC(44o^yIK~+Ad>3m~zyS=anr|e&J*xb;r7swB7%E3ps!>I?}ZWKAYX&`-2&ORffxh) zYozjd7hlTi3ycBGiW~~tTLrBul07#6_DD8-2&0S{6@9@J+(}zRkaPTs+SL+CdwqGMK(Na!cI2{~(8wHI z0*QeK1!_k_xjBfJEYdm_2+He{}N&$SAE%Ej_>Yr@4xwjUdpx&z{Dq{ zo#tSwmyZ4TvGk(E``683y3DwEvp3fQSVzvvd+q+Zr;?bKS$u6}sUbUY9W6bJzlE7w zz#>SG8ZJwaV2`e&oyzWGJS&D6=(XuZJ8C}`5!BGWt%jpU=UA(~X(rzuX6{yAAJMgr zIz1gm!|KY%&5_l0ht-kxu8r+;*zmx12q(^KwCrB6%gou}pzel!}(O_SL z%BKX>65BrgQ4E&;A7~3P)=>vXyclg|FoZ^R)3pelW4c)KZx3Jpum9OUH43$lgbg>P zS0mfX{~BFE>t*L*U1Z??rWjZRY_6}Ft6e%5M$y^bQdDn=Rj~#Oz`-cX0IxwaGrn^y z&Ox(DN^l3Yc0>t9sd0AWIu;plxxf!Z&TXcLSWOQ?5IJ~dAytjoI$9hA4%RG(IXKpY zgV}e--l$#oe`1fqAMj(w7B6t_f}L|nVz(P&x;op~6l0uyaf_f(5*`_3@L-h$5x6+l z=Ws&|cC6_Nf4bVTNlSQM4yz(LTDB4#I^bkMT}K7=^@FBk>Oajl^Um8}M^rbh`#!+7 zWm}J-$nY=<0-H6=9uDhI+ip#82!|{%h$c!rJy<7+Ln$kx=%Gz`0s_hHaf)aZQug_n zPTN^6mS}^CQ7kD&CpP0lJU$?P2+hMvBDpuR7bA`~_jli68Ij7(!G`4E@r=Z$gr%oA zZaK2^s8czz;k}>w-4`K}SVzw*6deKJlJ08k)7i@0UN3TdAM2lE%eK{@cIk+&u05TZ zLL(Xo2-Mwu?l;|t!)XC5Yty6fpC?WDtNQWFvnNDuXZ*G|-6%zPw{o*Zj3?b_BCi}p z|F$1Se(9_)a?IDDRt@(cADcjmS~=;5kJar+kP@R0y!$WqIThZ22X@USAOg@i=WD-M z>~o9@bdgZA6zS_z5dN*`fV6L7G**BF7_n+d{?ade4i7YzHk8(z%mUJ+xdTR z5nt>25JstXxNVWjZLe(APJNpzyDvI;u?3!Cdt4_dUK#sK(xdFUGpegG@~-(lRMz#o z8BM=`D&%R&zrvCvRF77U9YvllY|wU}K)KfEk`0I?C=_%|7wzqP)|23H1?FNSdXXGu zuYo!Jx|nf|O^;AOXodcfD&}VKB!moilucM+@IXmK26?qWrWq>6=#gXf$1qB0JS|Zc zD>;j|-Wt0~HFCufg$ucH<-7{q-T+vne|a%)X*KlIF-nmiMcLU4_2#@T@Ey!gyN{uEn~KkE%Cv ztaH&_jf6RmTeD-8=&q*2<_Kcn35){eadUcr&cT0>m{|RkWBeS0P}-x#^egYh#&=(Z zRO@#ihakowIALsQ0oapjx86G{$m`Yt7aQyn1dFKeT;|9|AoeMDNfO^(^yE?>7=}}+ zuEia(N8O}rMj-a~FW;SY6sR3@lMsAdx+ri@m$;cCyQX*N`aNkbwkfgZ9${s`u223$ zbOifR=vW^*bcMwJO@Fg`K9)HOv5wOLLg`#m$nj)VUegdR+Ry>U85WOL2bS(rvDA zK!V$A!XYS#8=(b9Xpr+J!HhfPWw>j2t?GQIoeg(3w;k1c7%Pq;4Mx^}T7E1sOR;xk zib=TlVQ!Y<2HYgKd=ewPc4+_SX>^!QLXq<(q=Xn%-Ei>dz=-e?j(o%)CZDouz87_k z3fqfXU$_x9bWyeB<~Rb=9CKIFADV}EsLpeN?YQ@k5Eb-I{f7T^f%8QljlzC>9xk`) zB>Z@wKy(xt&jAPSF)njM()ZL{y6(SS#a#8F3BAexaJ_ZpO_N~H61sdvXFZZCmY_-v zE!*_He{d*}8bw^LYSxH^EuH)ot|G)3Zkl=#XVnM7_oLCc7!s9cC>@|{;2L}z_dF1% zNQo1*=A!VXJQUyp5$v{S$*`4jUF&Mw%8XC1dLk6Lc`=3=YB%1=a-`?KgwQbWy)a=c znZb=ZwyOL$_EL84be2<1o?B^rr=wHy2Q2vES&zuU_1}pEH13)T$L+M__{J5Fd#dRJ z34iJ613ujxzv^d4!)&}x+Su3F_kSZ$WH%@-bdG%h%^yOE*iraD&7FinnSYOYBab{z z!Dnp_H>=FJF@qZt)Ko@Sce6Fr8XdNiWqSz<;->=oZ=GF@2b;brmt|($ZQ1z#SqeHMk?OkhM3SIObB7-otBe}L z7;U2=E)T_t;5wvix@_d^CL|V{vDP0ya8u3xL;OgJ!#An=yqw_Vu1yKLg!y!juXL%I zwse7d%^KV6BA%oUmFja_zdyvqbH8mnkL7-6)>jED^-In5r5f2QCM8|AYt3MT_#-BY&Z~0A_gN3-cFlL%Exz5VxzME zmFm6hQ+3RFns*`8^NIy~XIS1B?{-ClRm(o@PRJwFHvDs$Y!Ja{k2sx>*BQh%S3g>* zj7iS17Dl@$HJc!hyl%XGy)Y2J`@!4hbeBltZI|}V%f;&sb{v2m^(O!LS_p$$Bm|mk zV%jmR7+5n7jD+nhM;=g)Hq*Z)JQg$GFQV@a(ny`}5k<@+C*L z>o9#SnBluwdm&7-;(43mk1ikTi+T=Xb41W6v)2);3W6||h9>kCSw~)<$)dZO@tal{ z+R;k!X%sjvjJ)q~w_~wy`ll=8CEt#^1B<-;CVzVH;QLr-N42U->qozDanH_HDkkYQ zk6DF4t;e>sgd1g&Dj3})GH+FVD&+lnrl+13{OOyd;a}B&iMw%kCEitpzqTH;c;)-s zdhOTZQtQM=JL_D7-?5d|+?2D4%sK=fw_8>l?2Xm~91!df`%<5KXy!8h@7ssQ=NWHpUkSzAZ%;qW z%;dkybd591X=^%9Gqhwee@N`rEUrw1koo`g`|P*BlzsNL&Mrr8Q!fnCuZ49?k-9hd zu6^dT{O>{H+Ckz$MiW=(gP*LH(yb%&`KEOl38HTEf=_Zr%ZlqSf?&uJ!eh5wS$e*Hp;Bzbay@s%zQKjRnuSU%hL z8BBw{Q<8?NKPs8Y?%7pn3#Xsyc}sfCeq74Cb!?TQJGkNGw%{_ z4z7;f|q(@y;_(sV__=mPsZBXL?M|+OM7uE?+-;!FKP?)R(s% z0*$Pi+5-GGclf9G)xThpzhAEL8^73zGr7NOk1KpJ*|xbJaK6DBVQ-+Q@ghlU`T%@O~zA3G8JO^)#s`ZRRvl~?S2@^8>gT~YNq)ALDjBcN5L zrOk`Y?#{AX#Y+xVYsEU;LK*QFe<n% zw8@jlRelU-Z%!HFTC8B|{{^+mx>if`XM{@ZY%B8ReAT+&^ZrR0iqkK=76D1PV-hy# z+~jIYLjBE+Re471^Y%vz{r6S97X^>!uk2);JFQ}w_+F=&4l-GYjNak*$P?)b$OTh6 zJayGUYE{XIx<#_ws0j7jLc9`iiO~fbJf=Q331|Ufdg^v9|HuwWruaEAonGAP#G6-o zeV}``Fm>fvKc-iLzNJr=zsGD+kZI|t-yL>fInY#!75}PLr1S8Xl>W%ydLGZG>6Jr# zSw#YE2`_3`CC0b?gv!z~KX)q?Tg6ar4FSIXEG?*?OrIqCl1uXenmmXQs_XlN%MJ#=RpRB8=Q$V;+Pi8~!x7MfhFP8#v?W9({%9spYs`k-oqeN{6dPcT5wA%CTchY659~op^ zUObC_q0*Qq{K)$SUnk!e;SBazbz}V`1^yAYjB9?Ht-ibbkZ;dUe#-T@Chvr52l14+ z3|2DKbV%(+bb7qdxZBo>d}hJoH}&h)w?DxW0sQB=N5jtQj`6}HsUAkzg3H3|52hh?_ezwL zUwPEn@wk3@P3^AA{nkH4iLH-HFOo+m&vSY(Sj;n6@?A%x(GGRT-Tv+uZ6=?br{ASL z7*eYgeWUaJKN`IaYk|qR$Th`W8O<%dJ{lK=kt`E#MlzAys!R6ZCt8sVf$Wx+0(E{{ z{K>s>sSF1~Y=26B6n1zvYfr8eRXYZM(Mg|_U^SDQRRpAtB^<;EOb^G!_uQJ&+ic{^q>*y`L!j)$YcT?FvHE4N;o^3pE zPr&%!k=+;8*%uigtq2!oPH96xu(0M{?1E{y3a}4onw3| z0S>J}NyBM+_X3QC+82_a%_UzY%a}*mKCD=Qu0+Hn#V|Kc>cR_Vm{ma#H& zXS8POf^$LwI?}Q~mosd;z3WOdh9I3<-JHu#x~>irya9&@YCd?VPMoq@PGRaO{tFh` zdAYoP+cYOyxIm^!b?x(aby5@1HEW<5XxMnhd1vtZxMK1%>;FZ@S4Tzl#ovx@^wbXMgtR z^Evm-y~96frv;gDtx$jd&YiKCH!LnjT>H{s*VxzWHnJlqbVp@0o0Das4BTFTYE&!xToi5hn#TcgNz?Mp~X z@o(>wDv4$Ix{OZ=ha*%z4o;8o8$En5AfA@%4)*`@?f5=WDNKyzoyyvog}nx(_&0Xe zrx*v-u;^*ZFEb^WM49kesTD-kU7EJIHZe*1R}&pYdit;rd|=rl^{)kT^;k6(H4y@s zlNQ&*@kXBU?c&S1%S6v=Cp78WXsNMrdt_;!)GiE)KPe5{BX!|1?nI9n%$!UFK9u;f4O?w{=SysDB?)~&C3!QpAW6ycN``rIOL zx1(<&%{fZfQ){CAg){#)-+WnU^-PWFoRNuvk^{?QZ^HI=ti>-y2^=P^-C{ILZ|JVQ z#R`Alom&h=;1HefV2yn?PFVqoGidOt z5|h0?q~zUX4XXCWFFNx%Tda$s@}2v%OnhL4I%^q|_=<&oN{%uUFJ8BBz}F%TW}hi>Oa`cFy|Qt) zEix!v=P7J1Oeq1+koM4Al*H4N=V4Wws>Dl^{ZMsaDz?&kD-nKDyOeBK(aB!S4`8D`i(Ik#b6}5vdUOoq_Fw zw+z(77}tV5neP}$zm(SHa+hPg8%HtweS4nvVVn9eUKM%haAmI7fgqxu;{R5E=Gm9 z2MD|o{%nzl7fe-45p-1TU6TKO(sJyX*hd(KoGCj>qcuhLVlIMAjj%o#9PDSK3Y zLTHvC?5`eiL-yjVVX9miriXkpXzxsm&@8)q<~g^*I>Vf6G7_F``ARc;WF@LaK2qT* zO;cptQo`4Cb3o%e3$rEEghp1QzUwXV3153oEy7h-^ssFr_RTMZd0BywVbACcH$e0hr8}oOu#wRWOz&rH5;@338uQh+(6)DHy-9V z;@&@sqj*gv&uPS+@Ar3doRT`1Q8%RKQ7?}aZCjK(SGC`BPB%>j@~et;x0nNGv&RXO zOb+F7^*p7|GVnVt?Imd1-nq?*dD+x>v3X655X^VY$oYC|=mgpeG0Qy_dQE%k2t94q zI^P~mqt!Mo9E?F3J|H}QJv?hjIxekqbk zspnSHas%>Phdro@?Zc~LH}wdzSCt>mvaSv0cCBkHa+69&U!(N)?%H1%NK~Y~4)M+| zy2;pZoDl^Za`vVtspS|r6`9t*8WgE0GTp-wi`HE*iXcjqaU@7Q;U40y`~!x#3sosR zn7;5=rrm5HO$HB}ZN*M2d63~RW}83-+v;^i7h7Rbv;x*X&2rmiv_UZ<4&t+yWvqH9 z?$=oohG`Xxc5!()Z;6?^8!bjuV}^x1jBH3E+(nH^&D)mD-l@)|Lo|0DzunYTz4#sO z9j;fP*4_1WxvYfHq`YKE!9&afK9zq$$-)glR^xfEK+zF`NrUvX& zcDy^qjyJwiRz&_}YPW!FC6hKKs3_2#li^o<45LnQZEq)>#^`(oJU%LXv!?CLE>CMC z3{I`e^tV;#Y(=K(MA-Ox_-2}(v4^SipJc8!saFw8|7(lb@AJCd;FHO%PU*ex+ZFp<%X@bv zHHJxJa)?oz#uWnt+@SV+C6BA6K7q}rGqRBq9H;ZBzo4UN-PEFj6jhFLgI{K92QnS6 z70NdUxQv$L&#CubQLNCEZ!W&u75H)q!PFuDW)HqTwqnN~noqsK(f{*bW?U&^+NsO7 z%n}s7I;s;WcwQSPfF!XrG1Vf7*cCHS*GOiKai6p(m(Sldbw&_c+QaVo9 zR&u9R?aR~!&xR%$E_aPMy7s<^%}pe03hFKm-QCBe4(?nNe_=z{W#M;FU;hH$Njlr( z-D91V+QXMM-<_UM)stwVtoZT6vC>_l7V(uzr>xi|^S=g{!q!ZR3(@)UykEa6u}j|Q zT`u)08qJpnUFd3?`p0lfaOP#o;%<%YEtc3d&y_lHIDnHf-c-gEP86?>M9h7VHY4|W zR#Gx}bkiF4?0HGo%&eLLavltwyN$Hz3E*#8Jy>?q%Fg9ilAj%y;CYi*SCYHy3cOyu zmSzfQ_w_txSH73>-!xh=x(XWX|Cf}0iuXcktyl1gra<#jU9WIp@z*1t-eiUStnYG2 zr5XOZ^}G+ShF|;y5kDn*f3k|xjYqQ@I(EOD|P18l$l_Wmw=kZ_6X0ut{IU%L*OtLQu#-~QncAfiez+E;6@ zSA;SUOy#z2?EL8V##Er3G)20T z1`pChgptE{;_f;<5`1l+rJ(@m>wi3E)Pdsp%9hP}#|IfMHF@e*Pn*BcbE{o{-|f0A zlNL{4RRedMMK&m?#rKC9nO~HOw)Y5vUqWoo37Rj`C3= z{qZyQkvHutUbxPJ$9>KxoqygJ<+wYslhL1rMD6LC%xuKuCZpSGUOkHAYiKvYjATkak$nD@9g5atGSi zq_=+^`=igT-0qMW|GtPevYdn%xBmOO{d!5z4Rpf1lvp&jl&h`5Ag)jFcb1FM2GReb zt?7+36Tev`zZjtbY+yL>>TJljXJFXz)~-86d-kA0wf`ySfAXCg)tXkr^6ywvxZx$J zbK0om!&1|xo02S%_bZm}rSjR>pMDO_NJ-{m)0u4iQU89Sz!3D+=8Js#-J0b^dqX)Dk+ zw=tU{dLQS|)-Me{!JTQYyazQVD^&zLkK^v^GJg0-QqRoREZ)U|%Lt}6q^Lp{e0YRH zv+wG;>{y6i-@e|Z)Z#T*mjk|EM|}bQ!2M|PSf?|9g>s;w{2k3pH{qF$m@svFNptlH8bMNi>i0b{iq;v%$WhFzB)kM=(eG5nq5s*)Jw~3 zs!Wvx<}DV_3f5)+^5bj&CrxM0{ku0#9U4kadk_@&`FQ{&I$gEdV2ucm*q4M1zk8L| zk~;7SP$0DjRMF zBLSb2Q!mU%7X6(Rp!$h*46HGypwkoKRv(G2uxF-y_(hxti|V;Dbp8Jd>wa9kZ@!@i zDHA1|uGY)0Pz}T>5iYKdV^ECe83+%!v|!l9Brj)H#RvavRnD6CpRJqZqC1czR(uP| zcj*2lzuXfXG`_aGYN@38^N>N#IHXi;T<61&_~@i9JLFdR3NxoLzsyt4wuYPiOr^MU zrKj84#cAGcgNR7dn}!EY=<&UX4H^62HD~aBHfM8FkJ9=+5lCI)ZD-6mseICptz+uY z%U*7-W8t5cP3Ad4PyeOLrg?FDp48kjy_cmN{r4`F(j#-7r$Ega1etwybeWCsqL=m- zbpah_A{+dkHS(|UhUu$9_rJ@*R{v~?rRS0#LypbuN&m^)V1#3`V1u-bJG0c5khlXl z7ISYhsx3j(jPxhhJzdmzK63>7K3gq^%S=<(X_FLm5$}X3I;!saV%!|* z7DsZXZipnEx~Q*8AF5CA+(a8I$?$bHZn;5plFXN6ghx3Rl)*V3Pv{@x8Lv4jzvl`g z)K-n0P(Q9~3UU#nGpX*y+w?Q2rtkVML5XMviui*YM9E+BokOVX;|;s{!1&XUXxdRj zF2_m6=5U^W>`b1c$M7Gd-ONZUryC{{xiPHSKx-`dwo~?2{ z3E${!H$fpb5>v}h>JIpXgcTL@vLywppML%5*?oa(R=YbFmHf-7lHVV9d?NjA=3j=~ zAMRCsvY38Jd3h}TI=Xh}7*a8bt7V~-1Yw7=Y!P!gEk9v!z5#UZdXFmt)Hr(oHpf~0 zTr907yGgypHN4=Y?Q+@sj*p?pAYwk%*>co?VrX%R*Kz*0=|_&4IQ9JDer8|4@nMgH@g>i8zV4d0tz^> z?vppR{<{oUAltj?>n`3QDz{rfMU?zQglv1yTQ?w&AO16R)OK{3bI0tjf3x|s^cSav zTg@DbHC8W8h_;{2A7kE7J}G$^f;h4R(QWj`tGL;SBA@MA2`_~`lC;`EluBr8 zDC5XWn?Uh$rk7AUytx{U@Pc1e*lZMx3pIy@+Gc&~C-6!7jN6lYuz@k$ z>m$SBQPe$hX7J1~GZM9C+LY?mUeXYH*t6#`>nYtW12@9-k51+CAFULI1D_MWvZ|n+ z#OU!tsv80e5Ud9iK!p6EGg~aNoXXRRTEFH}Xn14gt{qZ9^|41M#bc@%?-pBwJb%w8 zT6|?$mIjf;MmY7JmF6<6;^?HYeER442ZARg{|e7W91mQN-S&xzZ#q=JV6G|HGo5?k zWvFMraepQpO~K&t-pU<6Nh+e!K=!DIbT z$*)aJCbO~3-GMK0j}reSnM}6Yx8>_{dk&pkoWJ)ZvVB*glfaCeJbcTY@)^|3sHm&{ zjwvjVxenWN;|2d%yt34Ppaa|Qe{zqf?h3FP?_gVuoX^_uZZSgESiFf>E2&JI%Tcb! z6)WL&va92xyss=I_Ih;$zB-$Fh(H^%t`}#X*vf0I22HA@Iu~RM5oYTBVNb(}*5i-4 zzKakv|I%UUly+x?k0Zuxd}MT$oT)tO7w+)mho|lphWKI7S4J7egC^%2yppK!-}J`6 zA_aex6EoT=`3rjpwN_AkRMrR|jDDFUhQ~SR)?`5ax3Blj!PKFevzj^C(RM}wZoX}d z4u8qcBIsd894lz~n~tdo{WDzXsA*gP0nh6{hw9`rJz*m4T3g-l@*oN|-Dynij_#a~ zTrCBA`isK)k_3|1Lb-9JSB!f<@Acy4ZNaDidR5IE2j0G$@tn1_)$^zPdHiUPT9idy zWhJO3W9NY|$Ty0T@DW*SgqMc?K=%)yG0dO?@qo)zu+pF8PLlO(M!EUWjSqQGr1@%k zzcAW?B%_Jw$dU52=HwZvI-6c1(swWTauuXo^blMfQKh1)PEV7n2DcfjTVxb5u{GVk z45V+cyJ$fyNRv&RraeRBw#bj$v%J3VB}6r~Rr!@@tBu$G!lLfFJ94`0TfIU4Ons3* zYw@2Up>Xx_KnW|GM@dil?t|@gak5DKquS=*Wx3F#lM50N0B`l9|?%gSX3l}=+_MAHZ$j8t#=*4 zTHhk{s&I3u7dPv1g#F-e)$N7`+w*Gz*CXTjsK8I0=yy`eJGY9+MdulM>gw1GwRtt3 z>m&#cMC(+qv1Cu=J{NBKq*&7yYhfH?Q-1V#-axva*4uBPfe+~@ZK4{u*huT`CNA_V zb~ROK8`=>1J0{_i!wuvQRY%sO)oDaoeB)}K){rHxz~jA`&+qvIU5*pCCojl$Y;%Ja zhAC1`MCihH-^L^u@b=d_x%=*0HVb_!eDgbrv04}dx0z#4pm6J${9GLCDqian>q6Da z6R&?9*|CZh!i|}7*CU?7C4r(WDui;xSEvRGP0>BPU>neWIXy~5{W-uR9hvn19lqzp z3Uul?)}miJU}Qcs%pTe5c`BCMau&N82o~G$3!$2k6?-FPc~R`j+JVSe(tOeMO}Asm zs<(81WXPR4(?_a&Nl>uiPx_8sE5qe6JHkQPZq)=P2x>|>6acF#+mWEOKH6iW7!&(x z5oQ}nJ){UmNHg9A3v4i6j)2`4BScPR9UsLr5=I5n&eB_ZkL zKh1Z^o@_lryHAOi3NPGoFJsNKj#^J1k(jPh0(v%h-dc z8uBS6zws-K^DQ&9?v3Yfuxe z8Sye5h&hp5G)|5jF$HPXc=r0O?%jP#XolP(KGb`yqliAZ=qZIMCD*%bSD z;QorXr_FA|ZhQ$b2|bK0|EB-N-6ZYDPkPb_B$3-GXT>%O!pM}5Fi<)p>m-P>oFjY` z2)qIE!A-JoXW-!!RRBqXl8g5kz9<)w)IT!y1JA_`$)}Pq=J=Arh+(#1-ndEZMM42q z1OG`;4h37LScIvYB78^K7|2J`PA{))NlMzyd3TQqd3pF zgJ)n5uzXwu9%2@<`h(2xTB1?evo~HKsSyW}n{)ICB|jdD7eYUDjOj@TQvmg6-~1(k zRpuPw))TEBlY@)d4#D6qwt;?7|Euz2Y*g_0C9WjH{Uvq>dF%6OR@fcrE>R*mp@;Tf z2PB+yfDiU#+YkfqDVvj``2R8zpfnSi)#+_D6aM62_Yp3ENeNH#CH2%(10XE1hZx`( z+z>VxUG5hUWD_^!KbUKx3=V=nhnWx+2;K(GU`S#jbih;~Gma6iB39T0#9rh6ZLD?T zKYiT7q(5bk>g9)iDx4?x{zxxYXE0E27O=|mulQ^od!Pq?@^RKNjWcWbo78u*_oh;r ziC#3YGiB!4z~lp_B`oJf$UVl2EqDd;d&qiN5V)Z?ypHx5DB(mIEX1+D0wv-!hZ$FZ z?mn6bh5K^n>p9-a6Nr7h(zkfOzvRs?3hRFmy&MaG_&%b+ya@Z-fEgk-v=o0s$d3A^ zn%j)$iNW`++V2Gx!V&D3P>*-vHbUtll-iAn7|8k2QIgE(`~=L)k;Mac7?LFQWajJp zv;IK|<_gARbM2#E`K_SB1@ci7;s-A$=p;nYm?k&lx8NW&bA)k2Bw#L(W{kz5@}VsP z-~@XPVqXY3^TrD#9CCr@*f#R5W^*dAP=+}blTtV+i6w4ZL%a?G1U=-@@Ws_3k=B(S z_#xR_7RGDT)5IjtZi9&m`fD@cm*7nUBS<|F0uQpOF~aV07TQ1+7$`D`h(@YXD>1pF z}5dJ}{k4E#Wa`nTRFV)gg^bLRAOBAIAxl&*j< zWB_ZCgd&Cn#X9~;8gh(xA#BDa5MRy(YI+x#K+Y)hA%1lnM2!e5X8?u7)_;2UV?Q%_ zA0ic3`p8pUo&_chL6JKO;<!M~f#%Kb@Ls7EM$uzY+3qiGme9}*F(6N@51y#V(sOD0S{x=?UDCPB%A zqm)BpCoww+OhsS~$~$o=kUF`kp+G#OCjmuNPX~*J1X5JzT)*MKM@fS3K>ehi7=sDv zY_Jkj9FSQo1CFO0>@&nQZj}IW5BppJI#N|9M+`thaV5(E(GDaO`yvuBo5ktCgPDUP z<8P#CKwult5iSZ3c&XkId-A~;a})YOcG^H(2;>qs1RHjzOk+%eQ)mbjf(iQpxrq~S zDdE85e9Q_H124x4xJ?787uiSnz@nU4Um>3CjMykMAjg1;b~bj1C=6Q}c#kTBufP;I zA*?{QH|YPYItjdbJh@<}5RHUV3{Sp4ViX8J7=HX}22f=`NFVcpj|Q}h+v)+)K!?c& z$}uBcfHZcPo{xa@Py(4%7iv?!qd+`|m?xBypq_%wAoeOVOr)N|Fj+oC066BH`41irH0(MOoR6*)V4-;1w2GR*6 zF_jYtV0+5KB!Ii94Hi@m!R(+!kV4GkP&(>4JMqR|*d2teZJ-%-h8PUV6rfU1a04g{ zFN73E0GY)N;RBxZ`Z$ZEsDSo~v+Eu7hw3qm2&90C;s7Vq;l~TS1$trw(k3X|O+I0~ z?#*Kwv<4=YQD|t_!sf9OqFabu$T*_t*ywm+w79!-`52%w@#!_`b)ya&!YWY zFRvmCnAUOb9`(>iJnq505k6N(J}JRZWJ&Q&s!a6FkNCmTrE3QY)6!RQNUls8;4rNE zw?WWv&w~YB28DtAVh4C+A$<-hEb+%h|3F)@EO7$_cX>?foVAGq+PHTZkTiPjW_ zDtQF^xdM_Hc{{)4%t7807jX^E{P*kH9yvN5%_VF@3_>>9mSBwc4(j*ZLQa&gbQM&U z3fF^`OJjC%~;^P-H(ny6jm4MnC*u>p&HMaBT&0#X<6i9qzlo$nm6U8l= zwcsV|xm&X|b_Ai0vSG#@o@Ck`p553*Db!C@9I9>`PJ8}%-x@LoHAfNvCZxq_%1AeI z%z-eaVr^)5;G-iKmSFDgQnEYiLnXdBdLn3w3kSJ121Rnnm5O`XFZDwuq-=Sw-Z3UK zt^%27N+3LtU$k3^p_Cmc@@QNR!U%PO8s;@@Lwcdx&?$H&Mn7PL3~YIT2m&2a0>$*x z%F*|v_f}w45LOV%f_a1S+Og#F#hH*{Knok#wY8x@(>?s*w4Mop@UyR>Al5yB4S0m} zJCJnFaWMaTpndM~*_uVXQX^dN?ZYe`bQT$1d>A25vop4Odj_VMo4f9|kMQ^64-Gw=lQ}$Wtcs z2B#v$TP>mhm^gej|3#2~hi9f0mewwJY?Cy=e#zRd4{W1uxlMv1*-=tuO~EZhlw*yo zAI%D)E5_}izF`TAEI~8_Ib-N<4N>YqM+dUoX7i!Ysb5xk#TL5yD#faFZ=$ja&|Png zHz(dF9d;Odjoahhp&52(3(y=#BzABvP=xsSCO*ly8sr!CN*VOIGmi1*ouRW|(xcpd zk{i6%E>(4)mr&42tVltca<~}07eb5Nn0I^3tAuq|77_mb9KCZ7`Dx1ZRHOI#Pq0?- zpbt66s>b8n^QC(jF2ZtB6tRru{K0S8YG(Jn@lKn$Ge@Z z_n>WOw2c$J8I=V%R~79z(3`Ohogd$01*i0FIo}w55iGe+7!WjP4NmR35kT-S#K4JU zw!Mrw+8v6+#N5_}Iq_Tlv`8U-Dy+(pWC#KCs&i|r`=ruQRDKwS#l1*yqh(Ze;l2`m z&LhM_^cs00|R;>NCh2 z3_bPVKGcXR59U2FDvEJwSHFa;XNj}q1>oOgW%|3b(&}oweSkPXqfEVtO75x3;zA!D zpY!=#1;7%5s$y4xLdw$@d81fw`p-E_F7p3P{CR)=0!ZB@e)U)UoWt1=bj2BIt>M>l z0}&I82c0P9$^8{CLcVY*475u^44X6pUAFT(w z-a+Oj|Ga-{_9rhsn#-KE-5T&F1{xbcH%1R5V&JutZZ|24VaHq9hnv`5CmC}9n|V|t zPjyoS6eSI`e3vF}uEVe0MQBZUq5P08w%Bt{$r%BKEJ8A@V9F#j5SChP7{X*Mn16vu&hCbZD-M#^C70l4}u0|bwBh!M$ zAn&xLMWP&lqiol5Q^Pv(NAx@qs9gt5%qn2?+cqkCcmciks{>YZju+a^Kz0V8MdYB^ z0q>nEU}fRoKgEp)Xzs{+uzFG>ZTas~gWo4@3bjS2d-5JemlwP*zSo~@sKK4=t2#G# z#@k63JHfl)h|EV|S-fofWp=2DY-q(0;;j7^1rH0C@=F;I31vmhMs2Y-*&Zr->^NSf znI9^;cTeAHZ*32pB;8~5lihHhN7qRsvB4U&v9*_@#|iVTnBG~xpvI~P~W1(4aNn^(HQ+^M_R!p!b`phROZh4d7ym9_Fh*Mg2WcKorP2j@ z$RmmU)9#E7c?w#=;G3hnNq;JhG(c*#U_d?Kc7M!^NMhl^z=R&YAx4^ti@)d$q)G$K zZ`GwRRLB74PDctuXRt6_2`LG562W{Pg_H(z+QlBGz;&UKP^uBE#Ax2LXtB2$xcC*K zM4tjhf|X2ZiNFzWEn~$v{J+foBEh?}-LwE&`w~8XXDoyR^8*-Y9$Xvxi{M{zCNyqn7R;Bly!TP z@j}+>r;bmyW>Izabc@r}pyGw`xD4(J!6& z%=zG*$harwZMGwC0}tz86TLmECuY}+G&p-&jf8V(5wpME`@56%cOv88&kw`ZZ@^zP znk~rQy#rhSxNYk?HLjcfjwD zpA?uLvjjV_O&aPy#T#NT-0KK3(mK2=ow#Ejvo)fW=6zgPiyQuXtSyk)MrMYa?-(yb+srF)R?vd1TeV^*zk6`tT-SCF zPgpT6dmxby*=eLhefoA!XV`xG*OS-fcWh*GDJ2ecNgIP&0Yll=YP&(<0h#zbx3%4o zb>H7NyPbPmhgtVBCWbfrOT75Wk!w@F+?gu&eZ<8VjPQShEWVBQLeljrmD!=v8%0>G zv04^3o_Dd-$_FCBgUMPOdGPAb6NT)VUAObUar-3k%RjKG!$&UaHSLY3UXe%jgTvs# z5`QLCa78(Ch1Zdk8S`G(MM3=#CD+<)rmQ7a_Y5c1XSK2%uSVYFW{!@`DIW!uDa8>Enb+4ON8Eh6AgP={wH8{jGomk zs{AaV_*E~X)o;7aQ)rqP{r_HJ69u9~{0_9n141?b_M@z{u3K~dxUla`sZ16p z0ZRi@H2`_rnse#Gel(@B8sqymK%3Q-@wL}83v5Q&efRa21Rm&Umc~M^=d+%;thEpc z-{r3#?KHPTnKwr2ym9UdLS+Q`keOQMiH3ng@urqJq(oxRK~h5FNw{{;LDB)#(xY_MjqB(|HQiO-II}-!h^)0^V+^qKUQ}ovlD!gZc8+BMVMGILgg#?9ADXsx{V{- zQ+W7U+kUOfGqUe=m?}r@KIb!$Z7x3y)d!pGINH;svDcI+|Cvl&zMqkMzz~iZM@3sR z6d!Dv!#)6`qgjd?md<86!6$=~R76rEYOypus!y9tRVOx8JX92ZZp-|aMZ4Ns-&>TI zSXqd=`#vxuxJJm(~Q+iW%`7Vwh%C^s2Z0TWzTn4vT7DKjX z-?-b0KUz&z5d(+!K z`TRdF9b@N+MDZ$YV^>Ycuh zr+BpSK0)L0XJiZ2(_{SoC&V^bPjEK&*FV4(*u-mth+7LlMN;EpkF2Ch6;!iLjEv+2 zCe_rFr}nC=n_)0{j%wH8YIk$_YOAAE*AC87v&KIwKOScu{|Yy)Kb8+0t`9mmE1G-> z#{Mp{nI_EP!2KgByQNM9mh9|G1j=c*6 zNrjdrI50f8??2%eWJd8DG3CCecvEvI9aj7?{ciHx2&GcEvK6J?(t)g_5o3aMulhM2 zg)gl(CqsFpiK;EEw)#T~zLobvFO*BjI?TYWTm9hGCUix#&&K3Y%HHvC=iil(hOft^i$26gc;>#t=`ZN4JD*>8h@GM$b~2(9wc>mF z1>WyMI^wOc`BG4}!@_S2ZkIGQ@`5#7Y{r>|YJczQZi=L`L3N7m7z5erVCGKF zX1wfN!Ee=>?LCvqmbsm=(`VeGLm$YR_9>-IzZhqcVk$%$h&Pp_?i{Y-;MC+73QK;x zDYu`|bkDp{^lR(Qqe;6`TriUu3Y|(CJ`H!{%*28Fs57J|3P_9L9_Jh+JF#dbXZhaj zWK+caXqGsH-@s-DXe8f+?Q-W0p>RT5U_J(#-1!>PFEidS#QffZEfL)_nn~Dujv27b znr;3y(b>~`VmC>yA@%F4mG%CwwDLNx()pu#6YZMmLMI*~TS3_>6#+M$I%5-^LMgRj z5}DUUZZcMsZhyGyCi3;zMN1~~`2;^W&424PUNq6()f2Yz^qiPC(Jd-5Zq2TvfjW7r zBVSun$h|dB%;u+k?n#!ReObqKP-@-ko2;Yy%Oz|rReiz3Vzhkcn;CzvfRBaCVSS@r zVOvAbp+Kax`x1|EMqZnxF?g`*~4zvC}JL2q0)#k#fTRJoF+mTAeyU-(sGlO+v9 zYzq=J$f(Z{_UB~_XyL;xoq7j}(uGg8b6Bol#7BZ3rN&U>X4A6~Ma1rbrNWC>lfEHC z@(N5|Hmy!1#ZPqGqseZ9av!h%m_6P|yH=2^ygK<+!f7lzn?x5^mS$2~hv7PhKMtxtHXneC)CDL86oq<)u}Ch(m(IaT*w zpJ0j{B?{O}cFlX)T-YshAtNOgE3UagOMbO;>jL88BepfyT@0)H8%q1UBQUlu($B~+ z&^2@VsWil6dT3hhm~5km7-aihr8|$`ls(V{3`KuKoAXuM?>tSS2p@JYPNBx1+ z7Bihnof@>CZNr|c+92WUBAF&!XJ$_8dq5yma#h4N+u6$)XcHx0H+_KoUh=#}4@(GN zH|q2FkbpE|bm+sky@%-BhO?&Wo`s@TYZ*G1xeuOX(`0&xE?;5)9W@;fz0o?BkHzju z3IT1}z7pzrre4^icB6MU%{G4$$ z$5>sKZmiEZf(X0JM8yT8Fc-DqFSf(&7i&?|6s|j=o#X|~*7U3dfzc8r(q!L!;fcFc zv_0CHM(i6zWkWn7*`EJ`NQ|1Km&wf}P`>+}U(Pf5SsWXX383FtVt!NpWe( zH+01 z&3RdTn@k5-T$_{Wa=MqDkxm8cjuk>QxNg_3J%nlMJi3EZ4Dka|lkORZ4^>nK-;V@A zhdu^PSLw;H0l#(Lv!a%llv}^Lc!e|R@EDffuRH73T8kj|%-6`1w!cYpo+t4XHmIxk z%@XM_{*YdaCu9ziWb<|o0crinnE$yc{ci%!kkga(A74<}%6jbdRowT<8O;5fI;(_7 z+&HpOE;!mm0>Vl z-3aqtk{RHexv>1&OyNRqWBhLVr^HYH-wr3MMlGs^y#cZP)}A;AzyZyHaF$nd=5cVJ zCM7(H*)ZFOA)e^0Fl}{Nm3ccl;V{7al8px^Ha`1F5q3>@osDIV@n{NSS5z!xmDHdh%Bpmf7c73CZAka4I>P6UxBv(HWeWuSkPc`_{ znoAUPgY)Zuv0NXL56jY4S$Dh?v7Fl9yp8y77j~9*0w-W;P2+sbv3&I5d5Kfbsn2|> z@}|q8yxW3(k|Qtj%vc7OHTzbKB<yA`*3>De>&Fc`tqW6$^&iVX*ZnsWsY z^hvD~cJ0?s2-D3)ggMqHO+$DK3e^`2zhhQyuj6qNlDP`~SQ66NG$nT!>p6K}F)@J;Y+F_Hx7* z-=2F~%u{i?$v-NA1~VtmhdkCmEf-%LC8rmHoMpSW;LR|)OFnx5{a z&)d;ssRgmHGLN|4nfCS#S8If?q>vl1+zKpz1C|e@7Ft8fJU;i#w3`CUHNdh&7emo& z8?U( z$KGnKPhkD}i!1y1=j&#!~+TTP>%_jz?oi`&F z4!k$ct)Vh&yzbL3I`@lv-r#BG2-ufY-28F-IJAK|JZ%ux`j>Sf%R``>{ss7)8S|S^U)rs z2N~R9#eH-iB0C%Sio%`r8Oo zRx+P2EaMy8nX2Hui- z13;B07rc9_%`A8Jv4*rFJlHs8_GL5xPxC>qzGv0q&joTOlAFakP`ygnjLBj_C z8YK^8Vi`*TSq2&g0PXK}0Q@7{vavtD0Te=Lh0}~2>9Y=CX1iSD)ZgSW-?C{gxo_#$ zP!`ofXoI8C>YVa{VJfikOFu& zX#i}{MnR zy z<+q913n4}T-@^v*7u><+&Ba^*ETZ*6X#PKdKSJyGcmVzg&AXv}mD@415o`E0N9lSRoJ6}#Sm$!NyZc0_{MTHRJx#Q=NzMSXiL0K>&U0QMEqPgp$4hJOw zCjCmnVD^v)fKnci=N9dpfmXTCpBW59`WfHy#OR|T1Px{Y3<}jnPLG3K~-9S z01xdmg$61(>j7908l4=Ys>kqiePXgu$h8u-*y3+y@1#AV za6~=w%vZ#o$x*~^qHdtJ<~HYVH)u3=@35=|zp|`_Tes*yB^?V@4n_r%ii|}YwzTXa zl5iuqHH^d>PdI)_l?X}#4|L~jf4qt_lPsmGscHkchOfYF-328KSH;_vfgin9afHYb zeJSS=y*1WRY-O!fbKE`I4fVML(i%Aje+PX~u8O-SjiQZsbi))Zvwar=4}#9A&LuRb zWXJl(mO@39V+vVt?+hcT&*}D!;6Yl;=R5;Ks zV5KcX3Mf_ESXgNiPo$;xb-aQNk_E{H=R|Wl5Vt+1jk3g-U>G38Xn%I1YaEG37-onRnhkXy8>~}!DU4c9N0AHGEk^{m zhY7;E6-pI@!z>?MGe{6(@TWRfg!{xk_sly+D`q;^z7 zh~)!sIeWQ&1#B&q=L=1U8pB4A3r^)gIZb#b=Yj+~h&143-K&b&QrLs}A)yX34LD|Z zT*9g3vthkRI|qUWTrF9j zj%9=(7(Y8vyrOs+HkAHwR|h5tZ3B}8L)JU(5K_5Pg$#vUj9Is6PCiklj0$-$$* zE${fqnm|4Fp@yzmxJl^ba~PRM>^qse($pAsv=qt)`4c&Ve1z;T<{L1sLE~QTrgc5F z>O_JzHVv?I?*tbeH0DFwVc{lurazSpBq*;*{MLSNU8OE4+$#}C<`U-m&ZqGDu271X zTex!K^8GY;Har8~i3=4+E0x>VlEN9W_lz}zg3~vN@Yxve2UQe%56$>ypEbx=DmoOJ zL?MZKCBnxZ?md(+s8mELVI}ROu~Lt*Qn<^^>yZJ+gDuaj0t8$KsF~2%m-R497OMcH z(?%>=+g%I}gaxgL;+gL2L|(y|se&fqIDMLNOp~u(gUz;V6_bbcN&^4@!o9iMB*NLR}*Zk@&Dx1*TN72xJtj zA5NyIBgYhy7cN71O^SJf_D6wHWXOKFtU`YH&3)j#YZ~lYe+=P43!xoRd`NqkJ#1Vd zI6?;hnxu^sBZ>AyF(F9=Z0-fh+d0GNKz(>^YFHxsFQJ4bf`|7<%s)|peDE+IM#kiB z(-vq@!2*)^0z*rK@1xZmXdxun(#GK+0pSt4hk0eka%ybRipSQ`shswQm^hPAq&>VBxea5{ zw;VI!+>A(9^Me-_bzpOy!Ja##Lrz7*5@z#)Pd91~yqLWzJK97EWDb5mBz~^ztUP*>F&SMWPjl_ES&!rCThEb5k*@&$O=8slEX#aX&}ND&QQ`xz9_h;f)YEI z$b(e*CKX#d=EghzX%U1mkyz2*8o|N}PeUA}t;G8psy$ z52E^D1P=5PcV=K3@VUXbduV8;$2-PU8hq37|k+3|zCK~iz)1<_7_EX|XaxAjKd`gV;2j$^F^G5{bWT`dqFt}(QR0gsco*%=) z45H9bUQ9F*n2h|EoFwuhof!SeL;%T*?8L6P57-qa8_Af+=Y+C90rB`H@i`5~2AFDC zZVa34ns!wdchq$e=DyggKoWrhDJ2wVjp2e=0-97=qhLR%Nrjfm91JbN5|E-1Tlpyv zD^b=nK~r4?yE@okKnwe{@GyoG(t?#&8NhHhsBL+|M+Gv7T#{NXP|lgd5lurDywhA> ztw_)bh@{gDYcgXnqp_pCH#wy1c{(wq)I{K93_F4qJ?p^%Np)@-Kb2?}<|Fo6+YJVm z^tk!Eb?5h&Us>MZFB3DI8*wwD#F5nSZ3U~)Jp5%s2GV6b2ApM5t+2y)3E{5fdw6Z8 zm2|BFsfk>QYOQr6Uh;D>-uD8{D(O&y0^_)WMq910arr8w_g}^Yi!%Qu46*2kK`ClT zBlZEN3_o5}*kAa8*^9XpEaNReM%-z+6#_Q^F+Pz{!xAZQpR#PP48>A;6~)z8{^V#E zlr2gU$$|8R8^Dj`bCDNtN+j7+e9W`d(8GvHq_i#`hAK7Ud_uwt89q`Whi_|%+h({0 zfMpDJ5TZRZjYBM-opK_%K$f`BG;IGB$WlqqTaqZbq4uLF&tn zI>}=R!R6~r${mH3LC}>!*bXJv#mR+pekTp%xP*SYkE$5Ewl~nLT9nY4L zcW(yMVqiN)5k2%RX6)Q6<`1v?KJv>(jP|PDR|0z50DO*a*3G%1>#Vrj*PvjJ2TVWt zYz0q;zH~;Myd6CYXs9-_m7Gc9(uly(Q@o0>tEL|u##73<`4LuNs?vc@*uI~z)J%yN zQ@FouEe1bV&U z>!P-+vK3r*2kFSK3e69 z7yD6KmDc&?8I|R1vQObw9mHoF6=~$%A4*C{kCNt@s-!Q?%3FrLDmT)q7)3^wz2>F` zE!g9tZwbFTj~GVjYXkdL*m2q!N=0*)xL%0Si)MW(k^gS|X}hts&MD)5R7(CTRK?ta z?QGY*NLIEwR|Tb56Iy!FVwv_pda97Iq~?%fUv(xkf2NSu;fMURV&+aFX!OkLSGxx$ zt7AQ&Q8goP!k{NYCGT^s3Ma3cds6uCq2rTTZv6PF4^!g28V8!@Kvc#j(a{Q``=97) zX7TzKRx(Y1?B#7VDe9&$Qt%bgffErzJR=7Gm;4XuORB0h`@N;j9kAZ2T$kCChpPgo zJq4IctqLOM2oJ#H3vIzpl!N&d5ohx&e^Vem_=tj!#ZvSm%cFPmKxs2b=O3olwwP{k z-p+2|D>5(ZB zn#GJdk9rm%^D@K@e9j|Ex_g!i0a>1t_8;JTgwB(do2@u#MTU!qtSd9bwpf~o56?aQ zU}FB{%etGVOKtZ=)nb53eCg=ePT=KaUL^Gn&B=y87YGnT@w&Prgr|ksHBBQmI^@sC z7N$L}GW*c+4ZGaw;cp|2Y2YCC7f)(_>PM1f|33dpZQ`e!D?D_gH}hKC1ipLvs<5vX ztZ$^XIHT#c{P*9f8O7`S4em?KET8KLwH5hR2ID586M(CRT9^R_Qi{C})$%lt34lh2 zXh*FR5H9fEX>;*oLm}2}Xydr9^?8U!yQMK_!iRQ`Y@_lk67{yEA>o%1cN8K*E-%({ZkTu7Z4SUZn@7&@Z2yCU0T$!Y3ZLu3OT8i3wXvn^hpff2}Z zCk;dhlZ2St^|vy*{nnRnPujr6K}LIc!X{-u^?WcD2|SiW(%I?u`_cZ29Esr;) zCy{n7UG*_D(phr@pQq~NWBhb!d8v60vCd*ur%a8$ z4{j(^eJgNeLIMaA$a~vQeywH&TI}mEpAdYk>nc{uAN=E;tM-%#)$o-gzKUxlF;!f_8e)*yNm z<(XeLA%caewfskCv;EJ=VE^JkNspj!J+pCIGwR)QLZvQx^%0z9)|gpOJFq%?ADP0qpeRoF!ZBwFM6rC-fV)l^Ugc z+h1M2jp{evcn=1O1x}mI^g3COg1^`~I<>!mj>E$=8e5Eo8^K*-31HAwdMGU{_BYie zG)Vv1u{SA0P6a5C{0)H)YuIB@Q@VlbxWA=bOyS#(-cy5z41i9Qe{8Ej&2OH=2@zoh zj@SyRG66}g=pivv^)^_rTaTW{T=-ibZ=Rejp34*6;y1IS^T{>ov4>Cmiq^7pW9g`? zIzPO!=^_5&VtzuA<|%GP-;+-FB)zPAkZ0(7xj87xKk|^O*nn#IZI7xJr{3{K<0G8~fN)-}F*9Az)0s>2 ztNxfZ`3Z(Q_RavS*Lj!i?tAQRiC|F1?%MrQo>RZslP|?#iV#>XxXs{&+z(1Ul-SHcvE;XO!|MT49rO)1%o~S(@Ekk4`+q^Vp>`9&LP4 z4Ym8(#c>qG1?}_atF0lFP!Mrd=VFd{24MJ;Q+b>@S7GVtZBwmgiic>4&oQnIArP(A zTU!~3io+}dmTx}eK({MDzvYHE-(7bPdOhxt*BqpwtGSW!PBkzyZf$>>ZPG3?&OL;# zs^-^^P;x&4Ui2_ZK#Xo>PiA@{2q-P1nr*dMYAKoKK8A^Od^dcrK)Nw`>Fe~i!8)ne zwd3@a0ZG2}$rW#Rfc;AS$5)hZg^%ki`LFGatY{T`lcny@i6CU>y<+l&i@=dd?pxx* z9XeWNU305^t{=iel`rNz^CKo2cw`5}YGm&=mw)--YQj#b+{^f}Rx6OrPg$jpTE8PW7i}j6=U9<7Z5C~ecEBc_w8*t0RKUv z_$QUlqSS?~Bj3^QphwH;e_jR^vvnviFsOZ^I07tjtw%fxy}Rj=5TNP&{6a%dICXk$ldfJBcLeqre4;+jQ6sKcE5V|<`tE3W!JRJG!8~NI9f$ik!Ko$w zN?nxWTmL%0p3=tDHS)`PRryzO6LPJ=j8fOTu?1kzZ?ZPoBnwwvyixCf4CP6OumCO! zK^3Jlcw_^2mV!6HSJQ(TNJ~CFEqQ%s>>)F!)k=D11K@($NZn0ccRfs(?d9~l4#(^9 zufM(#OT(FE(hdn#`q{j$zP^~7%>DWMw{6$T>$0d^rOVC|W3q`-P5(6C8mY}*yv_jM zXrB=Iz24I-H{AntN0YJ;Vy7&HRkLcgG|muSc%^JH<=#N%dl@8ZJ2H`_gh#Tvqd#4& zS1b^qa)Q}ND6{Ma{&Cs8?_cMR|6zrn;;m59R%YJhyW}Pk_TfSf=CIIbT188*lt0J0 zIE=hiT>n$1VAn$Y;l(;#Z@O|?$Rn`4VNFy9s{D&x_e(^LXpbtqY6qI^VRY{sJ-Vlyqg-6j>E{ ze~32p`XyY)j&SWbBOdBo3Jx;d>HM>;Bz)K|JIUKld{D=n<)BX1HH`VuLz!_B@22s* z?X!PiraZ${Yiicewmw)rU!$BOfVa2=jRkhM^@l{Bmy`%RFL7pGOLkDW)fHTY`H;Np z)zi}K*3_EiGx!*s;>Z=P~G)n9EZkwe3L{9ird zpUZfae4iNJ`>64@_+jTw5tEgvx&N4Uv9x{ZVqX1miSjHMY->Yj>r)38lQgX#j?4y% z$-4>|2#Tg1bBh*Z?}&d}d%E$jWUSP;49T%q(*vfm!k!odX6Frvmh}b%chO6%e)-r6 zcR58Gaab;eIOM>#9RIeiONCkG5`g&J#Cs8XzOB$D_bOSdgBrKAW#z}YT|WsG=g}@o zovjX-CiUQnWp&Z8hr$%qM14iWD_@-qth!7PpSBzDoAakI9h4h8fzCqiI_ECB&bwUb zdL^DCOHp|$wEo3N*VnGkU=y!Z_n=R8HC+tO5=&-8E1OZV{@-(%wZ5?2GGC#)KKEQ1 zjv=Wv{FheS4_>j5a=@5MSVA zR_7&7%mHKVXoXeNtKF-zATg1IsU>CY*?P(%kBBo|PSe%bUU_~kS}tw-KWplSWQo25swnsTE$q+ZsizfL zslL1G8T|l;h$)>FykuD}lUq@)5?R%=@p_)%bkS&1C;!_#s@7D!CTu3`Fo-Yb~W zdF|KjX+p4WI?6)${4Oi#R)27*YoRg$fk2*heqZ8Z?joTPY&Jf1j_I5EME7cxB>1_F zLWtJw=JEMVZ!J!rh;S-x17h=2p?M>dukV?@BJF}nfrKpFom%NkXlL!|sD zZ$+XTv$dYM*ko_WGA5=V-xCGaW7|(Fcv>SFTRQL16Rc zuB@6PwiSNEtY7E#Y-2p>_-NAZ%xxp}dzYTYU5^5)sVWzA3K@--?d5zb)aM+Wn{vA9 z6EB+D$G`8moGxvhHTC#Xp$ye-_PG$4ZSBF_p0$OAt7l)eS=fZiiB+e35tgVfS#m_{ zATJ~?%JHnJx&G~)?xvH-FY3R(KV*w&{$);kj^n@bu2bYY{d~mNVy^gut0`Y{pt++}61c`n*>-nf3dtpY z!H1N_a+vBCwTJ|TD^V1lM+)I}me(y#?uT)iizJnY z@Vw<}A`>EHwAU2|zGP zq}MZi43n|8eAF`y#da8R1KyAVU$`fd4#tbhPA#Nsqm$5D#DhqnT~HB7X(SDD4lW3H zljBP+#m&VHq%7{u;&m8mak{O4_&_dlA(iaSx|w<2M}ueRF=}Uw*;7YtbIGL zLl)%y9RzY1#*YFZ#n9Rw9rvZV6Ea{TW6SutI0sQ5I2~)8YGp$eC&66+B;&=^X|c^l)*UhKXF^{LRjC(ba>7Ckra@QDi?%3psiyZ>5bfmcgxKU zU&RZ$CVFHDcHIFIFFznr5S6cay38XW;&Dg~&wyQ%r$)I(1cjc9(A2<|HUkNkp9Ma| z2%vpXT$816Nw}|^Rhp-quiA&TA*+<_*!{he0C+om3Fan8IT>gG{a|8-ltG!F1gKrO zpe$@xllT>K))hgvt6>R|U1SXS*LT2CK@WJM4kK<}j2#zy$9M&xOd4cEf>eRa_{&7g zWZtmr@&+Fi4hJ7v@Sk&obDn*CMXYcuh4Gjf{ImBn_{+RTOlVP$l{-KVED`9j^3>+J zz0}=6l^oIc>5%S-L+Wjk0;O{?NU4}xVl$DU6n8naFb;|ghDjq&TRjOD@5RfxCF+r3 z_zgo`LzLkcLuL5Otc8q*aw2%roQGR5CM*EdZtFx=A!Qsal%-MBYp$e=;Y}CrN~;R~ zq-ZAxIy8MlAX3OdvVn9F=OA<}qKm_g6{TvsEl&qOg+D{xMKSsb%G20VD~Jwe6JT09 zGGX0+2^t8$kkyJNk`UXwJ)BLTjs@HD1PPJ%kh~}khX3rCa2J3BtJG zIH*P>J6Zzegw+g90^$bhV7=`@%A;DbKmyhuA#UtI+l%~(&@k+vSR35Jn&jQ0d=#T# zOas{jP<^a8zr!l-nfy^?4ALLAjUAvFK_?k)_zKzbC_v`UwJKJk21X{Yl6csI1f!UB zaWL#?5^OwHGq3{@Tl}D?BA@>b3e!VRJv~ zhOF(L*}L;$--l0|%M}yW&ORHgJEK|0VQ+Z-}5WXg7znzlP;+L%POj zZX-w)&t)BIM>Of-Wd>N&BuFoKENojof8%=(+|E`-P8_Qj`!Ya*WW*9(e|6b|?CxU1 zusZ71=I%4#3oF_y2*MeV+$ajHwQDMHM6$yY%*R0_HF8VN9M+1I{VPu`#Dr=7>pVUW zb|>Y*ZZ@s4aAsROg_AfR4zxHn#6pnA5Xos$V1Mf{+}HDP0;vJFf#H%n+ZCV|60gu-$%7fPt?K`v>ass**YS5htxPv}^95O;Mf>~df%6bes6uCI~P zVsb|`2Lz*xup7THG6kzx`q?2xaq4s*)G@bc>CW=s==`+@{A=bk(Ivz+4Qu$WtvP%~ zmrv;VITNIDJ{Z|!eJd{-eT_dV-+r%6eP0&kjnwv2{=P1SBL6#&L#kr={F=%NsCWT# z1tuzEC*-nqmEv4Xg)mCHb`~B5i-P$MsXhq23w?qq8ktaV%Mdq1{S`S%!4lWlhmI1l zM4^BRQ71lz0d0x8z-|~!FtP!99<&Dy0n5c-k>sR@n8dhn?9R)F#E09%J`7@2zEV~g zND^sy*IeE347EHN2~z?25MioXD5DND7I+*?79T<~M_lD)$*FUYD#ax7>jLe#owxhM@)W2o(D(Vzwl7(&1*b)0V`K1hK;y~NVb{?yHJaOFO*RVkhZ1?6b)BU~ zJVx%phI>qO{b|HE6^p%I<4p=dszDB`ZFPYzL2kv1T}Iaw`ASiwO_duem@p-e$X?p~ z_Z?bH=By@qb{+wnKP-87`<~@8{DKt=dh8E*b_sdFkX?0#U@HUKN~-7&3!*PA%2O9b z{XNE^~T%GF{J814GKvWsfDCDBb7 zY6L8sE2J9?;2MpO6E;ewYlh4v)A^kkr2s+;xWl1Z)_Lb%O@Nsl2T+6238GestBJDD zFuoS|+0JQjUvb5HZ*4$pP`P-;3G;QDy1!eop>BL&4u<5w3 z-`J-9sFqICFMs)x7pQvsgHDt|IxQ*5EHki2=*BbtQ(;RYC#8Fv($jUsMfSxdiAOwW z#M;#D+#v^PFnaXWDl!LYM1A!=jHjHaQI_Fu!J32;z2YdM!XF^|dOyoFBPY8it?%C0 zjNOGpDQFF>{-HTZ`KQZW^VV)y-nuS;3fSl#*vpo)O(1QBOVWE+N6(iZsmpV27{qsv z#KlVoln;GaL1g)M&J=28C*2;+XmL1jNaJx4d7BGu{<^%xE`6|1SlCxLvt~C!q}g7q z?@`#-9$ zZi)jIZm|w6_F%u?;xDBAYFbL)V|>iJvZT2U;lEptm;I`mJ&4C46cNxF9&^E>Nkqrv zi>(DCiiMy_g}Yz-oAS+Vk9xz!oKg-5LNZpR#yQNFNlZI={0M#fNmpoR_nC~D!8j_q zze6daz`bC9n+mOpecVlPk!o2L+oXypi~3RTtI!}!yr$~y&ftf5%4xBXFS-|PTQ!z* z)aI*i-!O?9N+}PVMo$^$AB~f}ujpC8sYSdWS|RW_-^w6OvvBj2fkVyDkM#TBY7@P8 z!dtn_wlO1g$?ydi%se!z+! zYL`j?*+tcb-mvTIG>QorakOWBjxeq$6*bZ0`OIh0Q{DR6doKNb4sW;Xuh=;fF7was z-QK&6g_WYl6lLLO2&ePf&q7<+CMO7)JDGum4JF*zNOvp*RoMzip^ufKr|KKw>t;QPAyYIh+WFdeXIxp zOX-VZ?Ipx6_7%I^g^jgHr6%nbQ$nH1mC(4_Q-!)UnFTd!utI0AbcFljVl@ymfjiWu zMFO}^3nV`Xkb;nR88%IS50pFYiRr3qX5&q~>s0n5+^w5I_bcv{CIc?N=;~IkKwW3TljjVBVb8;ajZSHg3t*|f&_c_*AHe<| zs?H(mMgE+_60&9^QM(@g@keo=S;nd!gd3~c)WRCAOl4FUT|oU z2TutUzO;Ert7G*>edo8qZnk}afPqARA}>faL!d~5ZnF4#$IK%0=X4zQdIp?Lu*2j3d4FoOpv68e8Io` zDDp_<^a*&daVAuNWVY@$!{<;!c7`uty!D)Lp`m5IU_WlAFMsbF*r0Z?VekEDrT4$5 zi$H%*7v%_0m+r?H_{4e!sYV-nHM>%O6w37hjF=_>)9NZFXNe_@w1yD1Ry_Z8Fmnnt zGtU{&-T3uli7TMH^Z(OeL36Hv;Pz`UO$Dpd%tmDvZ$-({{2%Gy-&;7ZxFpxL|FtZk zof&Olx1QQ61~Sg6TQVf_*7@zqz*FleX`|y~-B@noB4LyrJ!5Cn*lOZpT-mfV?QLOv zFM6#uHw;_M)|31cQgFp9$BQCe0`agmSu}IGq19588_%CSY2+);|^m4SXrS_%o zMiTNj8S2c?6vj%9M^6-6Lmd4@7}_~O#=RCVZHz$&h#cSy$k>~1ct6t0^i6UvjL?%-t-EE&mF;;Tx6`OKK%tWybB=ZSS zL^&gN!n+q0N4d_JsY0N${SBqh-v)`}r6?TkLwWK`*erA+h5PVpymR^4B>3A5<9Hbg zhrglf_}eVvc&mS%{8&9+4T~BK#@~)0pW*p@i5Fom8fieE{TyUamL^v^R)V_)fWK#)Fbl%({@gKWA6pP@|J)`Dyz-vblVs< z*)p|r1Sm^2`)z0c353Vo$bT8H=2D(>*?sZKSAg_h0jeQ)ZT>Mw_H!2lTj!Wct)zO6 zHfKT`N%Wd2jd{wfcOQq%_`hf4Bv|XU<9I0xW83Xml{4ZeHmxB*eu;JBmT*$RF;IJ! z_MTb-Af*mGX{6PM7&H?WuP7Nt@EhNS4~?Wf{a<>GLhl<38iiKuG~{iV2y;}hy3E*C zW>o@G>cMT5wCnR5N=bqVFU{s?yb34^HF{B#{B4?XymW=by{I;8NZ;(U+S9nIo*Bp@ zfZzV#EHxKI{Z-T#)EEayX#{&3X=MOxgdRRnYxx?W-fR67=HVQZs+H8lAt0hOTQacl z7$~CDe91u(KH+fWkI=qy{C5@l0Q#zj76Ibzh~a7hKRi$h5+a@W zU%h;0_VqO_zPa&#p3@$M*~}DG(q7F77-`KS22F*5Mq15|qhr+WQ&pcqK7rdWsNGp7 zO0gH)ggxtoJ=?@K>x8dXfoRwI1GHm6e{{i=PmGO0k#kIgR#GiToruy{3961GF0762 zYy35R zKSIq^*wK9UpQJb8OZ$(3@QitnyE=R1A*O<|Y>bQd5e>k!+KM_Kz*zNeT}7P#H(J-7 zc>iw!yJKqTl-wiD0v)Xaoqqe(f9gw$g%m~2SYL(L@ox3o##TxVxjSB5K7d^QwwBYJ zCqPc+j3)c3+6sMa)x{O`0nAnpEdYQ%X~h_VudmCM_5T0XSszbyV4>KnPnAQC#s5@} z`0QH@xc69n=KM9Vn7@9px5IvMKVmE^FN7tR<#!=KJm{o-+2Q3 z&(+!S=~cqZv0rWf^ZN7PdUM_uz|p-L`;bM}hI)>D?;A+Z!}U93Y0^Vh;-*QdOz)wjv2j`X|*tp1vtbuNune zZ8tIi>azbHf3*6H?i8Oi+;*+IHvF_6mOCFUXT~u8*IV; zQwNrpR5d9VFkUTc#lW?$1PfBHp<}PUA%+6F2ikQyEa^Jal0v~=n}1qvw>r}%CJ0tX zp+4H7-cDWjE{mBS<4ex6pNA@E`E5v|_b5D$ zQ!DxYeEqOjz$TqWwV6Vd>B7X}X#)*agbTTUb)KInZ)(lm7YP&aFt4-Ygp>DBhH`Qj z3M->C2)Ql_`K3rkhN)C|*T|pffNPjCT6IHNN*s&pC8jl4VJ2+PK6WI}8~(S{R8MnKlWTm_@$$KA*SA|3=hCE@_x20S;F$0KRMU+J-0`pdKu1ci3 zZc11gvA)Kg=rX!X^xFJqa@Jc%=M@v0qh&}|-M$K^5b|>^g@pDX?uN-4nWus-Z0zGE z0hIF!!*xpm_rq*;Yr?6hg?C|S2=(w!g6HgH6AAQk;Ksav@s&?q_vK{s5&k##tTIlw3I-^ z>9oo34J1(L(mA`J=*W`hw;=u#Y0b9I?F!VB39)nIByFpHbv9nJ%9xzG(kRFgqoAHXV;*Z(<(EYC?MxTfU(MOM(XR^XTlR* z1=2sf-=?QmbEXfkz3?bWM;j_*YQNYE-%pcHF5-pzN4}^g(MV|gcKU-O6QcCn&L~%v zDQ4YqHNN@ra?Z5Ze(aY@vtqUbVydEI-s%inBVbYNd^m|eo!N<7 zMMOWrxrKf~RlF|A)0TO2KzTTcB%PU#Q$@rgp|X}<+(z6p$#diD=77>rQfw+SHHQkX zS%SqUdhr_i2nyO}(zF-$+-e!MFMvtOkO+-QN)9#SqJJ1AEW@p4jEaUt3{QZ#Rhnz* zmyR*uuea)*D!*hlLf2Q~r zEa(8#VpZ3_4`zlOJf2#4#z)&2ZRq!Nt!q^nLwtOi@~sAp`z?ak?2XTp@O7395YxXy zGYfIE`HPzmzm^K&j5f9yXRZvL)2lQl|JY*oqn~I3OP?=gb&Lp)&D3=fy8ht@;CqD2 znh&!a2EZkDBY!%mR(w?14Zbhu%WUlY**GY+y?xbfglpmz?)avP#<$bjLO`+8!~$+Q zr=80i?G(vYC%Ikzx0!Z`X7%q;JiYpZZuyPQ90~DnjB7Y5`t{zFK+n^6IS#d5yniCP zt_pZ|_liXdjE$!&g1w6?ncc(FxNJ>d8wb5}%Z_+d48AAzx+j|EHd?RvI$hg-Bvboo zJ^YUt|D}fjKU<0Q;m4SE8_unS@)m`X_3Es1E8(Kpb_dqOf=ulzrF#C&@jl@X7CCiX zypqfO&HD-MU|$&C7H%5XrF(`hkC$SMe$cCppA^c3>pc|c7|@$ulzVOd=o=?4g!xY< znbbSoS2L>TsUM^7q^X3~&!_I1Pb2nIa9-Cc4YqB=!-y0XHNcli9qm*SvPJs&R##HK zJ@TW70Pj%R==c36_fZdGW3P&D6nrg}9)D;o&Vmp5pA_SWv!oX0DMXu)Z3r6<Zq@rjyrD5D02S}?|L57m|bKeC}4UX+v2Ni{C{84)2*D8=+12CnE6Cyi% z%;nln0J8ILd|&80TW?Xb{;csg)I5WU-ntPIt+pVl3(zVGR4jTbe-^1aOuWO^{<$>? ze7@Hox7gY7evVq5`O!gEfOkMkXDOnM*dtDX#oQoSP?YMNQeAUDoH4|n_!ZcXB!Rdn zT`?@YotrDDmU;BOU;lYk;f6I_-b-6+6D_y#rK|)&+h0a2quE?xL|TT|)G2qTT9Qt(g{N$u-5}em=PNv>eBJfM@06>Yt#DzRy3Y)4$Pxm+Y`CWzZ&{v$UuAYI zGZ^wvtL$O6(`LX-Y7Nh&e$earR6da3Sw?~JVu7ae1rkin?i0TUM~)xy(z8YT_S#sStSV_r5yv6Yb^zm&qP@W&rn6FLZ8FvCwFh z(TBLa>6=ZXQ?rIMSz)>^(67g-tr}3sG3rsS)LATsiqscYA=?o1AM;f~a z1^^$=`bk!Nqmo>#c9xZII>~v`iaCE1eRpFK4=$zlJCQ&7_z`E%`H+Lm;*%!h*y0#E z75A|PayFHtYUJs5)gkQRM+3JdGix5TbYbYprf0FCVe5B6I+mC zAoa=mG>Hx8UM~XtWY>Tk$12U{pt8P2?PIE&Ref-S*;Cl?^Pp+5LtM(!Q11hFYJ6MK z8Sabbz<@0BSF!xnyn4%^Z~#L(QFM4QX8t|*S!?YV+RkXCozU+U+Im_WZhAB|Lh;1s zJL|LPUE0oHY-_FF$3AD5V*z1YR+SsQK#BuIn@B2vC$56u*~{a#2}#dLd`{1z>G;c7 z@j5SXBv;~qr55j8jE!~JSX$57t`rFTTicPU6@y{o)?jGep=B}Kb{Wbl#0055Kf<++ z7+p-~8=7mOi%-hvCY_%P8i_flXqrQ8uCc#i#s}1AFC)bd*!FFYmDILHigwN^Fhgm9 z%$J@oy_JirTPDRx9JPV6R@Da_c~4qgGRTc%uMt)@p6tMEx~!xJ@7B-AvZ%VHyYJuvuu8IOidgC3R zTlx~3T+(oiFg|nVR6{F--YLzAC6Ub@!r|k@Dls{8{mt*tmDaBbob2*xfPsfQfS48#M2X0ma`krmSX3-1CxWIb0vpIg{3;1`PTCb zPj{F!M~?f0KHmmMP8HvZDXx?R(+&Mu9q_-{qg`q|$*n?sHzm^$^9MxK8v~^L0maxx z#vhP|ZKVAH!r1|axi|7Hva3C}$5UTRgTZ3m&{p_H_TrScj>Ks{aJ=k#kFDb755eHZ z;B9{6tz}?BA;nnbO@H}qXVY5utPy5zap=~}eACLQ;>O9PQP8PAzgjxC^m;Ed=Id|A z_TLO;%F8$GPV-edo-b4XR0F2p^K-hMl<=Y0|+e$#H{iG6=PTy3qlM6yj(1p8-D zwEsDv5ey+!wbWu2tv;eY{qxK6V53~b8#TiR;cB4*hAM4|ib9ArsQGjo+!x29TB`2y8Y zu`^d-y0od)WV2~%-Df#rU(f6T-(0$^ZVI=>0_*G12UdeKBz7LGeFG0zzkKF2rL2><5Phe zbPeqZuKGq{eJu*Y94XAzrFui)2?vB0)0AREDq{%<{eY)b#SvFpnQO zu4^FE0m?Q&UqY#7f=nnZs0bHr@SO}JekgOTAh}~qtJ6L45+f~xQ~Y~Y7?z5bC@#oM z&7zw0Ye*g|jfdbI6bK20OioItCNP$w(NZ9oC_8hYT&BY#PzfM4LPXDKQELHZIi$_Z zfiJBjzJoiYy#iBkaA4;FRXo&Na@DUFzbyoUb_3_cpr_<^JPk!b} zYJO&YTu{D2aDO#?5X+01(XGCp)nintEVa2g!OMCi_#9x^&QWbU@;)`M>6^6YHzSE1 zXRFCa{jP=28ggA@Xp&C);#5hjmE+jd+kueiy5(bIYvrOH@WrH^?;ES{GzVQJ0a(Sf z2c)_)A0Mr^iLE`&{dGyImyH@{OP&$I2(l;#myk~6b8uh;z2j~)tIEWd)mh4ffyxIc zPp}S4xnx>_CI79y4yR&Z8TVPjWrl0v$u#qpRa-8nZt2J19a6+A->a=cj#xLDNTaJQ z8;(Msb@qGlr52EPo>QW!QKb4SEk>yyNT(to;U`miZSNB%0Fcn?k|R{slcSwQ?A`X{ zs9ZVj!cef!zfGpkf9SD|Bq*U)y30K7AXT{U{3wo-zscbI$r6VO7WhAHmuXZ}*_MF2 z3Kb{7fMJLNWg;@8KoALpF#{wdkPy@g6>LErxy08M~nAn~Njh&CwkqXgXezL+`g; zW+XYcv%CduQ7y??L6AuYnJ~`n?G4FUhavSYq$WGJ2jO~^A|O~t2eb5B1#P$A9sFbu z=cXpwN~UpBoY+BWq_ypHE^?tMy8AQDQ$V=`R6EjKZI#nmD;ys;=?pKpPjk?4Zc)~R zzIxkS&!{U+PSs%uhiN%$&>i(DV zb%r*{2>)Vf^NZR=^;35ClPGlb^8#!0uyhXc(jfYy@8uRur><~NGd@3UXli*;OBkO| z?&)CR_?0;y~CD{wb?W8+EtQD%U_ra}$ z(zkZ1gp`GD(pxt0f`&5T_8@)sPD>EDzCyk))MJR?Vyn>O%S?yC9YN*-araAgI_M6U zo(%OFBI0d=uq=yi{ggDEy@Q1h%%wOlIZQ-GcL~sh?k<%lFnZ_c#S&r#Cpk{k?h>b| zwYGWF9_$a!b9Ht}#wO3*ROe`ays_1`hDo}Ei)zy2qnbqK_1sP2t`5R=?V3JyP5*Hz zzm=?bX{fu|((W>|HQbf!33=gn(R$JrTl4+|(}1te{u9JUUmb_iXa(_&R>N)rm+6Cw z>uYJ1>>kOaJT6wM;n8%NBUC$_$MtU^`{+_F_A zT?dbWJ20@E)dHWKctK#XdrzaLgE~5qnlj?A4CHKD!JW4sL8L!0b@ zOT}uxo1xaulIRB!*?9I^xJt%otfQ41>q(}+8Y31rvZyHCq2K(%;3w-y<2|yN@*~;^ zH~Dc;UHHSbmzq_QfUo-{X>iVte7T1#J>y53K5TDAtffL%p;8rgFqJ1xu(8oy_ zl)stRf$fI+F>@h;xXexxP`ubFGh|mb zQjqZlh%)xNo6qyQ0^}%gm%oZ=^Tm?J?a|JT0F4*8NXCIGydq+0Z2KLpR(8HcwNZn)ZPa3(~jjU~JAk zcG!ZNW2i5b4xz7n9!<(vhRVAORC42^AK=B_9}94t|3@f;gjm){2|BSTR^rv~H`VlO z;~f4kgpa7*iq)`g;BUeyHf^LN`UK%Ggri8LVi48}7=;tmhVM~Gg&U-d2`AWjxI=~n zWX!ZD%ukTUVTY>}$DsBjZ;ewFV|Jg!C5FZ>$RiBh1LlB9!U1~aG&#Y3bP~TD8t*Sn z0^Q!I&O`S-P|NH3V1XHhpMg=HI7;<97EXmuOabP=c~hYr29+i0bblQ^-+6W)niIL-Azx9(*>|{;%SlkoI%|;&t%>9HTsNr zdV!v}VBbMfI<4mrxt=rG{<>`ya)R{=BF~4LzMu`oW=+{RTXeYhWVhyf zIT_FqHvPPeZbX=|R$*OUF(NGoXTY@(4LA=An}1= z`MSe)_P<_j)^ASy&Nej>3GDcBDS^N1IGGV#nQBUGEs)nE@8HHEJcy+Y)qid7)ZymO zO1HERky;3)4FMN_^YqVOUgIx||9z*WfG2#ZJ`cJJ$V=vOe#@}zi+vYGa|CqkL= zSc612)KeGsF6+G32mWav-_m*W4^O8kS=IxFF344e?hYV;NnK{I_LsJok8<({oSnAn zOZX`aq{L661@&rLLEO*6p6P~X`Km^rV2HJGd|_TXt;ilxL^d)su&&|ZCU(kW&!X3cdk#_p`yV7NCu$#OP-1JHPi03+#EwEu74?($Q z_LWeJIo0z@>6`w`HP0=prqjNd_ee5R{D?$Cs(7&Xbf>T?Gy`{E+*&Hj zhAq?Qgo04=$gnuB=m2R;|ITBL{^f>*$`PRBR~WINn7CDtwZPsos96wa9-z5S!xCrN zdGkUA4Yt~HL0DsdDXifX;eO#A!2MF5f?VIc414kL=Rlap_=>Qqi$F}uE=C5Z`(YlI zpM~|DGb0btakB^cK@fkAkq}r26htgUI7H$=JvtJKDIE%W6bhOQ1>Fe+{pw!&L#T~P zdtl0RwiAFd$ovX2hk_&h;lanJG|us-g6(Kqrg68IhyDSgD)79(OrLSSP=Jp7@} z_Q{D5bABsLc^#$5{5y`&dQ;`2D|+p%qeC2rAVF|nd;jiED2-k$cSTNkdJ-;S3p6+5euqhM5DR#-flnt2MBIs5&yiQ@o}8pteg{C@2RGD#E-Mi z(J1rJ)rRkG21Yi%BVJ_V=EoVFO13OVvkT|PrC(v6EH%Hjq;1e82{zMGnwqq|g@2+TftY-?57MFWK{+&? zTEtNHGdtW^Q!QdeU%5P(^7%FJv_H7TICd?`;d%OlwqX7ddGEg#Z(Z$0;)kp=4|Fiu%qmQm)4vr9)zbqY? z``5p%i~NQ8KTt~p1QY-O00;nPY(7`?w&}7|LI40_mjM7H0000%P+u`KG&MLfH!w6Z zGBq$UHZ(ObG&NsSaBpdBWpXZbcy#T3TXP$^lIFW3{2yv(9(+3H^n^s}9=jVMQkG;} zvelxxJ?F7VLS!8kt9a@nnckRRwh#N0_AhKEP{k@F5-1eqopbAsn2SYxS-2z;nTgEA z|NY7jvOG$YVDH}#{(Tq(KL^1?i1}G?w0|@h3{HnfCws@ogM-t< z3Rl8T9{#(4X2B#a<2?BA;ltZE_xQC{^j!pBMYx7x z-=wp!{pml6yxnTDj6^)|YIUBi(#&W?TixTd8I6oD!n(wrv_6RqLyEQ}BKyOHYIU7E(h z!)9$=*~zkee2fJwe;H1h#EABSZX{Oz=r>J*#2A)453Z<&E4jZqqD!KH9F$xkT(0!p_{M( z{tWXd!4|)zFF7|)vem`S*t*B7g;ATvvM!1gw2~_f>=w>Bda~7p2!VZXqU6cJF7K0Y z8oT<1jkX*P3pbJ?5w?H3{UOZ4`D}(wrcoRf8;;m^Z%8H$V+)^G%>Fqo0%xdrB3VUoVh;&LwLoM@?<++`6SAsa^%9EV&E+bPmI83xtK zAYMEU1{?vj41NpaSZn~0hOrYcPFJfk!QPHx>O@ve0?PEOG-f$!|6u=gAUWYNDuUZE zTSN)hZh$*v^s(J&<`Oq3aEX4}`I@>md>6`I`{G4X1Fh)i#GCYf|R4<|&SsBji zi3oEPZPw2>lI882ah9(0FtPA#BcY+`D4ad5;eUeGe$YVg!z|vk&x5yb9`FFLwa5Ro z){`gDNLK7;eFGg}y++6=N5O5rl^^Q!*-jS64+4x9sfJo%BtWBJ`Zg_6t^92n7ttEehY)xt7GfQ!17qG+9+_6-G%p&;d)TeDz*&F|Ts4nG*8cVo1xGbe zz@(N|2iWRDOtUDrw7~y<0bNRpwO`5z=1HywKTg^ItLU*H2O87rHl62Asfw0JDAG7x zZ2lOWZv^mF2sQ}Fy5J6`133I^nmxgq{9#-IC#_If{ppXe6BoEpwQ#{dBnk446b63` zK9&iRxlci8qY442KY}8RTPFIxZRdI1|Gl2%mvFS51^a)82fCUfMF9Wx5EUo~&>TbQ z^RN5CA8H%$r!$b6n>0znC~pMlA1X!QClfo+u$M6?3c&0jqt-EUiZs%i7AAhE;mNNq z;DHW&fjN+d^tPP~d`Lzd%>}Gdnz}!Eq@gY{u=kVTA}9E&hR#%B6@9TU8 zQfIbA(-997Cr;e8+Ibp{?V8|zSCK;z;;Rfp*b^|K8Xm{h+t&K5UI4-SX`$P!U_ zboG$H;yCTz3vVria5vn3up<#gkN*O?AX5Y(Q7 z$vQ*jXe&)!qt{vRKfttIqJ#Q8Ukb0mpD^p@z34jU-HUY?fx(}?%!QYr*?ZN79qumzU_=GuqV2FHZi1^gon?lxJv0y-N|%vWCP zuCwfQ`10gBmE&+q&&E$;!COeO?V!I3Epht#pM$lYg^C69my|+H>xc9agg>a@aPZ%O zeSa3fUbzhy(F_dmsL(pkP#XAJE)3R?rcYuT;}+^Ml7oIH3P(a`*}D+zap`F;0UU*# z>BkV!`Svaa8jp|CEI>`>{ib_1j=hyf2CVbx4SrPmXbfGD!RnIr1E^q8x#AB7mY4Pj zGtD+L*@SZtaCn^=Z_0I)L@)u%Ou$mY|H?Zl47?5&7OL|g-Y$T#Kbd7I)%7{>0izD6 z`{_>Tq4hw)=Cy98(Scn7eH+DTo`b?j_HZZX6Eu-L%Pf7t9-5jQ!I3=+f>mmgD;I{G zF5yDJ#u%gS=>X{yr2puE9T8(7THuLz{!JegdP=70%8=HkUD>o8c()vSv18MIhtro> zrPNCoWm&ikeiM1&MCn7C6!NOIwb^L4FYis^B5|a@L?N7h(lsC55#F z^+-FAb(PP!EpwNA%Q;|krL_-aT zZk0Zvu3TiHx(PAtH4QxE4*#n#o9Y6pb-Q86k|>6citveuQw`%UMHNb(nB3<^QIgI| zd33m8gx5qIE6cU^3wFSV9fyVb%P!hWg`^gGmW$vrE(=Z5tJ)4(Q|vCyaFL7P%VTgJ z+=^@!Mso&j(PM)Pk&8?%QMS$n*U3Y23O$P~2O(_inX37b-=rP0ZZayms>UbIgK#hS z+UU6LL7x&GItyQd>#$&25}DX%4XMlfTUx-mdXbi>u#W`SFCqgmi1{Iv!5$BI>&5_l zIq|^LGOOF`YkL`H860zl`B%3l4nR07V5AROS^^K{EaJG&* ziwa;=|9aQ$QCmq^*n;?$mGkx*{lE`!Xy&LRbM(D6r5Z5wbfDMm5Bh%Kkh4KuD@UBY zK3q*4yIUKYqkiIR`_zEbeg|+ZGx=>@xd4Mn8E>A$CA)~j{eD|%I3QleC{GjqR=Y+F z%^Q5>e;L6ZnLnm6Kc)jljhF6V^Qx?d5H~7Dag|`UeNMlBk6FOc&f;)*Y;#16(zIZC zZK!j@ZJOlhTDUFs+upkMDciR{Ez@iz)yS&|lsfJ^2fi0gb$hDhM@Kj^#l52!b@4kR)=bs5TtU^$~UHPlqrG}ORy5jqLi>m_;$tjHmW zz{y}Kv!t_|#LX*a$UIp&D^ksl(J=aqe8phbxizlAt}0Py3hE#zTrwGj?@7bzICF;J zI0zD5ewCIBTmX4(14q|tPNd8>9Vt#iBo-u^&*kZlq0MAHon#Iz*JrR) zB3p~3Fyje&EP=1I@E|;R^=9o}j<&1k0@HDN_flV#OE@D+V73P^>$w=29xJ1+2Peza z#v_eyY65Cm#B2w<{BRK&^bXc@Q5(Ab#WJ3LiS64XY~;FFFSup(>R;2W3{w zf4el|A3|wd*GHkD;Q~43IB9mG-H16DhU=Ay{bn8_drGZ87 zzt{a(M5` z_+}l{0Ea%I6V}L+ofr3%3BG4Sps1MG&X(4bvJ!zDJ@flZ@0)pStY+g927O@x?O(yzdKbquIYATkPolg^O$*s<<<1FSP$6|5yaoZahAM5HT|s{$PL1swBk zKEJV@u;%nT0Iws=5yo_U{KoK|Yje1h-#m|lTBhs~Z%q;Xr3~dYG81`5!8)(~Db4cb zQ;4>N;r%tBJ4B~f$YIYV8yI(rVIeD9xlxC&;6rlx}IL*-mg9w?}4AQEi{dr;i;YyIZ z8v{flUCOyU9qjjW)Okm~TIn};eW6h33M{Z(EEM(BO`NmwG z4rrI8#8Iwf4V|t|^Oi5b7ENFSfqVtomCj{k3r2F8{6)~-e02}o^5y87#2D;_>D zb-gOMOv7q{4K&j!T;M(2ZIk26f(D$h(t^<)U}|k*xKylNOiTX%R6b>q;iiN0yuh5w zNfbZhmajbc1`}53f$xm!A;DZ=Hy=hoa04bR;2sP5jp2_Q%{{IIhyG!C)2Y(1bp5={ zl5nPZI7Y}HqY`!o`sR!7uxkS_;6jaLE5qzEuta|rlB=F{-xl7|**oath^G{~a!_b{ zy_a7_toeBUBxJn+dlwzG4;U=jpN72ZfDikrRnjx+=zI5}ZBnp%n^tMkfgL&(ewTUJ zTzi-iuTm}>_s%T@kpSU(O@gbNrbDV!WKp5K8rI8^)Z|!1N+ptWANf0fwekRi|Vy zYu&i8*_o`oNxZGm2GguER2}Z%&n zGI?G$51wu_l8-310UL$-xCzQPfm$v%H(zpo$IB+yPtI4lD4mte2W(-}P5VK= zJ*&bNxlhSsmv@A8O;qhMtef7I)T$e zq)`~WqRf&;h}_s#xpm6SGILk9rG|_l*y?z-F|6vv$UhR8ZLA+2Zsws!Q9TYK9XRw) zjcN5wt!jBDR#C{70akL!F*D`h;0O174EMq7GG~Fb7&M6Ag_q{Jj3W1WG#J`Bnr;T zDY*!avQ2PN=3J^v1qnB+l<*KnwT#idf_ZjE-`HGI?qHFvZ(tivK~dV-pMXRx*|MH{ zRrNYc!+CCQcBiT#krmIs4;RqzQ&WtLhSr7)mWd<{Rn!VED(!NoG24tTFpJT?PB0D# z3Azv0(azI#Q_e6DTo+3s#>4?3=DE>+vI^znGsRN69m6CcpSA_Es>NwP=g~89Tz=gv z-~#z5OCombI76+i%>6ao$j`>5Ah~QW&>SShlEiKNI@wMY77*v|!BG87V5;;^B9LUk z8y**4Lz&>Y9wm?1YHo@MvqIQalTq7{aGuG)-(W<{K);`a>zJwvldValI}e<9E-e)2 z!=S^QF>#wstYOZ|>Qb#o4XRaI(0DQ3Ri zVa>>n*!@sA%Z)pd0`KslhwoYrv2C!{Yalq@@vMd1X#LI8@;tw1;Bg($>~p*O)j2E4$eKzDph;XmMWX&ZdU!+v`BT)-eLB~VQ< z;Bzt{-e#3x4?rh?B}zohXd4=q-hXfF8?gyP8kE`BcW}&Qf)SXmU@50*CO69_N!~Gf zAJ1-lkup393YbOn&}?D25&5o$JulrVXRI|`ytXc9S=Qy_Ib~R$TkebbZQze_k*z+M ziK0N&i5N5vy&ZAaW~DrIXB08U^pdv9O);5m@bur^|0uV*UolfMiGyi8&eL8+oxY_X+EdU_V&wR5o|1QV6y>s0RPPf?uE>KQ9` z0q-X*zY8$s93veldw&zN5?}gI_AFmywN2=nF2QzY994hX1Wc*rwNKk5I3EC-7_Y!0qu?La$n)aYnT_NyAdw9Jkj(swqq|mNxWn9+tWSfT@O$6DfHvc^V6X zg;}(slm8e?HQ8X`d!<4pf)l?ZAqpNMON~0Se*0OTNb?#LYf$B+;TAqVnpc)oOSzx4 zE)5Khy9%=y?<=|P+pZeyrjv$ZPLYq{_wOCw;`LmkuAcE#6gA+1P>_ z+%isApw#j*wW|Vo*BUx%lT_8BV7fv1WSOoyWnaS8+J5S7pM+_OiqTFeI)(=8imO0p z?Y9W8^tof=OvdJ7un~qQve6Y2TdAj>(eQHfZ2dMUv8Hi2Cu^W@1-f-@UZ2JZ`T>po zm3og$y1iy$E=~N2$eyE_u#;p?IFPocly}yJW3QF<4F zaMLD2dUubPF^-R*^`Yd0=_VRqxT<*8;hDDJ6-3(t%g?I!8`GrB=@+e2Rb`ERl5ZKl z{|2HhxM_5!E#C6(l{=agfv#5$SP#QRl+UnYEhXfk276wp%K7NJ??s6KN(}9V^lsLp)LjpwH@jmYx6=-G@LbOUahS%4;vWG7ohQRLEi2>oDxK%X(D^)0)N#N9)WuP& zIU@ndLn5ul=Ji~6-RcY5a|Ni!#qoyen*FsSDWt$GPzmikj@CUvpJE<8MpB0e=YmJ6 zng=-}lCK4+AGzfV)ASEB0k+ypbK%~|lrCe?rQQ(&*C|XJDQIiALMG?zw_MNE6WtlJ)7zIkva5OXPqC)qQOf6PT%##k_h}9`E&8P{<=elx z_dWP0TjmCLS*qHzsXyBXzuGs}pX|?moHcJ9%labbiHPV{Lgqzl1MEbAyMy7KF$UCR zAu~9|EPh40LQ7#7YG3mub)fgXM*d*U`+8V{B5V5rj0h9xwJL zqK+|NhPkBz7}EHf#*go+NJ@3&F0wG+aZnb0#nX#a4T^n&rAH_DpljC^$%QgqeJez0;wp1s?MnT2nN{_u4Xn)Yaeq1L%uOVg?^&RokUSpxS%GW zntNNBQTDh3hQf!?K_nT%k;&L~_`#duDtqFq2-j)CJeTH*EU9=d0-9O%1j!Ay_&GSA zZeZhn4V81ar}-l{f+xc?r3c1wTF!GDoluTqW27kg3DZhG;c({ZLJqZZ+VsA~ACH@u zafh#pF%Vk7+bDj@x~~rra)nGJ?Ji+4e_{51u5SoTsnY%|7vt`uMU!qg$DN=BMC_4q zXGP||#?jasWoPjMDoiDqT8enJ&9X=&^Bhg}N<0iexc@{ySu^7`Fq+yaz|BdNQ9Wjk zK5*lW%Ql6OVPxxGpI{V{l1Tvl8YYEzSvN$k#q23Y#mN!gVY%m26qImO5z`|Qu-8cA zW7_4GXe`2~uI+({&YMpgP>bJT;^(^dtD@5Re5MgsW$3C%<{|wC0{J!~#!FqmZ&uG3 zQ;+qgt1dolBs3TWcX+mE(7cm!DzuVMl&4#T0(D0JBI2@ymcPb@-COlBq|s{4YDvq* z=1Q8(mNI6 zXh~ws&0y^bHMCF(c>fJHFKUlJ&p_M7eQYWU9WgwLu~E-;9Tc1cMfJc@AR1svgys*J zH+jx7j}dH&c3TNn)|`>&of->I()4SZ6?iY?ea$BQlQD-lVhPE5JP+EkAu zd&SFws@cp|lgk+z2JnkBd6T4yn>sxnBcS{a&(HJ)6ySwEB^RikMDbMRj$kvAMd9K) zyqL;R9Lq{Mk$7aKo`VT4oE2ivIN!2?8K(r)$~<-gd3J}Te+&~w1!O3gF&^C~kRs!( z&fw)<_;7LNekZ{vELxFiOcc{5bUqO}k{&G5sqF+B4o6$sA)@{RLvAsH&Lz&PB7Qka)(rG=d8UQ`p0a5VlPVl)*aIq`*nIqRL#gEw?+;G*x8@=y6u&#LXc2 z0^O#{iF)s$nDg#9NyuK(mRpy*adkt^UsQMHMpOix#-&fi36qF%AuC1EZKPL7Vt|ZJ zV!2ah;cRq@QLfjVMAuETGj|xl){s>+23MlUA|rbWVeey+CKz*}-9zJ+H552=q-+2v zh_^%(6xcR)VT3Tl*~WvffJw7ea9_rvE2a?+|AJFHWv>}8ul=1bUeUiB`@9i`!K`uk zZKKIt_0Bq2-Lf@zDRaKYbW27vL=@Pkc;F^8w1>?&5L;LrLYttB`*OM=cPhxxIzu3Y z^@tk@xwhz`^BY$hZxvxbj#2Wo3(1Wg&tBnT7iET5w_;t82U^CCf-=r~KSbJ#GV|Gn z661`Cbl2w_cRUj2?LRRonfm`2^hitCsR`$mqK*JVju2}P*x#YN8CwbgI}UWY3RaW4 z@r~aAljY``cb7y%4xU9}9DTQb-}yF|$6<9db`-efc- zMg7H!6UH!s(dF#MF%hcBmilH01@HJ%Nj$Bb#~_~k6@43d*)h<^!-Z`fr=8zT*F_d;T-Jlh>J~nNNG_cM5|)PoOtj0Zgsxg!C@0B zRq)2hl>~zbba*_zLSvmc9kM>8lqTChBx$?;)#i|SZIxO~=0qiF!b#sMx6$xW6&F=U z@*DOGAG#)&gOtwNRej@VnF?IT;`3y9@!Xk@#S>!%HHKVpYEgT~FgB<;HBu*-hkBWa zD`#PLn*>lmcOeTDS?e{U4I}g#^D2w}soz(1eHzn+=IwFWcHQy>TDqOc`VJ_K;_Vg5B?uTZFbjykgz*#cg>FZ)J$0AiYK{H8f`#5>y$ds( z-?hDzHir}%3U~sn%YuFA6{&c=ek(nji9CFWnTaGk7NH|41F6{FXjHe=#?w;>fj&Qp zsVZ;EM;df$m=ziOnPoNS@38twnaB(x*Ue~maF8O__JEIY$>}}uI!qRv^QjqvJrdVB z3cqKD{U5_M=G06)bfxw(1Q;7WeS8Ev)hIe|KzXt6ErJYstmMA~T>$KEer@g}P$n?l zh%pMgNGl5M!@UXr@Xw}haR}9iJh#X-PS-YFjLY$&T7lZ*`&(zl_9qp37QtEgB~zhe zq3#Y;$N`6RmF25}L-v!t?>I{m2ONoyX>s?-cKM`mha9fEK(hiLx%%y}(rWxMhsWG# z#^b6GCmf=E(<{qN$O9%!O!z7LK}#{FiXHa&Rn3=p{XA#+r;2!JwRhj&Z`sELx*dZp z1~Q>8=Vi?^460A`>XwI0I!wCUmT4S)HLpXqtYV_PN|S6E$Box-6?L95kws#`F-}FkJwcFMto z^iAHP2O$wGx0oP*Ua7oq7VbXhB;y$1 zgAACET<4k-`m{b~T8}Zz*t}e+7QV+|PnpKn+HkG)Hc{1je?aGTn9DrZbPd{k!7+@+ zi9{;>e5sN^m_@gszC^KUt#Sj*p zsx)mu9otZjOsR%RELbz^pk@@?Y;-tST1;d6q_?D~>n~_Kfp^{4EW<#|NRgUXn8yB^ z{s9N)N_sWi!T`==@y&94aO8dT4t5G`r_@RRNj~Kuo$5940|R4t;e549Ic8}4%Gz7T zS~9$52@8-d&0cec1>^MB)ofwGI;7U24P$#}sb&$|oY(^5YZkHKI=sC#$5_zL%2W;W zSo=KPhGUsd*)0!Q&>nnr3tcK#ISy-s%HBnq$l_kPZc6Z>Z#o#OCUEGhE}Z47*7efi z1IuS`vwshMiL^{~4sH9mbpz@6q2=pd;j0EQOJ{6mijF?8%|9P6XRN&q&OHgCLyz`s zE6C*i>Cj^f)Qs!ZaVNIkx|5wLnNtgyPERKxV_7(F-!a({(saZkZ9DPgfQNJCiU|Ml zK)bh?Fdz@Nn+*m7vT(QfB_jY)SVWKEtk7s!%S8}A=F#15S;7rG8IQySgAG_hHbuk` zt1Pz~o89AWW0sGE0*}wx z>rjsbzY;}JRZYk=SCG4sZ5T;c_Bn_tB7^G+E3)Fxmq+=slXiDGf5y<`R*ZuhSvbf0 z8pCpjgG`=d=S%eaX&xHwRY@&veVr6SX+atinsgSB5pxhxE5}=Rnt_e zE+S0&x^-#_*XdeU3eD2}?ZyS@TzUaPWWbfBd!Iu6M7C#DHW>9{SX;lXUcI^(>ohC4 z&(yIOmMNGl`JJyq-rA==ll9XymXES{sB2q9xmrI(NzcWvWUG&Rbqi^|?9uLDSqO5( zv@pwZ+C;beb`B4o$E=KsUN%*O-WGe`30{>>sDhw0`O5`1HMqo-SDqSgP2(Y5k=4gS zd6$*JOpcD_DtmMs|#uX;p*1E(N)z=(a>^?4QDw=bcm| z_-7b&dTA`bd-7lKtVECAh%UU8T}xVUXnQQnq(7%)yJ@N(lJgQtRW)%h^Sj1WwJFGH z?WlU&78@(E0JwHjgr;ZC)B)Rq^c-^5Z{D1zG763!0oNs73|pS#sEV3ZMi2&W9ca{B z^cjBFz{=98 zHM+BLILV-GCG26wo^*w|Bj5S$8`Q_rc{wxvhaQp9*T8%aDTaF0<@G7-VUa_}^zG}s$oiDP_Jz{~ls^C47wOu-cvA6~QslaEW{ow49)i%oPE@K% z|9LsDGs$l^7}}$C_&3ZpG4!X)3@cC@r-r+}(m6VRu)+>Ana;}n*uyHJN~PaxhkmW} z7|ePbZe+I3XQ5lw){^+hAD<l{UtDs+ipby_=6?rpYe6R zOe;C!VQ7!UhH}+7Z$aAr)v;^02ie|UHBS?n!qV1nD9hCYMR!%;nC-DEI ztKdPzhR1;?aIz}_6{*53KxZLshK$h*zbc;Q>c$LH=tW|Mi#cM3H@x9@0#2YV-WY7( zacHXMcTl7qvb+^Z!JsguG47(B=VMFZSQUVAV6~t3?aNYO4dF*MIu>PgzrMdv zWhOAIY@V(hALp#nmY;)rzQG_syKb`{D9-4-mJmk$@H$?;C}i$rthtN#B_G4g{%wgh z7)QP(bW=H~nHoS04LkGrZzdI_+aV(~pjvcsd6=jrf5F)D%A z#gs|LSS5?|)kK=i)%onJK}J0+?;6Sj=)X&9w6Ro9eh3v~R6ERTy*=r;RKhnF!CFRX z(v3IPruz*78!2O07?AQTYr12V*jPPgijVX;4%gbAqvPV=@nNBKNUqwkHX6oQeDc`d zFBYZdH4C zNY)PesYh1i1hDu#IT*g7?y1e9P^%;>-)0gEV4v-iIaOIl;^(@^u;RS_@*T#V+=T_G zl0Lb*wFB#|=K)4msfE}unWe5_vur|1#($s_@=eW|-)DQMR))8n$p;ouW~qOaweI*+H}EX@Ro(XYXdN@h@=m3 zFJ-qe7;kY~#zaE6zk`@b64KBaS*OcccZYZx@zPFbfpI8gH7F}YfF@qf%2xMkPE}P2 zTXpnJucpD@wKKv#Jr7YFuA{KO!r7*QK1llk(2>lpT^Psd)ang3kD)g7Hkwxt0nu5I zepV24%sWhE{?=*wq^euAeJ|Te+wRRUj`b)FQtFX3PG`h#-T5-R;WwY|;4{BTr+Fc= z{#W9+WuEJT!g=M{hJM-5Pbx2;ohi}9vs(Lv?h%hqRqu}42ewy@d9-15-B&mq&e{NQ zJvvEr*$^b62O)wLy+rUwbXE(ZMYp=JS`ealt9OgA(R*jr-9>a!qFbHSKIfd9bMc*- z=b86v-m7_LZsz^HW&#TP&Sd4$l-(g8r!t2*G^JC}pGk_>2U5S}fif^f=2PKssC(4V&D7^TNH^q|ZBr|Sd z-)}jxtNW4Ddi76Fn?S@Q#!<*3!(&FK4;0@1?0g@0H-(tS+e7hY=k^ejCHiU{t}nVS zOmuOCn{4siCh7fClt!WuF5?|upRDfMU0xEcK@T%KOebk-gWaOZPLwUG4TnZxM5MNH z%)f&4N^E8@;l2%LgGMio3)VIov)h29kjlvV%k`;XgrItuuh?3MO@p}(!OepUAD;J| zQ)G$V>J?ky;|5>Ha#}%sbl{6YO9Ua7Pq9->YdswD2RRu{z&W6ZCA9+-D8UWgPIiVo=Mywn43Ctl^i!6>KAWl zgjnIJqpxD!tinH15w?fqSW9Fh9l396J~n)^HcPkVy*N874#5r25N=5JFp{*CA9~ z8?I%-Wo%D6SISWnYR{wfK=UFY>H##*jz0|PR<;%R)Gp8PX))$t3!_7EMy{4lZhd(rx-4|s} z9}$HI`(pp3#8H&T?FFZITJQUs-X3OJt^(t@ z7KauY_-ikXcwtjdv9z+Jnr91gd87C&xC_FntrZx(RUy> z44p=X@K?4v$*6zKAa(kuv|6{gfmCy_^-+(e+Ny~~_SV?XSWA7vnG_;7k4u%l(w4oR znGMtFDBjE{7#Z^=EV-~1bud^ix5-%hTF-nlvE_)#Y6xHA=yid}Y_j6K_-N4`0c5*rR*LfFnFx+5+O$!fBrjMjz8a5TA)?8IvE~Y+u){`N9PCV}hTeCN2 z0I53KKMJMkf4&#a4H|27f{uJq3VcL*DoO37Q_?F&3!Aj%H4TT{@hH<0qsqrO3>CHP zEr)pDn_wZZJ>BGVx^2eFaii}5oP^?+9=18zBt=yH`NbNc5drE^psj2%ZL}qR2N6jL zqhsCbQ_b^@KsBWIZGqnYGJoB8T-Bo-tL5JUv(ww-gDRqeG80WU8 z^k8OR-ORklQ5U8ZRd#1sYi4DlBNqQ^(}XJX)6N(K*xZ*px&CMAxst!Uon~axxk_3> zX#A(qH?kslki{u^!hY=B>~z&91I=`MeR#6Zq7+H@?}~IU@$YA1{%J)VHmUw+_2`tK zG4WrsRHa!nk{Ii)+YW6L2P*R%qXj(m$?BID<}~40;$Qqe(q)+M5LMa2Bz3k&tDgCl-H6EvqXfFyPQ}XP8q>3-+J+ccbxA4=1+{&v45;Wl zSPy+d{EXKa5*Lpu)AkMacF!boVkcYgydt2gXJqL&T5>7tqVRd1SQ3HQykY>T8+RFG z;swctS&qGOU2j&7hI}|vUpYH}CHovP{K5G$=!1jSje@i*R5Er|E7AkLGm^c3Y;wab zyV^-T`#Y$x)+BwJZp43vz3tR4ZG#XPQ2D+LL_l1}6S>BVE{nRJ_lu5qS`(5LWjSKE zYkv~q6VHvs3=Y(2y}rFGrYgnwW+Vr&WC zZ5qAu^*gUH$2X#p;PfysB!lc80QN^G6sP(6=SB6(V3HjEr!GAsbGHHKbhW*PdIX+Q z1$+;dI3f@8GyvmJ)Nh*!sx!x8mMJQRgns><3Vs7^mB-~eM?fpZ{V6%1HNXAiy=K6~ z&jC^I%NEF=jx((g9_mua#*Yt?=P^F(uc;TRypSn zt5PaF?lBo`GxTI7>bA{;175o5C?3wIXVNn%F2jkTD+QVc*??02VOP7rlv%CM1)=RY zWM zM#S)iUjITop?_a2R$7Fy^O2~V!RxWH|4kkAasW;~rLDR7m3dDfDXF=8*qSQOd15q!SW)8iO_q99s*ExiAg3htm)e2?9i(r~_fmwf&le3a?Tc+BpB|Q<(cd2L zW!zwkzq#)N%`3qOruCk7P6%tw1Oya2;uX=if?UCv`H)hKC~CPVGZF6nV3KjZISp$? zYwKZlk)^boMIq}N?$JISJ^It6E>X`E*>#@UrKlv||NLIOS$>+0ml9i3q-ATwp8A?v zvV9QAc0rM<1ob+@3KL^{_=r09bD3nS-5w^f&NMo!QlIck={TaYRS0D;O_OLD%T+Cq0{?9F z5Od0M^D`<#%3y%DKDzGYg9dqU7R%n39N^+}Cyh_%t09g=ONEjE-X0k^b=3zrMesDL zy>N57AZ{8dwN|w7H#GF@5xKwDWp#R&RL$mI?2`+>wUT7As&Zisl3gwQxtxhAB9YK` zHef>hY~xx}XWLCVtM;Q-)yfP4Kb{Ni0&p)eenTyx3fF1v9^chc?FBxBKM?WK6K3Q< zJzL}asu1}ue=cXdJds4XsK~oW!0!%~e5{?o~^r(41W{M+@r?V`d^ zf5HTG*Bw;wEFi$Ox)&RvU1tH}N8{Rq!sos%&%nK@&IFAD^#+QIO`f(ZAzypL+;t z57i7wf~Wh5M8mXwQ?adqkAPp+@Dp58|30~hNMHdVry`r=f`k?&)Ou(gBQBq+K-A=*U*lQiAXrwv>&W^BV6)?s4tzes+YDa zO|rc(&SUg1AZF9^ZxaT6!!Un5wEWR1i7V5sR*A&#s|c6&H=$lU*Pp;VElcd;E$~{o zkww;-y}@9`2tB^d+Gp0Kqi0`g9W-e_A@n&Z0--+DH#=kl1f4vQVmMy?6^8SKrQHxWN3u&@#P9Q6{WE9XjrL}=JmB;HDsbK9( ziSQ@Sw_5(R`yt@xK=$j&a(Hthkj1n&z~8oRj{W{1L*BdZh=&EzWW>y^BoTM>-KM9c zRPehVa5B9ObO3XKrWl*$7$|lkftL?K2t5=UE+!B5ZLNqCO6@iv*^6mh!1}M5xTUyR z7K7(9YNuWGHbbSBTiyWZGmHqQ_%dd)kj07bR==B%2=wn2g|T23pWLz~OFITUancwc zm+fpT2lJWI6G+hI$^Vx6Byj6l#yVu;bkSDa0IX<@VtTDqQ5xB_TWwj?n$iol&^CRG zmXlF8$QTo4GmgRceCt_~*nB#*U*nI7J3g)U9i^wtZ>xo=oDgeDUz~~h^!Kz|SE^B+ zGeE1YsjJkqdIF~F#ZPUk_f}w|Li#|rv*u~aD_7YK3`PXj46t)BV^Keq+RZ+Xh*O0_ z&FT%~O9j3amb=PE&>0b7ftd^jcmY0RU{$0~S7GDzDLFJ1odUgs~A|(x; zZl^5o@z(eSQ1NC351wnInM0-Tv%bw| zd1BR-+Cp5vCMNcG?+Zf8#)Sy)zBYk#Nuxr=ca=Jd&<@CV|NeiWAuDuAzivbnP|EJG zH7&wnD{4mowS1X7SmR@kqR|s`S3{|=rFOTa^!Wy%joEpZ3jDyVOda&YJ%KhZ+)Gt1 z`8-fRmrYjz8#>v8yZhLv)cn4T6!fmLg4D*2Z70A$z1v|ZGIQmr@5P^rr-pK;l$jHs zqY1?+W%R0R2Pmn&TTY+X4{Jjs)uz{bO-nFBQKzhkapD!cA&hQ3AI zZ>rBdmF0Z{QcE#>rmRDPw2<1P05AVI_4H9YRxvqv%++145OMswx`aF2q_<65SQNS= z;OXzHOLjYlWzHCY_TelWz4Bd;`W<@x`H$Putbi&~s;4x5_L62X;pS=Qe!+j=SrKtZ z)EaMOi;JjV$6yb1Ijk_pcjQu0Da)jz5|_hw7f>12gtx28bZ--NTyrOMNX6xxDUMW& zis~QTGBcdpLn`CPIPu8R^0H@ezC)Q%{-p2fSaOD$Q!kAmkZz)G2|;$a2y7!(ZP-OW zq}E+zgvY-`Ke^J$xm{HM9=TY5u{d>soD^hc8?~l@yNz#}EyjD#O3wuzOW_8XuD1Uc zSrl!4DWmrOahUX}YLtL<2LkN_IlV$zP+}othqn@L*9k)5bHx}5qn30&vq-+Sl)(7G zP!$8x1U+FWh3(Hzau+;e)bWS%f|yIPppNL!Ts;aaEfK^>glYI9TSL ztV`6kX^pSC#>&$7YqZm3`q|0BuXwe)Ui?aNi{v2e&PlhH@pcuGF<%*NTFeZxs=4C^ z9G5{)O&9A&jYgKnw%P?(TMdO{=hl`|_MM!z`~)z8rpP*R$0_^O4S|@bC{Z37yktMv;@Hq!v~&Q5ME$0D`LhU( zQpoO7@5@`3e^hbtXmI|+Qhd5+Dd@k{k?c?4;E+t?{F|k?mnr@|eg*w2{12pp-`v&m yv#qn0gSm~C#Bry3u6aKe)@sBDY(Z4p~-Os%H*h7PRzy2S9{)K=5 diff --git a/disabled yamls/DLCPlayer.yaml b/disabled yamls/DLCPlayer.yaml deleted file mode 100644 index 39cf505dbe1f..000000000000 --- a/disabled yamls/DLCPlayer.yaml +++ /dev/null @@ -1,14 +0,0 @@ -DLCQuest: - progression_balancing: random - accessibility: random - double_jump_glitch: random - coinsanity: random - coinbundlequantity: random - time_is_money: random - ending_choice: random - campaign: random - item_shuffle: random - death_link: random -description: 'Generated by https://archipelago.gg/ for DLCQuest' -game: DLCQuest -name: DLCPlayer diff --git a/disabled yamls/DLCTester.yaml b/disabled yamls/DLCTester.yaml deleted file mode 100644 index ab846608fb78..000000000000 --- a/disabled yamls/DLCTester.yaml +++ /dev/null @@ -1,13 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: items - double_jump_glitch: simple - time_is_money: option_I_want_speed - coinsanity: coin - coinbundlequantity: 20 - ending_choice: true - campaign: both - item_shuffle: shuffled -description: 'Generated by https://archipelago.gg/' -game: DLCquest -name: KaitoKid \ No newline at end of file diff --git a/disabled yamls/DragorrodSV.yaml b/disabled yamls/DragorrodSV.yaml deleted file mode 100644 index b65e5cceec08..000000000000 --- a/disabled yamls/DragorrodSV.yaml +++ /dev/null @@ -1,528 +0,0 @@ - -name: DragorrodSV - -game: Stardew Valley -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -Stardew Valley: - progression_balancing: 10 - accessibility: items - - - plando_items: - - items: - Beach Bridge: 1 - Amaranth Seeds: 1 - Corn Seeds: 1 - Desert Obelisk: 1 - Fishing Level: 7 - Galaxy Dagger: 1 - Galaxy Hammer: 1 - Galaxy Sword: 1 - Greenhouse: 1 - Haley <3: 3 - Harvey <3: 3 - Elliott <3: 3 - Emily <3: 3 - Alex <3: 3 - Island Farmhouse: 1 - Island North Turtle: 1 - Island West Turtle: 1 - Kale Seeds: 1 - Luck Level: 5 - Maru <3: 3 - Melon Seeds: 1 - Minecarts Repair: 1 - Movement Speed Bonus: 5 - Parrot Express: 1 - Penny <3: 3 - Progressive Barn: 3 - Progressive Coop: 3 - Progressive Fishing Rod: 2 - Progressive House: 3 - Red Cabbage Seeds: 1 - Return Scepter: 1 - Rusty Key: 1 - Sebastian <3: 3 - Seed Maker: 1 - Shane <3: 3 - Silo: 1 - Skull Key: 1 - Stardrop: 2 - Starfruit Seeds: 1 - Strawberry Seeds: 1 - Sunflower Seeds: 1 - The Queen of Sauce: 1 - Tomato Seeds: 1 - Tractor Garage: 1 - locations: - - 25,000g Bundle - - Catch A Squid - - Catch a Lingcod - - A Curious Substance - - Aquatic Overpopulation - - Biome Balance - - Cellar Blueprint - - Collect All Rarecrows - - Complete Fish Tank - - Crop Order - - Danger In The Deep - - Deluxe Barn Blueprint - - Deluxe Coop Blueprint - - Fair Stardrop - - "Fishsanity: Blobfish" - - "Fishsanity: Blue Discus" - - "Fishsanity: Glacierfish" - - "Fishsanity: Ice Pip" - - "Fishsanity: Lava Eel" - - "Fishsanity: Legend" - - "Fishsanity: Midnight Squid" - - "Fishsanity: Midnight Carp" - - "Fishsanity: Scorpion Carp" - - "Fishsanity: Spook Fish" - - "Fishsanity: Stingray" - - "Fishsanity: Void Salmon" - - Floor 120 Elevator - - Four Precious Stones - - Fragments of the past - - "Friendsanity: Abigail 14 <3" - - "Friendsanity: Alex 14 <3" - - "Friendsanity: Elliott 14 <3" - - "Friendsanity: Emily 14 <3" - - "Friendsanity: Haley 14 <3" - - "Friendsanity: Harvey 14 <3" - - "Friendsanity: Leah 14 <3" - - "Friendsanity: Maru 14 <3" - - "Friendsanity: Penny 14 <3" - - "Friendsanity: Sam 14 <3" - - "Friendsanity: Sebastian 14 <3" - - "Friendsanity: Shane 14 <3" - - Gifts for George - - Galaxy Sword Shrine - - Grange Display - - Harvest Banana - - Harvest Cactus Fruit - - Have Another Baby - - "Help Wanted: Fishing 5" - - "Help Wanted: Gathering 5" - - "Help Wanted: Item Delivery 20" - - "Help Wanted: Slay Monsters 5" - - Iridium Axe Upgrade - - Iridium Hoe Upgrade - - Iridium Pickaxe Upgrade - - Iridium Trash Can Upgrade - - Iridium Watering Can Upgrade - - Island Farmhouse - - Island Ingredients - - Island Mailbox - - Island Resort - - Island Trader - - Island West Turtle - - Juicy Bugs Wanted! - - Kids Room Blueprint - - Kitchen Blueprint - - Level 10 Binning - - Level 10 Cooking - - Level 10 Combat - - Level 10 Luck - - Level 10 Mining - - Level 10 Foraging - - Level 7 Archaeology - - Level 7 Combat - - Level 7 Cooking - - Level 7 Farming - - Level 7 Fishing - - Level 7 Foraging - - Level 7 Mining - - Level 7 Socializing - - Mayor's Need - - "Museumsanity: Golden Relic" - - "Museumsanity: Rare Disc" - - Night Fishing Bundle - - Pierre's Prime Produce - - Parrot Express - - Purchase Iridium Rod - - Qi's Challenge - - Qi's Crop - - Qi's Cuisine - - Qi's Kindness - - Qi's Prismatic Grange - - Quality Crops Bundle - - Repair Boat Anchor - - Repair Boat Hull - - Repair Ticket Machine - - Robin's Project - - Robin's Resource Rush - - Rock Rejuvenation - - Strange Note - - The Mines Floor 110 Treasure - - The Mysterious Qi - - The Strong Stuff - - Tractor Garage Blueprint - - Tropical Fish - - Volcano Bridge - - Volcano Caldera Treasure - - Volcano Exit Shortcut - - "Wanted: Lobster" - from_pool: true - world: NevaSV - force: true - percentage: 100 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - Farm Computer: 1 - Movement Speed Bonus: 2 - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - goal: - community_center: 50 - grandpa_evaluation: 0 - bottom_of_the_mines: 0 - cryptic_note: 0 - master_angler: 0 - complete_collection: 0 - full_house: 0 - greatest_walnut_hunter: 0 - perfection: 0 - - starting_money: 800 - - profit_margin: 125 - - bundle_randomization: - vanilla: 0 - thematic: 0 - shuffled: 50 - - bundle_price: - # How many items are needed for the community center bundles? - # Very Cheap: Every bundle will require 2 items fewer than usual - # Cheap: Every bundle will require 1 item fewer than usual - # Normal: Every bundle will require the vanilla number of items - # Expensive: Every bundle will require 1 extra item when applicable - very_cheap: 0 - cheap: 0 - normal: 0 - expensive: 50 - - entrance_randomization: - # Should area entrances be randomized? - # Disabled: No entrance randomization is done - # Pelican Town: Only buildings in the main town area are randomized among each other - # Non Progression: Only buildings that are always available are randomized with each other - # Buildings: All Entrances that Allow you to enter a building using a door are randomized with each other - # Chaos: Same as above, but the entrances get reshuffled every single day! - disabled: 0 - pelican_town: 0 - non_progression: 0 - buildings: 50 - chaos: 0 - - season_randomization: - # Should seasons be randomized? - # All settings allow you to choose which season you want to play next (from those unlocked) at the end of a season. - # Disabled: You will start in Spring with all seasons unlocked. - # Randomized: The seasons will be unlocked randomly as Archipelago items. - # Randomized Not Winter: The seasons are randomized, but you're guaranteed not to start with winter. - # Progressive: You will start in Spring and unlock the seasons in their original order. - disabled: 0 - randomized: 50 - randomized_not_winter: 0 - progressive: 0 - - cropsanity: - # Formerly named "Seed Shuffle" - # Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. - # Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops - # Shuffled: Seeds are unlocked as archipelago item, for each seed there is a location check for growing and harvesting that crop - disabled: 0 - shuffled: 50 - - backpack_progression: - # How is the backpack progression handled? - # Vanilla: You can buy them at Pierre's General Store. - # Progressive: You will randomly find Progressive Backpack upgrades. - # Early Progressive: You can expect your first Backpack in sphere 1. - vanilla: 0 - progressive: 0 - early_progressive: 50 - - tool_progression: - # How is the tool progression handled? - # Vanilla: Clint will upgrade your tools with ore. - # Progressive: You will randomly find Progressive Tool upgrades. - vanilla: 0 - progressive: 50 - - skill_progression: - # How is the skill progression handled? - # Vanilla: You will level up and get the normal reward at each level. - # Progressive: The xp will be earned internally, locations will be sent when you earn a level. Your real - # levels will be scattered around the multiworld. - vanilla: 0 - progressive: 50 - - building_progression: - # How is the building progression handled? - # Vanilla: You will buy each building normally. - # Progressive: You will receive the buildings and will be able to build the first one of each type for free, - # once it is received. If you want more of the same building, it will cost the vanilla price. - # Progressive early shipping bin: You can expect your shipping bin in sphere 1. - vanilla: 0 - progressive: 0 - progressive_early_shipping_bin: 50 - - festival_locations: - # Locations for attending and participating in festivals - # With Disabled, you do not need to attend festivals - # With Easy, there are checks for participating in festivals - # With Hard, the festival checks are only granted when the player performs well in the festival - disabled: 0 - easy: 50 - hard: 0 - - elevator_progression: - # How is Elevator progression handled? - # Vanilla: You will unlock new elevator floors for yourself. - # Progressive: You will randomly find Progressive Mine Elevators to go deeper. Locations are sent for reaching - # every elevator level. - # Progressive from previous floor: Same as progressive, but you must reach elevator floors on your own, - # you cannot use the elevator to check elevator locations - vanilla: 0 - progressive: 0 - progressive_from_previous_floor: 50 - - arcade_machine_locations: - # How are the Arcade Machines handled? - # Disabled: The arcade machines are not included in the Archipelago shuffling. - # Victories: Each Arcade Machine will contain one check on victory - # Victories Easy: The arcade machines are both made considerably easier to be more accessible for the average - # player. - # Full Shuffling: The arcade machines will contain multiple checks each, and different buffs that make the game - # easier are in the item pool. Junimo Kart has one check at the end of each level. - # Journey of the Prairie King has one check after each boss, plus one check for each vendor equipment. - disabled: 50 - victories: 0 - victories_easy: 0 - full_shuffling: 0 - - special_order_locations: - # How are the Special Orders handled? - # Disabled: The special orders are not included in the Archipelago shuffling. - # Board Only: The Special Orders on the board in town are location checks - # Board and Qi: The Special Orders from Qi's walnut room are checks, as well as the board in town - disabled: 0 - board_only: 0 - board_qi: 50 - - help_wanted_locations: 40 - - fishsanity: - # Locations for catching fish? - # None: There are no locations for catching fish - # Legendaries: Each of the 5 legendary fish are checks - # Special: A curated selection of strong fish are checks - # Randomized: A random selection of fish are checks - # All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal - # Exclude Legendaries: Every fish except legendaries - # Exclude Hard Fish: Every fish under difficulty 80 - # Only Easy Fish: Every fish under difficulty 50 - none: 0 - legendaries: 0 - special: 0 - randomized: 0 - all: 50 - exclude_legendaries: 0 - exclude_hard_fish: 0 - only_easy_fish: 0 - - museumsanity: - # Locations for museum donations? - # None: There are no locations for donating artifacts and minerals to the museum - # Milestones: The donation milestones from the vanilla game are checks - # Randomized: A random selection of minerals and artifacts are checks - # All: Every single donation will be a check - none: 0 - milestones: 0 - randomized: 0 - all: 50 - - friendsanity: - # Locations for friendships? - # None: There are no checks for befriending villagers - # Bachelors: Each heart of a bachelor is a check - # Starting NPCs: Each heart for npcs that are immediately available is a check - # All: Every heart with every NPC is a check, including Leo, Kent, Sandy, etc - # All With Marriage: Marriage candidates must also be dated, married, and befriended up to 14 hearts. - none: 0 - bachelors: 0 - starting_npcs: 0 - all: 0 - all_with_marriage: 50 - - friendsanity_heart_size: - # If using friendsanity, how many hearts are received per item, and how many hearts must be earned to send a check - # A higher value will lead to fewer heart items in the item pool, reducing bloat - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 1 - # Maximum value is 8 - 3: 50 - random: 0 - random-low: 0 - random-high: 0 - - movement_buff_number: - # Number of movement speed buffs to the player that exist as items in the pool. - # Each movement speed buff is a +25% multiplier that stacks additively - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 12 - 10: 50 - random: 0 - random-low: 0 - random-high: 0 - - luck_buff_number: - # Number of luck buffs to the player that exist as items in the pool. - # Each luck buff is a bonus to daily luck of 0.025 - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 12 - 10: 50 - random: 0 - random-low: 0 - random-high: 0 - - exclude_ginger_island: - # Exclude Ginger Island? - # This option will forcefully exclude everything related to Ginger Island from the slot. - # If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway - false: 50 - true: 0 - - trap_items: - # When rolling filler items, including resource packs, the game can also roll trap items. - # This setting is for choosing if traps will be in the item pool, and if so, how punishing they will be. - no_traps: 0 - easy: 0 - medium: 0 - hard: 0 - hell: 50 - nightmare: 0 - - multiple_day_sleep_enabled: - # Enable the ability to sleep automatically for multiple days straight? - false: 0 - true: 50 - - multiple_day_sleep_cost: - # How much gold it will cost to use MultiSleep. You will have to pay that amount for each day skipped. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 200 - random: 0 - random-low: 0 - random-high: 0 - free: 50 # equivalent to 0 - cheap: 0 # equivalent to 25 - medium: 0 # equivalent to 50 - expensive: 0 # equivalent to 100 - - experience_multiplier: - # How fast you want to earn skill experience. A lower setting mean less experience. - # A higher setting means more experience. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 800 - random: 0 - random-low: 0 - random-high: 0 - half: 0 # equivalent to 50 - vanilla: 0 # equivalent to 100 - double: 0 # equivalent to 200 - triple: 50 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - friendship_multiplier: - # How fast you want to earn friendship points with villagers. - # A lower setting mean less friendship per action. - # A higher setting means more friendship per action. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 800 - random: 0 - random-low: 0 - random-high: 0 - half: 0 # equivalent to 50 - vanilla: 0 # equivalent to 100 - double: 0 # equivalent to 200 - triple: 50 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - debris_multiplier: - # How much debris will spawn on the player's farm? - # Vanilla: debris spawns normally - # Half: debris will spawn at half the normal rate - # Quarter: debris will spawn at one quarter of the normal rate - # None: No debris will spawn on the farm, ever - # Start Clear: debris will spawn at the normal rate, but the farm will be completely clear when starting the game - vanilla: 0 - half: 50 - quarter: 0 - none: 0 - start_clear: 0 - - quick_start: - # Do you want the quick start package? You will get a few items to help early game automation, - # so you can use the multiple day sleep at its maximum. - false: 0 - true: 50 - - gifting: - # Do you want to enable gifting items to and from other Stardew Valley worlds? - false: 0 - true: 50 - - mods: - # List of mods that will be considered for shuffling. - ["Bigger Backpack", "Tractor Mod", "Luck Skill", "Archaeology", "Cooking Skill", "Binning Skill"] - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 50 - true: 0 diff --git a/disabled yamls/GiftReceiver.yaml b/disabled yamls/GiftReceiver.yaml deleted file mode 100644 index 9b63c341a31a..000000000000 --- a/disabled yamls/GiftReceiver.yaml +++ /dev/null @@ -1,41 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: locations - goal: bottom_of_the_mines - starting_money: -1 - profit_margin: 200 - bundle_randomization: vanilla - bundle_price: very_cheap - entrance_randomization: disabled - season_randomization: disabled - cropsanity: disabled - backpack_progression: vanilla - tool_progression: vanilla - skill_progression: vanilla - building_progression: vanilla - festival_locations: disabled - elevator_progression: vanilla - arcade_machine_locations: disabled - special_order_locations: disabled - help_wanted_locations: 0 - fishsanity: none - museumsanity: none - friendsanity: none - friendsanity_heart_size: 4 - movement_buff_number: 4 - luck_buff_number: 4 - exclude_ginger_island: 'true' - trap_items: no_traps - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 800 - friendship_multiplier: 800 - debris_multiplier: none - quick_start: 'true' - gifting: 'true' - death_link: 'false' - start_inventory: - {"Movement Speed Bonus": 4} -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: Receiver diff --git a/disabled yamls/GiftSender.yaml b/disabled yamls/GiftSender.yaml deleted file mode 100644 index c7105919df42..000000000000 --- a/disabled yamls/GiftSender.yaml +++ /dev/null @@ -1,41 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: locations - goal: bottom_of_the_mines - starting_money: -1 - profit_margin: 200 - bundle_randomization: vanilla - bundle_price: very_cheap - entrance_randomization: disabled - season_randomization: disabled - cropsanity: disabled - backpack_progression: vanilla - tool_progression: vanilla - skill_progression: vanilla - building_progression: vanilla - festival_locations: disabled - elevator_progression: vanilla - arcade_machine_locations: disabled - special_order_locations: disabled - help_wanted_locations: 0 - fishsanity: none - museumsanity: none - friendsanity: none - friendsanity_heart_size: 4 - movement_buff_number: 4 - luck_buff_number: 4 - exclude_ginger_island: 'true' - trap_items: no_traps - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 800 - friendship_multiplier: 800 - debris_multiplier: none - quick_start: 'true' - gifting: 'true' - death_link: 'false' - start_inventory: - {"Movement Speed Bonus": 4} -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: Sender diff --git a/disabled yamls/Kat.yaml b/disabled yamls/Kat.yaml deleted file mode 100644 index d9a0301f5c61..000000000000 --- a/disabled yamls/Kat.yaml +++ /dev/null @@ -1,40 +0,0 @@ -Stardew Valley: - progression_balancing: 65 - accessibility: locations - goal: community_center - starting_money: 5000 - profit_margin: 300 - bundle_randomization: shuffled - bundle_price: cheap - entrance_randomization: disabled - season_randomization: progressive - cropsanity: shuffled - backpack_progression: vanilla - tool_progression: progressive - skill_progression: progressive - building_progression: progressive_early_shipping_bin - festival_locations: easy - elevator_progression: progressive_from_previous_floor - arcade_machine_locations: disabled - special_order_locations: board_only - help_wanted_locations: 7 - fishsanity: none - museumsanity: all - friendsanity: none - friendsanity_heart_size: 4 - movement_buff_number: 4 - luck_buff_number: 8 - exclude_ginger_island: 'true' - trap_items: no_traps - multiple_day_sleep_enabled: 'false' - multiple_day_sleep_cost: 0 - experience_multiplier: 200 - friendship_multiplier: 400 - debris_multiplier: vanilla - quick_start: 'true' - gifting: 'false' - mods: [] - death_link: 'false' -description: 'Generated by https://archipelago.gg/ for Stardew Valley' -game: Stardew Valley -name: Kat diff --git a/disabled yamls/NevaSV.yaml b/disabled yamls/NevaSV.yaml deleted file mode 100644 index da096ae8b67b..000000000000 --- a/disabled yamls/NevaSV.yaml +++ /dev/null @@ -1,527 +0,0 @@ - -name: NevaSV - -game: Stardew Valley -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -Stardew Valley: - progression_balancing: 10 - accessibility: items - - plando_items: - - items: - Beach Bridge: 1 - Amaranth Seeds: 1 - Corn Seeds: 1 - Desert Obelisk: 1 - Fishing Level: 7 - Galaxy Dagger: 1 - Galaxy Hammer: 1 - Galaxy Sword: 1 - Greenhouse: 1 - Haley <3: 3 - Harvey <3: 3 - Elliott <3: 3 - Emily <3: 3 - Alex <3: 3 - Island Farmhouse: 1 - Island North Turtle: 1 - Island West Turtle: 1 - Kale Seeds: 1 - Luck Level: 5 - Maru <3: 3 - Melon Seeds: 1 - Minecarts Repair: 1 - Movement Speed Bonus: 5 - Parrot Express: 1 - Penny <3: 3 - Progressive Barn: 3 - Progressive Coop: 3 - Progressive Fishing Rod: 2 - Progressive House: 3 - Red Cabbage Seeds: 1 - Return Scepter: 1 - Rusty Key: 1 - Sebastian <3: 3 - Seed Maker: 1 - Shane <3: 3 - Silo: 1 - Skull Key: 1 - Stardrop: 2 - Starfruit Seeds: 1 - Strawberry Seeds: 1 - Sunflower Seeds: 1 - The Queen of Sauce: 1 - Tomato Seeds: 1 - Tractor Garage: 1 - locations: - - 25,000g Bundle - - Catch A Squid - - Catch a Lingcod - - A Curious Substance - - Aquatic Overpopulation - - Biome Balance - - Cellar Blueprint - - Collect All Rarecrows - - Complete Fish Tank - - Crop Order - - Danger In The Deep - - Deluxe Barn Blueprint - - Deluxe Coop Blueprint - - Fair Stardrop - - "Fishsanity: Blobfish" - - "Fishsanity: Blue Discus" - - "Fishsanity: Glacierfish" - - "Fishsanity: Ice Pip" - - "Fishsanity: Lava Eel" - - "Fishsanity: Legend" - - "Fishsanity: Midnight Squid" - - "Fishsanity: Midnight Carp" - - "Fishsanity: Scorpion Carp" - - "Fishsanity: Spook Fish" - - "Fishsanity: Stingray" - - "Fishsanity: Void Salmon" - - Floor 120 Elevator - - Four Precious Stones - - Fragments of the past - - "Friendsanity: Abigail 14 <3" - - "Friendsanity: Alex 14 <3" - - "Friendsanity: Elliott 14 <3" - - "Friendsanity: Emily 14 <3" - - "Friendsanity: Haley 14 <3" - - "Friendsanity: Harvey 14 <3" - - "Friendsanity: Leah 14 <3" - - "Friendsanity: Maru 14 <3" - - "Friendsanity: Penny 14 <3" - - "Friendsanity: Sam 14 <3" - - "Friendsanity: Sebastian 14 <3" - - "Friendsanity: Shane 14 <3" - - Gifts for George - - Galaxy Sword Shrine - - Grange Display - - Harvest Banana - - Harvest Cactus Fruit - - Have Another Baby - - "Help Wanted: Fishing 5" - - "Help Wanted: Gathering 5" - - "Help Wanted: Item Delivery 20" - - "Help Wanted: Slay Monsters 5" - - Iridium Axe Upgrade - - Iridium Hoe Upgrade - - Iridium Pickaxe Upgrade - - Iridium Trash Can Upgrade - - Iridium Watering Can Upgrade - - Island Farmhouse - - Island Ingredients - - Island Mailbox - - Island Resort - - Island Trader - - Island West Turtle - - Juicy Bugs Wanted! - - Kids Room Blueprint - - Kitchen Blueprint - - Level 10 Binning - - Level 10 Cooking - - Level 10 Combat - - Level 10 Luck - - Level 10 Mining - - Level 10 Foraging - - Level 7 Archaeology - - Level 7 Combat - - Level 7 Cooking - - Level 7 Farming - - Level 7 Fishing - - Level 7 Foraging - - Level 7 Mining - - Level 7 Socializing - - Mayor's Need - - "Museumsanity: Golden Relic" - - "Museumsanity: Rare Disc" - - Night Fishing Bundle - - Pierre's Prime Produce - - Parrot Express - - Purchase Iridium Rod - - Qi's Challenge - - Qi's Crop - - Qi's Cuisine - - Qi's Kindness - - Qi's Prismatic Grange - - Quality Crops Bundle - - Repair Boat Anchor - - Repair Boat Hull - - Repair Ticket Machine - - Robin's Project - - Robin's Resource Rush - - Rock Rejuvenation - - Strange Note - - The Mines Floor 110 Treasure - - The Mysterious Qi - - The Strong Stuff - - Tractor Garage Blueprint - - Tropical Fish - - Volcano Bridge - - Volcano Caldera Treasure - - Volcano Exit Shortcut - - "Wanted: Lobster" - from_pool: true - world: DragorrodSV - force: true - percentage: 100 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - Farm Computer: 1 - Movement Speed Bonus: 2 - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - goal: - community_center: 50 - grandpa_evaluation: 0 - bottom_of_the_mines: 0 - cryptic_note: 0 - master_angler: 0 - complete_collection: 0 - full_house: 0 - greatest_walnut_hunter: 0 - perfection: 0 - - starting_money: 800 - - profit_margin: 125 - - bundle_randomization: - vanilla: 0 - thematic: 0 - shuffled: 50 - - bundle_price: - # How many items are needed for the community center bundles? - # Very Cheap: Every bundle will require 2 items fewer than usual - # Cheap: Every bundle will require 1 item fewer than usual - # Normal: Every bundle will require the vanilla number of items - # Expensive: Every bundle will require 1 extra item when applicable - very_cheap: 0 - cheap: 0 - normal: 0 - expensive: 50 - - entrance_randomization: - # Should area entrances be randomized? - # Disabled: No entrance randomization is done - # Pelican Town: Only buildings in the main town area are randomized among each other - # Non Progression: Only buildings that are always available are randomized with each other - # Buildings: All Entrances that Allow you to enter a building using a door are randomized with each other - # Chaos: Same as above, but the entrances get reshuffled every single day! - disabled: 50 - pelican_town: 0 - non_progression: 0 - buildings: 0 - chaos: 0 - - season_randomization: - # Should seasons be randomized? - # All settings allow you to choose which season you want to play next (from those unlocked) at the end of a season. - # Disabled: You will start in Spring with all seasons unlocked. - # Randomized: The seasons will be unlocked randomly as Archipelago items. - # Randomized Not Winter: The seasons are randomized, but you're guaranteed not to start with winter. - # Progressive: You will start in Spring and unlock the seasons in their original order. - disabled: 0 - randomized: 50 - randomized_not_winter: 0 - progressive: 0 - - cropsanity: - # Formerly named "Seed Shuffle" - # Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. - # Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops - # Shuffled: Seeds are unlocked as archipelago item, for each seed there is a location check for growing and harvesting that crop - disabled: 0 - shuffled: 50 - - backpack_progression: - # How is the backpack progression handled? - # Vanilla: You can buy them at Pierre's General Store. - # Progressive: You will randomly find Progressive Backpack upgrades. - # Early Progressive: You can expect your first Backpack in sphere 1. - vanilla: 0 - progressive: 0 - early_progressive: 50 - - tool_progression: - # How is the tool progression handled? - # Vanilla: Clint will upgrade your tools with ore. - # Progressive: You will randomly find Progressive Tool upgrades. - vanilla: 0 - progressive: 50 - - skill_progression: - # How is the skill progression handled? - # Vanilla: You will level up and get the normal reward at each level. - # Progressive: The xp will be earned internally, locations will be sent when you earn a level. Your real - # levels will be scattered around the multiworld. - vanilla: 0 - progressive: 50 - - building_progression: - # How is the building progression handled? - # Vanilla: You will buy each building normally. - # Progressive: You will receive the buildings and will be able to build the first one of each type for free, - # once it is received. If you want more of the same building, it will cost the vanilla price. - # Progressive early shipping bin: You can expect your shipping bin in sphere 1. - vanilla: 0 - progressive: 0 - progressive_early_shipping_bin: 50 - - festival_locations: - # Locations for attending and participating in festivals - # With Disabled, you do not need to attend festivals - # With Easy, there are checks for participating in festivals - # With Hard, the festival checks are only granted when the player performs well in the festival - disabled: 0 - easy: 50 - hard: 0 - - elevator_progression: - # How is Elevator progression handled? - # Vanilla: You will unlock new elevator floors for yourself. - # Progressive: You will randomly find Progressive Mine Elevators to go deeper. Locations are sent for reaching - # every elevator level. - # Progressive from previous floor: Same as progressive, but you must reach elevator floors on your own, - # you cannot use the elevator to check elevator locations - vanilla: 0 - progressive: 0 - progressive_from_previous_floor: 50 - - arcade_machine_locations: - # How are the Arcade Machines handled? - # Disabled: The arcade machines are not included in the Archipelago shuffling. - # Victories: Each Arcade Machine will contain one check on victory - # Victories Easy: The arcade machines are both made considerably easier to be more accessible for the average - # player. - # Full Shuffling: The arcade machines will contain multiple checks each, and different buffs that make the game - # easier are in the item pool. Junimo Kart has one check at the end of each level. - # Journey of the Prairie King has one check after each boss, plus one check for each vendor equipment. - disabled: 50 - victories: 0 - victories_easy: 0 - full_shuffling: 0 - - special_order_locations: - # How are the Special Orders handled? - # Disabled: The special orders are not included in the Archipelago shuffling. - # Board Only: The Special Orders on the board in town are location checks - # Board and Qi: The Special Orders from Qi's walnut room are checks, as well as the board in town - disabled: 0 - board_only: 0 - board_qi: 50 - - help_wanted_locations: 40 - - fishsanity: - # Locations for catching fish? - # None: There are no locations for catching fish - # Legendaries: Each of the 5 legendary fish are checks - # Special: A curated selection of strong fish are checks - # Randomized: A random selection of fish are checks - # All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal - # Exclude Legendaries: Every fish except legendaries - # Exclude Hard Fish: Every fish under difficulty 80 - # Only Easy Fish: Every fish under difficulty 50 - none: 0 - legendaries: 0 - special: 0 - randomized: 0 - all: 50 - exclude_legendaries: 0 - exclude_hard_fish: 0 - only_easy_fish: 0 - - museumsanity: - # Locations for museum donations? - # None: There are no locations for donating artifacts and minerals to the museum - # Milestones: The donation milestones from the vanilla game are checks - # Randomized: A random selection of minerals and artifacts are checks - # All: Every single donation will be a check - none: 0 - milestones: 0 - randomized: 0 - all: 50 - - friendsanity: - # Locations for friendships? - # None: There are no checks for befriending villagers - # Bachelors: Each heart of a bachelor is a check - # Starting NPCs: Each heart for npcs that are immediately available is a check - # All: Every heart with every NPC is a check, including Leo, Kent, Sandy, etc - # All With Marriage: Marriage candidates must also be dated, married, and befriended up to 14 hearts. - none: 0 - bachelors: 0 - starting_npcs: 0 - all: 0 - all_with_marriage: 50 - - friendsanity_heart_size: - # If using friendsanity, how many hearts are received per item, and how many hearts must be earned to send a check - # A higher value will lead to fewer heart items in the item pool, reducing bloat - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 1 - # Maximum value is 8 - 3: 50 - random: 0 - random-low: 0 - random-high: 0 - - movement_buff_number: - # Number of movement speed buffs to the player that exist as items in the pool. - # Each movement speed buff is a +25% multiplier that stacks additively - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 12 - 10: 50 - random: 0 - random-low: 0 - random-high: 0 - - luck_buff_number: - # Number of luck buffs to the player that exist as items in the pool. - # Each luck buff is a bonus to daily luck of 0.025 - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 12 - 10: 50 - random: 0 - random-low: 0 - random-high: 0 - - exclude_ginger_island: - # Exclude Ginger Island? - # This option will forcefully exclude everything related to Ginger Island from the slot. - # If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway - false: 50 - true: 0 - - trap_items: - # When rolling filler items, including resource packs, the game can also roll trap items. - # This setting is for choosing if traps will be in the item pool, and if so, how punishing they will be. - no_traps: 0 - easy: 0 - medium: 0 - hard: 0 - hell: 50 - nightmare: 0 - - multiple_day_sleep_enabled: - # Enable the ability to sleep automatically for multiple days straight? - false: 0 - true: 50 - - multiple_day_sleep_cost: - # How much gold it will cost to use MultiSleep. You will have to pay that amount for each day skipped. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 200 - random: 0 - random-low: 0 - random-high: 0 - free: 50 # equivalent to 0 - cheap: 0 # equivalent to 25 - medium: 0 # equivalent to 50 - expensive: 0 # equivalent to 100 - - experience_multiplier: - # How fast you want to earn skill experience. A lower setting mean less experience. - # A higher setting means more experience. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 800 - random: 0 - random-low: 0 - random-high: 0 - half: 0 # equivalent to 50 - vanilla: 0 # equivalent to 100 - double: 0 # equivalent to 200 - triple: 50 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - friendship_multiplier: - # How fast you want to earn friendship points with villagers. - # A lower setting mean less friendship per action. - # A higher setting means more friendship per action. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 800 - random: 0 - random-low: 0 - random-high: 0 - half: 0 # equivalent to 50 - vanilla: 0 # equivalent to 100 - double: 0 # equivalent to 200 - triple: 50 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - debris_multiplier: - # How much debris will spawn on the player's farm? - # Vanilla: debris spawns normally - # Half: debris will spawn at half the normal rate - # Quarter: debris will spawn at one quarter of the normal rate - # None: No debris will spawn on the farm, ever - # Start Clear: debris will spawn at the normal rate, but the farm will be completely clear when starting the game - vanilla: 0 - half: 50 - quarter: 0 - none: 0 - start_clear: 0 - - quick_start: - # Do you want the quick start package? You will get a few items to help early game automation, - # so you can use the multiple day sleep at its maximum. - false: 0 - true: 50 - - gifting: - # Do you want to enable gifting items to and from other Stardew Valley worlds? - false: 0 - true: 50 - - mods: - # List of mods that will be considered for shuffling. - ["Bigger Backpack", "Tractor Mod", "Luck Skill", "Archaeology", "Cooking Skill", "Binning Skill"] - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 50 - true: 0 diff --git a/disabled yamls/Plandark.yaml b/disabled yamls/Plandark.yaml deleted file mode 100644 index 857783a9e78b..000000000000 --- a/disabled yamls/Plandark.yaml +++ /dev/null @@ -1,86 +0,0 @@ -game: Dark Souls III -name: Plandark -description: 'Generated à la sueur de mon front' -Dark Souls III: - progression_balancing: 50 - accessibility: locations - enable_weapon_locations: 'true' - enable_shield_locations: 'true' - enable_armor_locations: 'true' - enable_ring_locations: 'true' - enable_spell_locations: 'true' - enable_key_locations: 'true' - enable_boss_locations: 'true' - enable_npc_locations: 'false' - enable_misc_locations: 'true' - enable_health_upgrade_locations: 'true' - enable_progressive_locations: 'true' - pool_type: shuffle - auto_equip: 'false' - lock_equip: 'false' - no_weapon_requirements: 'true' - randomize_infusion: 'true' - randomize_infusion_percentage: random-range-50-75 - randomize_weapon_level: all - randomize_weapon_level_percentage: 100 - min_levels_in_5: 3 - max_levels_in_5: 5 - min_levels_in_10: 6 - max_levels_in_10: 10 - late_basin_of_vows: 'true' - late_dlc: 'false' - no_spell_requirements: 'true' - no_equip_load: 'true' - death_link: 'false' - enable_dlc: 'false' - plando_items: - # Gotta Fight in Stardew to Fight in Dark Souls - - items: - Storm Ruler: 1 - locations: - - "Cryptic Note" - force: true - world: true # other world - - # Enjoy the art - - items: - "Cinders of a Lord - Abyss Watcher": true - "Cinders of a Lord - Aldrich": true - "Cinders of a Lord - Lothric Prince": true - "Cinders of a Lord - Yhorm the Giant": true - "Lothric War Banner": true - "Small Envoy Banner": true - "Small Lothric Banner": true - locations: - - "Lupini: Red Eagle" - - "Lupini: Portrait Of A Mermaid" - - "Lupini: Solar Kingdom" - - "Lupini: Clouds" - - "Lupini: 1000 Years From Now" - - "Lupini: Three Trees" - - "Lupini: The Serpent" - count: false - force: true - world: true # other world - - # Enjoy the art - - items: - "Small Doll": 1 - "Basin of Vows": 1 - "Mortician's Ashes": 1 - locations: - - "Egg Festival: Strawberry Seeds" - - "Luau Soup" - - "Collect All Rarecrows" - count: false - force: true - world: true # other world - - # No early travelling merchant for you - - items: - Grand Archives Key: 1 - locations: - - "Mermaid Pearl" - force: true - world: true # other world - diff --git a/disabled yamls/Plandew.yaml b/disabled yamls/Plandew.yaml deleted file mode 100644 index 6f63f74efc0f..000000000000 --- a/disabled yamls/Plandew.yaml +++ /dev/null @@ -1,489 +0,0 @@ -game: Stardew Valley -name: Plandew -description: 'Generated mostly manually' -Stardew Valley: - progression_balancing: 50 - accessibility: locations - goal: community_center - starting_money: random - profit_margin: 200 - bundle_randomization: thematic - bundle_price: normal - entrance_randomization: disabled - season_randomization: randomized - cropsanity: shuffled - backpack_progression: early_progressive - tool_progression: progressive - skill_progression: progressive - building_progression: progressive_early_shipping_bin - festival_locations: hard - elevator_progression: progressive - arcade_machine_locations: full_shuffling - special_order_locations: board_only - help_wanted_locations: 7 - fishsanity: exclude_hard_fish - museumsanity: milestones - friendsanity: starting_npcs - friendsanity_heart_size: 4 - movement_buff_number: 5 - luck_buff_number: 8 - exclude_ginger_island: 'true' - trap_items: hard - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 300 - friendship_multiplier: 400 - debris_multiplier: quarter - quick_start: 'true' - gifting: 'true' - mods: ["Bigger Backpack", "Juna - Roommate NPC", "Ayeisha - The Postal Worker (Custom NPC)", "Socializing Skill", "Binning Skill", "Archaeology"] - death_link: 'false' - start_inventory: - Fall: 1 - plando_items: - # Stay away from my waifu - - items: - "Random Teleport": 2 - locations: - - "Friendsanity: Abigail 4 <3" - - "Friendsanity: Abigail 8 <3" - force: true - world: false # own world - - # Fuck your mining runs - - items: - "Burnt": true - "Frozen": true - "Jinxed": true - "Slimed": true - "Weakness": true - locations: - - "Floor 5 Elevator" - - "Floor 15 Elevator" - - "Floor 25 Elevator" - - "Floor 35 Elevator" - - "Floor 45 Elevator" - - "Floor 55 Elevator" - - "Floor 65 Elevator" - - "Floor 75 Elevator" - - "Floor 85 Elevator" - - "Floor 95 Elevator" - - "Floor 105 Elevator" - - "Floor 115 Elevator" - count: false - force: true - world: false # own world - - # Your reward is: A Gambling Addiction! - - items: - "Club Card": 1 - locations: - - "Floor 120 Elevator" - force: true - world: false # own world - - # Fuck your skull cavern dive - - items: - "Nauseated": 1 - locations: - - "Qi's Challenge" - count: false - force: true - world: false # own world - - # Fighting might be harder with this - - items: - "Shuffle": true - "Nauseated": true - "Darkness": true - locations: - - "Level 1 Combat" - - "Level 2 Combat" - - "Level 3 Combat" - - "Level 4 Combat" - - "Level 5 Combat" - - "Level 6 Combat" - - "Level 7 Combat" - - "Level 8 Combat" - - "Level 9 Combat" - count: false - force: true - world: false # own world - - # Gotta Fight in Dark Souls to Fight in Stardew - - items: - "Galaxy Sword": true - "Galaxy Dagger": true - "Galaxy Hammer": true - locations: - - "PC: Soul of Yhorm the Giant" - count: 1 - force: true - world: true # other world - - # Go home and no grow - - items: - "Drought": true - locations: - - "Egg Hunt Victory" - - "Dance with someone" - - "Dance of the Moonlight Jellies" - - "Smashing Stone" - - "Spirit's Eve Maze" - - "Win Fishing Competition" - - "The Legend of the Winter Star" - count: false - force: true - world: false # own world - - # Cleaning your farm will get you stabbed and make it dirty again - - items: - "Monsters": true - "Debris": true - locations: - - "Level 1 Foraging" - - "Level 2 Foraging" - - "Level 3 Foraging" - - "Level 4 Foraging" - - "Level 5 Foraging" - count: false - force: true - world: false # own world - - # Reverse friendship - - items: - "Pariah": true - locations: - - "How To Win Friends" - - "Secret Santa" - count: false - force: true - world: false # own world - - # Fuck your other crops when harvesting something - - items: - "The Crows": true - locations: - - "Getting Started" - - "Harvest Amaranth" - - "Harvest Artichoke" - - "Harvest Beet" - - "Harvest Blue Jazz" - - "Harvest Blueberry" - - "Harvest Bok Choy" - - "Harvest Cauliflower" - - "Harvest Corn" - - "Harvest Cranberries" - - "Harvest Eggplant" - - "Harvest Fairy Rose" - - "Harvest Garlic" - - "Harvest Grape" - - "Harvest Green Bean" - - "Harvest Hops" - - "Harvest Hot Pepper" - - "Harvest Kale" - - "Harvest Melon" - - "Harvest Parsnip" - - "Harvest Poppy" - - "Harvest Potato" - - "Harvest Pumpkin" - - "Harvest Radish" - - "Harvest Rhubarb" - - "Harvest Starfruit" - - "Harvest Strawberry" - - "Harvest Summer Spangle" - - "Harvest Sunflower" - - "Harvest Tomato" - - "Harvest Tulip" - - "Harvest Unmilled Rice" - - "Harvest Wheat" - - "Harvest Yam" - - "Harvest Cactus Fruit" - - "Harvest Pineapple" - - "Harvest Taro Root" - - "Harvest Sweet Gem Berry" - - "Harvest Apple" - - "Harvest Apricot" - - "Harvest Cherry" - - "Harvest Orange" - - "Harvest Pomegranate" - - "Harvest Peach" - - "Harvest Banana" - - "Harvest Mango" - - "Harvest Coffee Bean" - count: false - force: true - world: false # own world - - # No Early Traveling Merchant for you - - items: - "Traveling Merchant: Sunday": 1 - locations: - - "GA: Crystal Scroll" - count: false - force: true - world: true # other world - - # No Traveling Merchant for you - - items: - "Traveling Merchant: Monday": 1 - locations: - - "Traveling Merchant Sunday Item 1" - count: false - force: true - world: false # own world - - # No Traveling Merchant for you - - items: - "Traveling Merchant: Tuesday": 1 - locations: - - "Traveling Merchant Monday Item 1" - count: false - force: true - world: false # own world - - # No Traveling Merchant for you - - items: - "Traveling Merchant: Wednesday": 1 - locations: - - "Traveling Merchant Tuesday Item 1" - count: false - force: true - world: false # own world - - # No Traveling Merchant for you - - items: - "Traveling Merchant: Thursday": 1 - locations: - - "Traveling Merchant Wednesday Item 1" - count: false - force: true - world: false # own world - - # No Traveling Merchant for you - - items: - "Traveling Merchant: Friday": 1 - locations: - - "Traveling Merchant Thursday Item 1" - count: false - force: true - world: false # own world - - # No Traveling Merchant for you - - items: - "Traveling Merchant: Saturday": 1 - locations: - - "Traveling Merchant Friday Item 1" - count: false - force: true - world: false # own world - - # These two seasons will be well hidden - - items: - "Spring": true - "Summer": true - locations: - - "Traveling Merchant Saturday Item 1" - - "Magic Ink" - count: false - force: true - world: false # own world - - # Unlock the hard quests early to bait him into doing them - - items: - "Special Order Board": 1 - locations: - - "Level 1 Farming" - count: false - force: true - world: false # own world - - # Prairie King buffs will be hard-earned - - items: - "JotPK: Progressive Boots": true - "JotPK: Progressive Ammo": true - "JotPK: Increased Drop Rate": true - "JotPK: Progressive Gun": true - locations: - - "Level 10 Fishing" - - "Level 10 Foraging" - - "Level 10 Mining" - - "Level 10 Combat" - - "Level 10 Socializing" - - "Level 10 Binning" - - "Level 10 Archaeology" - - "Friendsanity: Ayeisha 10 <3" - - "Friendsanity: Juna 10 <3" - - "Premium Pack" - count: false - force: true - world: false # own world - - # No Junimo Kart until you win Prairie King - - items: - "Skull Key": 1 - locations: - - "Journey of the Prairie King Victory" - count: false - force: true - world: false # own world - - # The most well-hidden item - - items: - "Winter": 1 - locations: - - "Junimo Kart: Secret Level" - count: false - force: true - world: false # own world - - #Some art is money laundering - - items: - "Taxes": true - locations: - - "Lupini: Land Of Clay" - - "Lupini: 'Tropical Fish #173'" - count: false - force: true - world: false # own world - - #Greenhouse behind the hardest-to-grow crop - - items: - "Greenhouse": 1 - locations: - - "Harvest Sweet Gem Berry" - count: false - force: true - world: false # own world - - # As soon as you switch seasons, here's a good fall seed - - items: - "Rare Seed": 1 - "Pumpkin Seeds": 1 - "Amaranth Seeds": 1 - locations: - - "Summer Foraging Bundle" - - "Spring Foraging Bundle" - - "Winter Foraging Bundle" - count: false - force: true - world: false # own world - - # Got any grapes? - - items: - "Grape Starter": 1 - locations: - - "Big Coop Blueprint" - count: false - force: true - world: false # own world - - # The two ways to make babies - - items: - "Ugly Baby": true - "Cute Baby": true - locations: - - "Mayor's \"Shorts\"" - - "Harvest Red Cabbage" - count: false - force: true - world: false # own world - - # tough to get backpacks - - items: - "Progressive Backpack": 2 - locations: - - "Have Another Baby" - - "Strange Note" - count: false - force: true - world: false # own world - - # tough to get backpacks - - items: - "Rusty Key": 1 - locations: - - "Have a Baby" - count: false - force: true - world: false # own world - - # Try to hide this obelisk a little bit - - items: - "Desert Obelisk": 1 - locations: - - "Dark Talisman" - count: false - force: true - world: false # own world - - # Kids are dwarves - - items: - "Dwarvish Translation Guide": 1 - locations: - - "Friendsanity: Vincent 10 <3" - - "Friendsanity: Jas 10 <3" - count: false - force: true - world: false # own world - - # They're hoeing around - - items: - "Progressive Hoe": 4 - locations: - - "Friendsanity: Caroline 4 <3" - - "Friendsanity: Caroline 8 <3" - - "Friendsanity: Haley 4 <3" - - "Friendsanity: Haley 8 <3" - count: false - force: true - world: false # own world - - # They're hoeing around - - items: - "Progressive Trash Can": 4 - locations: - - "Friendsanity: Pierre 4 <3" - - "Friendsanity: Pierre 8 <3" - - "Friendsanity: Demetrius 4 <3" - - "Friendsanity: Demetrius 8 <3" - count: false - force: true - world: false # own world - - # Self Explanatory - - items: - "Penny <3": 1 - locations: - - "Copper Hoe Upgrade" - count: false - force: true - world: false # own world - - # Self Explanatory - - items: - "Maru <3": 1 - locations: - - "Iron Hoe Upgrade" - count: false - force: true - world: false # own world - - # Self Explanatory - - items: - "Haley <3": 1 - locations: - - "Gold Hoe Upgrade" - count: false - force: true - world: false # own world - - # Self Explanatory - - items: - "Abigail <3": 1 - locations: - - "Iridium Hoe Upgrade" - count: false - force: true - world: false # own world - diff --git a/disabled yamls/Plandow.yaml b/disabled yamls/Plandow.yaml deleted file mode 100644 index 800a42ff5965..000000000000 --- a/disabled yamls/Plandow.yaml +++ /dev/null @@ -1,87 +0,0 @@ -description: 'Generated by https://archipelago.gg/ for Hollow Knight' -game: Hollow Knight -name: Missing_DLL -Hollow Knight: - progression_balancing: disabled - accessibility: locations - RandomizeDreamers: 'true' - RandomizeSkills: 'true' - RandomizeFocus: 'true' - RandomizeSwim: 'true' - RandomizeCharms: 'true' - RandomizeKeys: 'true' - RandomizeMaskShards: 'true' - RandomizeVesselFragments: 'true' - RandomizeCharmNotches: 'true' - RandomizePaleOre: 'true' - RandomizeGeoChests: 'true' - RandomizeJunkPitChests: 'true' - RandomizeRancidEggs: 'true' - RandomizeRelics: 'true' - RandomizeWhisperingRoots: 'true' - RandomizeBossEssence: 'true' - RandomizeGrubs: 'true' - RandomizeMimics: 'true' - RandomizeMaps: 'true' - RandomizeStags: 'true' - RandomizeLifebloodCocoons: 'true' - RandomizeGrimmkinFlames: 'true' - RandomizeJournalEntries: 'true' - RandomizeNail: 'true' - RandomizeGeoRocks: 'true' - RandomizeBossGeo: 'true' - RandomizeSoulTotems: 'true' - RandomizeLoreTablets: 'true' - RandomizeElevatorPass: 'true' - PreciseMovement: 'true' - ProficientCombat: 'true' - BackgroundObjectPogos: 'true' - EnemyPogos: 'true' - ObscureSkips: 'false' - ShadeSkips: 'true' - InfectionSkips: 'false' - FireballSkips: 'false' - SpikeTunnels: 'false' - AcidSkips: 'true' - DamageBoosts: 'true' - DangerousSkips: 'true' - DarkRooms: 'true' - ComplexSkips: 'false' - DifficultSkips: 'false' - RemoveSpellUpgrades: 'false' - StartLocation: king's_pass - Goal: radiance - WhitePalace: include - StartingGeo: random - DeathLink: off - MinimumGeoPrice: random - MaximumGeoPrice: random - MinimumGrubPrice: random - MaximumGrubPrice: random - MinimumEssencePrice: random - MaximumEssencePrice: random - MinimumCharmPrice: random - MaximumCharmPrice: random - RandomCharmCosts: -2 - MinimumEggPrice: random - MaximumEggPrice: random - EggShopSlots: 7 - SlyShopSlots: 5 - SlyKeyShopSlots: 7 - IseldaShopSlots: 5 - SalubraShopSlots: 6 - SalubraCharmShopSlots: 5 - LegEaterShopSlots: 5 - GrubfatherRewardSlots: 7 - SeerRewardSlots: 5 - ExtraShopSlots: random - SplitCrystalHeart: 'true' - SplitMothwingCloak: 'true' - SplitMantisClaw: 'true' - CostSanity: on - CostSanityHybridChance: 2 - CostSanityEggWeight: 1 - CostSanityGrubWeight: 10 - CostSanityEssenceWeight: 10 - CostSanityCharmWeight: 10 - CostSanityGeoWeight: 8 \ No newline at end of file diff --git a/disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml b/disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml deleted file mode 100644 index 2e1094560bf6..000000000000 --- a/disabled yamls/RC1/CaitSith2-ALttP_-_Copy.yaml +++ /dev/null @@ -1,670 +0,0 @@ -############################################################################################################# -# # -# ▄████▄ ▄▄▄ ██▓▄▄▄█████▓ ██████ ██▓▄▄▄█████▓ ██░ ██ ▄▄▄█████▓ █ █░ ▒█████ # -# ▒██▀ ▀█ ▒████▄ ▓██▒▓ ██▒ ▓▒▒██ ▒ ▓██▒▓ ██▒ ▓▒▓██░ ██▒ ▓ ██▒ ▓▒▓█░ █ ░█░▒██▒ ██▒ # -# ▒▓█ ▄ ▒██ ▀█▄ ▒██▒▒ ▓██░ ▒░░ ▓██▄ ▒██▒▒ ▓██░ ▒░▒██▀▀██░ ▒ ▓██░ ▒░▒█░ █ ░█ ▒██░ ██▒ # -# ▒▓▓▄ ▄██▒░██▄▄▄▄██ ░██░░ ▓██▓ ░ ▒ ██▒░██░░ ▓██▓ ░ ░▓█ ░██ ░ ▓██▓ ░ ░█░ █ ░█ ▒██ ██░ # -# ▒ ▓███▀ ░ ▓█ ▓██▒░██░ ▒██▒ ░ ▒██████▒▒░██░ ▒██▒ ░ ░▓█▒░██▓ ▒██▒ ░ ░░██▒██▓ ░ ████▓▒░ # -# ░ ░▒ ▒ ░ ▒▒ ▓▒█░░▓ ▒ ░░ ▒ ▒▓▒ ▒ ░░▓ ▒ ░░ ▒ ░░▒░▒ ▒ ░░ ░ ▓░▒ ▒ ░ ▒░▒░▒░ # -# ░ ▒ ▒ ▒▒ ░ ▒ ░ ░ ░ ░▒ ░ ░ ▒ ░ ░ ▒ ░▒░ ░ ░ ▒ ░ ░ ░ ▒ ▒░ # -# ░ ░ ▒ ▒ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ▒ # -# ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ # -# ░ # -# # -# @ # -# @@@@@ ,@@@@@@ # -# @@@@&@@@ ,@@@&@@@@ # -# %@@@@&&@@@ @@@&&&@@@& # -# @@@@&&&@@@ ,@@@&&&@@@@ # -# @@@@&&&&&@@@ @@@&&&&&@@@@ # -# @@@@&&%&&@@@ @@@@@@@@@@@@@@@@@@@@@& @@@@&&%&&&@@@ # -# @@@@&&%%&&&@@@ @@@@@@@@@@################%@@@@@@@@% @@@&&&%&&&@@@@ # -# @@@@&&&%%&&@@@/ (@@@@@@################################&@@@@@@ @@@&&&%%&&&@@@@ # -# @@@&&&&%%&&&@@@,@@@@@@#########################################%@@@@@ @@@&&&&%&&&&&@@@ # -# @@@&&&&&%%&&&&@@@@@@@################################################&@@@@@@@&&&&%&&&&&&@@@ # -# @@@&&&&&&%&&&&&@@@@@&#####################################################%@/.,&&&&&%&&&&&&&@@% # -# @@@&&&&&&&&&&&&&@@@###########################################################@#../&&&&&&&&&&&@@. # -# @@@&&&&&%%%&&&&&&@######* #####################################################@#...@%&&&&&&@@@ # -# @@@&&&&&&&&&&&&&#########* /###################. (####################@##@%*#@@#(#&@/.../@@&@@@ # -# @@&&&&&&&&&&&###########. ,###############/ ,##################@@@@**/**/@##&..%@&@/.....*@ # -# @@@&&&&&&&&%####. ,/###(/, #* .(####@@#****@###&&@/...,//.., # -# (@@@&&&&&#####* ######&@#####&&&&@@@..*, # -# @@@&&&######. /@@@@@@@@@@@@@/ &@@@@@@@@@@@@% (##########&@@@@@, # -# @@@&######. ,@@@@@%%%%%%%%%&@@@@@ /@@@@@%%%%%%%%%@@@@@& .########&@@@.@.@ # -# @@@#######( %%((%%%&&%%%%%%# @@% @@#.%%%%%%&&&%%#(#%, ########@@@. /@ # -# @@@@######( #(((&&&&&&%%% @ */ *%%%&&&&&(((#. #######@@@@ # -# @@@@###### ((/((#/%%/((((* ((((##%#/#(((( ######@@@@ # -# @@@@##### /((((((((((. ((((((((((( #####&@@@@ # -# @@@@@#### .#####@@@@ # -# @@@@&###. /@ .@#@& ,@ #####@@@@@ # -# @@@@@###. (((((% #####@@@@@ # -# @@@@@#### (%&. #####%@@@@ # -# %@@@@@%### .#####@@@@@ # -# @@@@@@@####(. .####%@@@@@@ # -# @@@@@@@@@&#################/*.... ....,/########%@@@@@@@@@ # -# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # -# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # -# # -############################################################################################################# - -description: CaitSith2's ALttP YAML 1 of 1 -name: -# CaitSith {NUMBER}: 1 -# Yunica Tovah {NUMBER}: 1 -# Adol Christin {NUMBER}: 1 - Untitled Goose {NUMBER}: 1 -# Boco {NUMBER}: 1 -# Popoi {NUMBER}: 1 -game: - A Link to the Past: 1 -requires: - version: 0.2.3 - plando: bosses -# Shared Options supported by all games: -accessibility: - items: 0 - locations: 50 - none: 0 -progression_balancing: 50 -A Link to the Past: - start_hints: - - Swords - - Lamp - start_location_hints: - - 'Take-Any #1' - - 'Take-Any #2' - - 'Take-Any #3' - - 'Take-Any #4' - - 'Old Man Sword Cave' - start_inventory: - Rupees (300): 33 - Bombs (10): 1 - Arrows (10): 3 - Pegasus Boots: 1 - glitches_required: - none: 50 - minor_glitches: 0 - overworld_glitches: 0 - hybrid_major_glitches: 0 - no_logic: 0 - dark_room_logic: - lamp: 0 - torches: 1 - none: 0 - restrict_dungeon_item_on_boss: - on: 0 - off: 50 - bigkey_shuffle: - original_dungeon: 0 - own_dungeons: 1 - own_world: 0 - any_world: 0 - different_world: 0 - start_with: 0 - smallkey_shuffle: - original_dungeon: 0 - own_dungeons: 1 - own_world: 0 - any_world: 0 - different_world: 0 - universal: 0 - start_with: 0 - compass_shuffle: - original_dungeon: 0 - own_dungeons: 0 - own_world: 0 - any_world: 0 - different_world: 0 - start_with: 1 - map_shuffle: - original_dungeon: 0 - own_dungeons: 0 - own_world: 0 - any_world: 1 - different_world: 0 - start_with: 0 - key_drop_shuffle: - on: 1 - off: 0 - dungeon_counters: - on: 50 - pickup: 0 - default: 0 - off: 0 - progressive: - on: 50 - off: 0 - grouped_random: 0 - local_items: - - Swords - - Moon Pearl - - Lamp - - Bottles - - Flute - - Magic Mirror - - Gloves - - Hammer - - Hookshot - - Flippers - - Magic Powder - - Cane of Somaria - - Bombos - - Fire Rod - - Ice Rod - - Book of Mudora - - Shovel - - Mushroom - entrance_shuffle: - none: 0 - dungeonssimple: 0 - dungeonsfull: 0 - dungeonscrossed: 0 - dungeonscrossed-1000: 1 - simple: 0 - restricted: 0 - full: 0 - crossed: 0 - insanity: 0 - crossed-1000: 0 - crossed-group-myfriends: 0 - goals: - ganon: 0 - crystals: 0 - bosses: 1 - pedestal: 0 - ganon_pedestal: 0 - triforce_hunt: 0 - local_triforce_hunt: 0 - ganon_triforce_hunt: 0 - local_ganon_triforce_hunt: 0 - ice_rod_hunt: 0 - open_pyramid: - goal: 50 - auto: 0 - yes: 0 - no: 0 - triforce_pieces_mode: - extra: 0 - percentage: 0 - available: 50 - triforce_pieces_extra: - 0: 0 - 5: 50 - 10: 50 - 15: 0 - 20: 0 - triforce_pieces_percentage: - 100: 0 - 150: 50 - 200: 0 - triforce_pieces_available: - 25: 0 - 30: 0 - 40: 1 - 60: 0 - triforce_pieces_required: - 15: 0 - 20: 0 - 30: 1 - 40: 0 - 60: 0 - crystals_needed_for_gt: - 0: 50 - 7: 0 - random: 0 - random-low: 0 - random-middle: 0 - random-high: 0 - crystals_needed_for_ganon: - 0: 0 - 3: 0 - 4: 0 - 5: 50 - 6: 50 - 7: 50 - random: 0 - random-low: 0 - random-middle: 0 - random-high: 0 - mode: - standard: 0 - open: 50 - inverted: 0 - retro_bow: - on: 0 - off: 50 - retro_caves: - on: 1 - off: 0 - hints: - 'on': 1 - 'off': 0 - full: 0 - scams: - 'off': 1 - 'king_zora': 0 - 'bottle_merchant': 0 - 'all': 0 - swordless: - on: 0 - off: 1 - item_pool: - easy: 1 - normal: 0 - hard: 0 - expert: 0 - item_functionality: - easy: 50 - normal: 0 - hard: 0 - expert: 0 - tile_shuffle: - on: 50 - off: 0 - misery_mire_medallion: - random: 0 - Ether: 0 - Bombos: 1 - Quake: 0 - turtle_rock_medallion: - random: 0 - Ether: 0 - Bombos: 1 - Quake: 0 - boss_shuffle: - none: 0 - basic: 0 - full: 0 - chaos: 0 - - #I have no desire to fight Trinexx on Ice. The boss that is able to go into all locations is being placed there instead. - Ganons Tower Bottom-Kholdstare;Trinexx;Kholdstare: 1 - Ganons Tower Bottom-Moldorm;Trinexx;Moldorm: 1 - Ganons Tower Bottom-Mothula;Trinexx;Mothula: 1 - Ganons Tower Bottom-Helmasaur King;Trinexx;Helmasaur King: 1 - Ganons Tower Bottom-Vitreous;Trinexx;Vitreous: 1 - #And the rest of the singularity combinations the exclude trinexx entirely. - Armos Knights;Moldorm: 1 - Armos Knights;Helmasaur King: 0 - Armos Knights;Mothula: 1 - Armos Knights;Vitreous: 1 - Armos Knights;Kholdstare: 1 - Lanmolas;Moldorm: 1 - Lanmolas;Helmasaur King: 1 - Lanmolas;Mothula: 1 - Lanmolas;Vitreous: 1 - Lanmolas;Kholdstare: 1 - Arrghus;Moldorm: 1 - Arrghus;Helmasaur King: 1 - Arrghus;Mothula: 1 - Arrghus;Vitreous: 1 - Arrghus;Kholdstare: 1 - Blind;Moldorm: 1 - Blind;Helmasaur King: 1 - Blind;Mothula: 1 - Blind;Vitreous: 1 - Blind;Kholdstare: 1 - Moldorm: 1 - Helmasaur King: 1 - Mothula: 1 - Vitreous: 1 - Kholdstare: 1 - enemy_shuffle: - on: 0 - off: 50 - killable_thieves: - on: 1 - off: 0 - bush_shuffle: - on: 0 - off: 50 - enemy_damage: - default: 50 - shuffled: 0 - chaos: 0 - enemy_health: - default: 50 - easy: 0 - hard: 0 - expert: 0 - pot_shuffle: - 'on': 0 - 'off': 50 - beemizer_total_chance: - 0: 100 - 25: 0 - 50: 0 - 75: 0 - 100: 0 - beemizer_trap_chance: - 0: 100 - 60: 0 - 70: 0 - 80: 0 - 90: 0 - 100: 0 - shop_item_slots: - 0: 1 - 5: 0 - 15: 0 - 30: 0 - random: 0 - shop_price_modifier: - 0: 0 - 400: 0 - random: 0 - random-low: 0 - random-high: 0 - 100: 50 - shop_shuffle: - none: 0 - uw: 50 - g: 0 - f: 0 - i: 0 - p: 0 - w: 0 - ip: 0 - fpu: 0 - uip: 0 - shuffle_prizes: - none: 0 - g: 50 - b: 0 - bg: 0 - timer: - none: 50 - timed: 0 - timed_ohko: 0 - ohko: 0 - timed_countdown: 0 - display: 0 - countdown_start_time: - 0: 0 - 10: 50 - 20: 0 - 30: 0 - 60: 0 - red_clock_time: - -2: 50 - 1: 0 - blue_clock_time: - 1: 0 - 2: 50 - green_clock_time: - 4: 50 - 10: 0 - 15: 0 - glitch_boots: - on: 50 - off: 0 - random_sprite_on_event: - enabled: - on: 1 - off: 0 - on_hit: - on: 1 - off: 0 - on_enter: - on: 1 - off: 1 - on_exit: - on: 1 - off: 1 - on_slash: - on: 1 - off: 1 - on_item: - on: 1 - off: 1 - on_bonk: - on: 1 - off: 1 - on_everything: - on: 0 - off: 1 - use_weighted_sprite_pool: - on: 1 - off: 0 - sprite: - goose: 1 - boco: 1 - yunica tovah: 1 - adol: 1 - popoi: 1 - music: - on: 50 - off: 0 - quickswap: - on: 50 - off: 0 - triforcehud: - normal: 0 - hide_goal: 0 - hide_required: 0 - hide_both: 1 - reduceflashing: - on: 50 - off: 0 - menuspeed: - normal: 0 - instant: 0 - double: 0 - triple: 0 - quadruple: 1 - half: 0 - heartcolor: - red: 0 - blue: 1 - green: 0 - yellow: 0 - random: 0 - heartbeep: - double: 0 - normal: 0 - half: 0 - quarter: 1 - off: 0 - ow_palettes: - default: 50 - good: 0 - blackout: 0 - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - uw_palettes: - default: 50 - good: 0 - blackout: 0 - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - hud_palettes: - default: 50 - good: 0 - blackout: 0 - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - sword_palettes: - default: 50 - good: 0 - blackout: 0 - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - shield_palettes: - default: 50 - good: 0 - blackout: 0 - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - legacy_weapons: - trigger_disabled: 50 - randomized: 0 - assured: 0 - vanilla: 0 - swordless: 0 - death_link: - false: 50 - true: 0 - allow_collect: - false: 0 - true: 1 -linked_options: - - name: crosskeys - options: - A Link to the Past: - entrance_shuffle: crossed - bigkey_shuffle: true - compass_shuffle: true - map_shuffle: true - smallkey_shuffle: true - percentage: 0 - - name: localcrosskeys - options: - A Link to the Past: - entrance_shuffle: crossed - bigkey_shuffle: true - compass_shuffle: true - map_shuffle: true - smallkey_shuffle: true - local_items: - - "Small Keys" - - "Big Keys" - percentage: 0 - - name: enemizer - options: - A Link to the Past: - boss_shuffle: - basic: 1 - full: 1 - chaos: 1 - singularity: 1 - enemy_damage: - shuffled: 1 - chaos: 1 - enemy_health: - easy: 1 - hard: 1 - expert: 1 - percentage: 0 -triggers: - - option_name: legacy_weapons - option_result: randomized - option_category: A Link to the Past - options: - A Link to the Past: - swordless: off - - option_name: legacy_weapons - option_result: assured - option_category: A Link to the Past - options: - A Link to the Past: - swordless: off - start_inventory: - Progressive Sword: 1 - - option_name: legacy_weapons - option_result: vanilla - option_category: A Link to the Past - options: - A Link to the Past: - swordless: off - plando_items: - - items: - Progressive Sword: 4 - locations: - - Master Sword Pedestal - - Pyramid Fairy - Left - - Blacksmith - - Link's Uncle - - items: - Moon Pearl: 1 - Lamp: 1 - locations: - - early_locations - - option_name: legacy_weapons - option_result: swordless - option_category: A Link to the Past - options: - A Link to the Past: - swordless: on - - option_name: enemy_damage - option_category: A Link to the Past - option_result: shuffled - percentage: 0 - options: - A Link to the Past: - swordless: off - - option_name: name - option_result: Yunica Tovah {NUMBER} - option_category: null - options: - A Link to the Past: - sprite: - goose: 1 - boco: 1 - yunica tovah: 28 - adol: 1 - popoi: 1 - - option_name: name - option_result: Adol Christin {NUMBER} - option_category: null - options: - A Link to the Past: - sprite: - goose: 1 - boco: 1 - yunica tovah: 1 - adol: 28 - popoi: 1 - - option_name: name - option_result: Untitled Goose {NUMBER} - option_category: null - options: - A Link to the Past: - sprite: - goose: 28 - boco: 1 - yunica tovah: 1 - adol: 1 - popoi: 1 - - option_name: name - option_result: Boco {NUMBER} - option_category: null - options: - A Link to the Past: - sprite: - goose: 1 - boco: 28 - yunica tovah: 1 - adol: 1 - popoi: 1 - - option_name: name - option_result: Popoi {NUMBER} - option_category: null - options: - A Link to the Past: - sprite: - goose: 1 - boco: 1 - yunica tovah: 1 - adol: 1 - popoi: 28 - diff --git a/disabled yamls/RC1/DOOMBeta.yaml b/disabled yamls/RC1/DOOMBeta.yaml deleted file mode 100644 index f7414131bc18..000000000000 --- a/disabled yamls/RC1/DOOMBeta.yaml +++ /dev/null @@ -1,164 +0,0 @@ -# Q. What is this file? -# A. This file contains options which allow you to configure your multiworld experience while allowing -# others to play how they want as well. -# -# Q. How do I use it? -# A. The options in this file are weighted. This means the higher number you assign to a value, the -# more chances you have for that option to be chosen. For example, an option like this: -# -# map_shuffle: -# on: 5 -# off: 15 -# -# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned -# off. -# -# Q. I've never seen a file like this before. What characters am I allowed to use? -# A. This is a .yaml file. You are allowed to use most characters. -# To test if your yaml is valid or not, you can use this website: -# http://www.yamllint.com/ -# You can also verify your Archipelago settings are valid at this site: -# https://archipelago.gg/check - -# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. -# {player} will be replaced with the player's slot number. -# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. -# {number} will be replaced with the counter value of the name. -# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. -name: ForsakenDoom - -# Used to describe your yaml. Useful if you have multiple files. -description: Default DOOM 1993 Template - -game: DOOM 1993 -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -DOOM 1993: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 50 # equivalent to 50 - extreme: 0 # equivalent to 99 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - {} - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - difficulty: - # Choose the difficulty option. Those match DOOM's difficulty options. - # baby (I'm too young to die.) double ammos, half damage, less monsters or strength. - # easy (Hey, not too rough.) less monsters or strength. - # medium (Hurt me plenty.) Default. - # hard (Ultra-Violence.) More monsters or strength. - # nightmare (Nightmare!) Monsters attack more rapidly and respawn. - baby: 0 - easy: 50 - medium: 0 - hard: 0 - nightmare: 0 - - random_monsters: - # Choose how monsters are randomized. - # vanilla: No randomization - # shuffle: Monsters are shuffled within the level - # random_balanced: Monsters are completely randomized, but balanced based on existing ratio in the level. (Small monsters vs medium vs big) - vanilla: 50 - shuffle: 0 - random_balanced: 0 - - random_pickups: - # Choose how pickups are randomized. - # vanilla: No randomization - # shuffle: Pickups are shuffled within the level - # random_balanced: Pickups are completely randomized, but balanced based on existing ratio in the level. (Small pickups vs Big) - vanilla: 0 - shuffle: 50 - random_balanced: 0 - - allow_death_logic: - # Some locations require a timed puzzle that can only be tried once. - # After which, if the player failed to get it, the location cannot be checked anymore. - # By default, no progression items are placed here. There is a way, hovewer, to still get them: - # Get killed in the current map. The map will reset, you can now attempt the puzzle again. - false: 0 - true: 50 - - start_with_computer_area_maps: - # Give the player all Computer Area Map items from the start. - false: 0 - true: 50 - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 0 - true: 50 - - episode1: - # Knee-Deep in the Dead. - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 0 - true: 50 - - episode2: - # The Shores of Hell. - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 0 - true: 50 - - episode3: - # Inferno. - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 50 - true: 0 - - episode4: - # Thy Flesh Consumed. - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 50 - true: 0 diff --git a/disabled yamls/RC1/Dragus_DOOM_world.yaml b/disabled yamls/RC1/Dragus_DOOM_world.yaml deleted file mode 100644 index 566b0b49c36c..000000000000 --- a/disabled yamls/RC1/Dragus_DOOM_world.yaml +++ /dev/null @@ -1,53 +0,0 @@ -DOOM 1993: - progression_balancing: 50 - accessibility: items - difficulty: medium - random_monsters: shuffle - random_pickups: shuffle - allow_death_logic: 'false' - start_with_computer_area_maps: 'false' - death_link: 'false' - episode1: 'false' - episode2: 'false' - episode3: 'true' - episode4: 'false' -description: 'Generated by https://archipelago.gg/ for DOOM 1993' -game: DOOM 1993 -name: Dragus DOOM - - ---- - -Super Mario World: - progression_balancing: 50 - accessibility: items - death_link: 'false' - goal: yoshi_egg_hunt - bosses_required: 7 - number_of_yoshi_eggs: 50 - percentage_of_yoshi_eggs: 70 - dragon_coin_checks: 'false' - bowser_castle_doors: fast - bowser_castle_rooms: random_two_room - level_shuffle: 'true' - exclude_special_zone: 'false' - boss_shuffle: full - swap_donut_gh_exits: 'false' - display_received_item_popups: progression - trap_fill_percentage: 0 - ice_trap_weight: medium - stun_trap_weight: medium - literature_trap_weight: medium - timer_trap_weight: medium - autosave: 'true' - early_climb: 'false' - overworld_speed: fast - music_shuffle: none - mario_palette: waluigi - foreground_palette_shuffle: 'true' - background_palette_shuffle: 'true' - overworld_palette_shuffle: 'true' - starting_life_count: random -description: 'Generated by https://archipelago.gg/ for Super Mario World' -game: Super Mario World -name: DragusSMW diff --git a/disabled yamls/RC1/Fatman_Main.yaml b/disabled yamls/RC1/Fatman_Main.yaml deleted file mode 100644 index acceef167494..000000000000 --- a/disabled yamls/RC1/Fatman_Main.yaml +++ /dev/null @@ -1,444 +0,0 @@ -description: 'Me waiting for Silksong in AP (Its coming out this week I swear) :I' -name: Fatman -game: - Hollow Knight: 1 - Minecraft: 0 - Rogue Legacy: 0 - Super Mario 64: 0 - Factorio: 0 - Subnautica: 0 - Timespinner: 0 - The Witness: 0 -Hollow Knight: - RandomizeDreamers: - 'true': 25 - RandomizeSkills: - 'true': 25 - RandomizeFocus: - 'true': 25 - RandomizeSwim: - 'true': 25 - RandomizeElevatorPass: - 'true': 25 - RandomizeCharms: - 'true': 25 - RandomizeKeys: - 'true': 25 - RandomizeMaskShards: - 'true': 25 - RandomizeVesselFragments: - 'true': 25 - RandomizeCharmNotches: - 'true': 25 - RandomizePaleOre: - 'true': 25 - RandomizeGeoChests: - 'true': 25 - RandomizeJunkPitChests: - 'true': 25 - RandomizeRancidEggs: - 'true': 25 - RandomizeRelics: - 'true': 25 - RandomizeWhisperingRoots: - 'true': 25 - RandomizeBossEssence: - 'true': 25 - RandomizeGrubs: - 'true': 25 - RandomizeMimics: - 'true': 25 - RandomizeMaps: - 'true': 25 - RandomizeStags: - 'true': 25 - RandomizeLifebloodCocoons: - 'true': 25 - RandomizeGrimmkinFlames: - 'false': 25 - RandomizeJournalEntries: - 'true': 25 - RandomizeNail: - 'true': 25 - RandomizeGeoRocks: - 'false': 25 - RandomizeBossGeo: - 'true': 25 - RandomizeSoulTotems: - 'false': 25 - RandomizeLoreTablets: - 'false': 25 - PreciseMovement: - 'true': 25 - ProficientCombat: - 'true': 25 - BackgroundObjectPogos: - 'true': 25 - EnemyPogos: - 'true': 25 - ObscureSkips: - 'false': 25 - ShadeSkips: - 'false': 25 - InfectionSkips: - 'false': 25 - FireballSkips: - 'false': 25 - SpikeTunnels: - 'false': 25 - AcidSkips: - 'false': 25 - DamageBoosts: - 'false': 25 - DangerousSkips: - 'false': 25 - DarkRooms: - 'false': 25 - ComplexSkips: - 'false': 25 - DifficultSkips: - 'false': 25 - RemoveSpellUpgrades: - 'false': 25 - SplitCrystalHeart: - 'true': 25 - SplitMothwingCloak: - 'true': 25 - SplitMantisClaw: - 'true': 25 - StartLocation: - king's_pass: 25 - MinimumGrubPrice: - 5: 25 - MaximumGrubPrice: - 25: 25 - MinimumEssencePrice: - 400: 25 - MaximumEssencePrice: - 1600: 25 - MinimumEggPrice: - 3: 25 - MaximumEggPrice: - 10: 25 - MinimumCharmPrice: - 3: 25 - MaximumCharmPrice: - 20: 25 - MinimumGeoPrice: - 15: 1 - MaximumGeoPrice: - random-range-middle-200-750: 1 - RandomCharmCosts: - random-range-middle-60-110 - EggShopSlots: - random-range-middle-4-8 - SlyShopSlots: - random-range-middle-4-8 - SlyKeyShopSlots: - random-range-middle-6-10 - IseldaShopSlots: - random-range-middle-3-7 - SalubraShopSlots: - random-high: 1 - SalubraCharmShopSlots: - 1: 1 - LegEaterShopSlots: - random-range-middle-3-7: 1 - GrubfatherRewardSlots: - random-range-middle-3-10: 1 - SeerRewardSlots: - random: 1 - Goal: - radiance: 2 - hollowknight: 0 - WhitePalace: - include: 2 - kingfragment: 2 - DeathLink: - shade: 0 - off: 1 - progression_balancing: - 0: 1 - CostSanity: - true: 1 - CostSanityHybridChance: - random-range-low-3-20: 1 - CostSanityEggWeight: - random-range-low-15-30: 1 - CostSanityGrubWeight: - random-range-middle-35-65: 1 - CostSanityEssenceWeight: - random-range-middle-35-65: 1 - CostSanityCharmWeight: - random-range-low-15-30: 1 - CostSanityGeoWeight: - random-range-middle-100-160: 1 - accessibility: - items: 25 - priority_locations: [] - StartingGeo: - random-high: 1 - exclude_locations: ["Boss_Essence-Grey_Prince_Zote"] - local_items: ["Void_Heart", "Herrah"] - non_local_items: [] - start_hints: ["Monomon", "Lurien", "Queen_Fragment", "Upslash"] - start_location_hints: [] -Minecraft: - advancement_goal: - random-range-middle-45-55: 20 - egg_shards_required: - random-range-middle-15-20: 25 - egg_shards_available: - 30: 25 - required_bosses: - none: 25 - shuffle_structures: - 'true': 25 - structure_compasses: - 'false': 25 - bee_traps: - 15: 25 - combat_difficulty: - normal: 40 - include_hard_advancements: - 'false': 25 - include_unreasonable_advancements: - 'false': 25 - include_postgame_advancements: - 'false': 25 - send_defeated_mobs: - 'false': 25 - death_link: - 'false': 25 - progression_balancing: - 20: 1 - accessibility: - items: 25 - priority_locations: [] - start_inventory: {} - exclude_locations: - - "Caves & Cliffs" - - "Great View From Up Here" - local_items: [] - non_local_items: [] - start_hints: [] - start_location_hints: [] -Rogue Legacy: - starting_gender: random - starting_class: random - new_game_plus: normal - fairy_chests_per_zone: 5 - chests_per_zone: 18 - universal_fairy_chests: 'true' - universal_chests: 'false' - vendors: random - architect: normal - architect_fee: 70 - disable_charon: 'false' - require_purchasing: 'true' - progressive_blueprints: 'true' - gold_gain_multiplier: normal - number_of_children: 4 - free_diary_on_generation: 'true' - khidr: vanilla - alexander: vanilla - leon: vanilla - herodotus: vanilla - health_pool: 15 - mana_pool: 15 - attack_pool: 15 - magic_damage_pool: 15 - armor_pool: 10 - equip_pool: 10 - crit_chance_pool: 5 - crit_damage_pool: 5 - allow_default_names: 'true' - death_link: 'false' - progression_balancing: 35 - exclude_locations: - - Fairy Chest 7 - - Fairy Chest 8 - - Fairy Chest 9 - - Fairy Chest 10 - - Fairy Chest 11 - - Fairy Chest 12 - - Fairy Chest 13 - - Fairy Chest 14 - - Fairy Chest 15 - - Fairy Chest 16 - - Fairy Chest 17 - - Fairy Chest 18 - - Fairy Chest 19 - - Fairy Chest 20 - accessibility: items -Super Mario 64: - progression_balancing: 25 - accessibility: items - AreaRandomizer: courses_and_secrets - ProgressiveKeys: 'true' - EnableCoinStars: 'false' - AmountOfStars: 120 - StrictCapRequirements: 'true' - StrictCannonRequirements: 'true' - FirstBowserStarDoorCost: random-range-middle-6-15 - BasementStarDoorCost: random-range-middle-20-40 - SecondFloorStarDoorCost: random-range-middle-40-60 - MIPS1Cost: random-range-middle-10-20 - MIPS2Cost: 50 - StarsToFinish: 60 - death_link: 'false' - BuddyChecks: 'true' -Factorio: - accessibility: items - max_science_pack: production_science_pack - goal: rocket - tech_tree_layout: random - tech_cost: kind - silo: randomize_recipe - satellite: randomize_recipe - free_samples: single_craft - tech_tree_information: advancement - recipe_time: normal - recipe_ingredients: science_pack - imported_blueprints: 'true' - progressive: on - evolution_traps: 0 - attack_traps: 0 - evolution_trap_increase: 10 - starting_items: # Mapping of Factorio internal item-name to amount granted on start. - burner-mining-drill: 10 - stone-furnace: 10 - world_gen: # World Generation settings. Overview of options at https://wiki.factorio.com/Map_generator, - # with in-depth documentation at https://lua-api.factorio.com/latest/Concepts.html#MapGenSettings - autoplace_controls: - coal: - frequency: 1 - richness: 6 - size: 3 - copper-ore: - frequency: 1 - richness: 6 - size: 3 - crude-oil: - frequency: 1 - richness: 6 - size: 3 - enemy-base: - frequency: 1 - richness: 1 - size: 1 - iron-ore: - frequency: 1 - richness: 6 - size: 3 - stone: - frequency: 1 - richness: 6 - size: 3 - trees: - frequency: 1 - richness: 1 - size: 1 - uranium-ore: - frequency: 1 - richness: 6 - size: 3 - cliff_settings: - cliff_elevation_0: 10 - cliff_elevation_interval: 40 - name: cliff - richness: 1 - enemy_evolution: - destroy_factor: 0.002 - enabled: true - pollution_factor: 9.0e-07 - time_factor: 4.0e-06 - enemy_expansion: - enabled: true - max_expansion_cooldown: 216000 - max_expansion_distance: 7 - min_expansion_cooldown: 14400 - settler_group_max_size: 20 - settler_group_min_size: 5 - peaceful_mode: false - pollution: - ageing: 1 - diffusion_ratio: 0.02 - enabled: true - enemy_attack_pollution_consumption_modifier: 1 - min_pollution_to_damage_trees: 60 - pollution_restored_per_tree_damage: 10 - property_expression_names: - control-setting:aux:bias: 0 - control-setting:aux:frequency:multiplier: 1 - control-setting:moisture:bias: 0 - control-setting:moisture:frequency:multiplier: 1 - seed: null - starting_area: 1.5 - terrain_segmentation: 0.5 - water: 1.5 - progression_balancing: 30 - death_link: 'false' - energy_link: 'false' -Subnautica: - progression_balancing: 25 - accessibility: items - swim_rule: easy - early_seaglide: 'true' - item_pool: valuable - goal: infected - creature_scans: 15 - creature_scan_logic: either - death_link: 'false' - start_inventory: - Seamoth Fragment: 1 -Timespinner: - progression_balancing: 30 - accessibility: items - StartWithJewelryBox: 'true' - DownloadableItems: 'true' - EyeSpy: 'false' - StartWithMeyef: 'false' - QuickSeed: 'false' - SpecificKeycards: 'true' - Inverted: - random: 1 - GyreArchives: 'false' - Cantoran: 'true' - LoreChecks: 'true' - BossRando: 'true' - BossScaling: 'true' - DamageRando: balanced - HpCap: 999 - BossHealing: 'true' - ShopFill: randomized - ShopWarpShards: 'true' - ShopMultiplier: 1 - LootPool: randomized - DropRateCategory: tiered - FixedDropRate: 5 - LootTierDistro: default_weight - ShowBestiary: 'true' - ShowDrops: 'false' - EnterSandman: 'false' - DeathLink: 'false' -The Witness: - progression_balancing: 50 - accessibility: items - puzzle_randomization: sigma_normal - shuffle_symbols: 'true' - shuffle_doors: doors_complex - shuffle_lasers: 'true' - disable_non_randomized_puzzles: 'false' - shuffle_discarded_panels: 'true' - shuffle_vault_boxes: 'true' - shuffle_postgame: 'false' - victory_condition: mountain_box_short - mountain_lasers: 7 - challenge_lasers: 8 - early_secret_area: 'false' - trap_percentage: 25 - puzzle_skip_amount: 9 - hint_amount: 10 - death_link: 'true' - local_items: ["Lasers"] \ No newline at end of file diff --git a/disabled yamls/RC1/Figment-SDV-4xx-MA.yaml b/disabled yamls/RC1/Figment-SDV-4xx-MA.yaml deleted file mode 100644 index 4e2c20801d93..000000000000 --- a/disabled yamls/RC1/Figment-SDV-4xx-MA.yaml +++ /dev/null @@ -1,190 +0,0 @@ -description: NO FARM, ONLY FISH! -name: Figment{NUMBER} -game: Stardew Valley -requires: - version: 0.4.2 - plando: items -Stardew Valley: - progression_balancing: 50 - accessibility: items - goal: master_angler - starting_money: -1 - profit_margin: 400 - bundle_randomization: vanilla - bundle_price: very_cheap - entrance_randomization: disabled - season_randomization: randomized - cropsanity: disabled - backpack_progression: vanilla - tool_progression: progressive - skill_progression: progressive - building_progression: vanilla - festival_locations: disabled - elevator_progression: progressive - arcade_machine_locations: disabled - special_order_locations: disabled - help_wanted_locations: 0 - fishsanity: all - museumsanity: milestones - friendsanity: none - friendsanity_heart_size: 4 - movement_buff_number: 0 - luck_buff_number: 12 - exclude_ginger_island: true - trap_items: no_traps - multiple_day_sleep_enabled: true - multiple_day_sleep_cost: 0 - experience_multiplier: 800 - friendship_multiplier: 800 - debris_multiplier: start_clear - quick_start: true - gifting: true - mods: [] - death_link: false - start_inventory: {Return Scepter: 1} - exclude_locations: - - A Soldier's Star - - Animal Bundle - - Artisan Bundle - - Carving Pumpkins - - Chef's Bundle - - Complete Bulletin Board - - Complete Pantry - - Cow's Delight - - Crop Research - - Cryptic Note - - Dye Bundle - - Enchanter's Bundle - - Exotic Spirits - - Fall Crops Bundle - - Floor 105 Elevator - - Floor 110 Elevator - - Fresh Fruit - - Galaxy Sword Shrine - - Have Another Baby - - Have a Baby - - Iridium Axe Upgrade - - Iridium Hoe Upgrade - - Iridium Pickaxe Upgrade - - Iridium Trash Can Upgrade - - Iridium Watering Can Upgrade - - Jodi's Request - - Knee Therapy - - Magic Ink - - Mayor's "Shorts" - - Mayor's Need - - 'Museumsanity: 3 Artifacts' - - 'Museumsanity: 5 Donations' - - 'Museumsanity: 6 Artifacts' - - 'Museumsanity: 9 Artifacts' - - 'Museumsanity: 11 Artifacts' - - 'Museumsanity: 11 Minerals' - - 'Museumsanity: 15 Artifacts' - - 'Museumsanity: 15 Donations' - - 'Museumsanity: 20 Artifacts' - - Old Master Cannoli - - Pam Is Thirsty - - Pam Needs Juice - - Qi's Challenge - - Quality Crops Bundle - - Spring Crops Bundle - - Staff Of Power - - Strange Note - - Summer Crops Bundle - - The Mines Floor 110 Treasure - - The Mysterious Qi - plando_items: - # Skills - - items: - Combat Level: 10 - locations: - - Level 1 Combat - - Level 2 Combat - - Level 3 Combat - - Level 4 Combat - - Level 5 Combat - - Level 6 Combat - - Level 7 Combat - - Level 8 Combat - - Level 9 Combat - - Level 10 Combat - - items: - Farming Level: 10 - locations: - - Level 1 Farming - - Level 2 Farming - - Level 3 Farming - - Level 4 Farming - - Level 5 Farming - - Level 6 Farming - - Level 7 Farming - - Level 8 Farming - - Level 9 Farming - - Level 10 Farming - - items: - Foraging Level: 10 - locations: - - Level 1 Foraging - - Level 2 Foraging - - Level 3 Foraging - - Level 4 Foraging - - Level 5 Foraging - - Level 6 Foraging - - Level 7 Foraging - - Level 8 Foraging - - Level 9 Foraging - - Level 10 Foraging - - items: - Mining Level: 10 - locations: - - Level 1 Mining - - Level 2 Mining - - Level 3 Mining - - Level 4 Mining - - Level 5 Mining - - Level 6 Mining - - Level 7 Mining - - Level 8 Mining - - Level 9 Mining - - Level 10 Mining - # Vanilla Museum - - item: - Ancient Seeds Recipe: 1 - location: 'Museumsanity: Ancient Seed' - - item: - Dwarvish Translation Guide: 1 - location: 'Museumsanity: Dwarf Scrolls' - # Filler Museum - - items: - Ancient Seeds: 5 - Magic Rock Candy: 5 - Traveling Merchant Discount: 8 - locations: - - 'Museumsanity: 20 Donations' - - 'Museumsanity: 21 Minerals' - - 'Museumsanity: 25 Donations' - - 'Museumsanity: 30 Donations' - - 'Museumsanity: 31 Minerals' - - 'Museumsanity: 35 Donations' - - 'Museumsanity: 40 Donations' - - 'Museumsanity: 41 Minerals' - - 'Museumsanity: 50 Donations' - - 'Museumsanity: 50 Minerals' - - 'Museumsanity: 60 Donations' - - 'Museumsanity: 70 Donations' - - 'Museumsanity: 80 Donations' - - 'Museumsanity: 90 Donations' - - 'Museumsanity: 95 Donations' - - 'Museumsanity: Skeleton Back' - - 'Museumsanity: Skeleton Front' - - 'Museumsanity: Skeleton Middle' - # Mines - - item: - Rusty Sword: 1 - location: Floor 115 Elevator - - item: - Slingshot: 1 - location: Floor 120 Elevator - - item: - Master Slingshot: 1 - location: The Mines Floor 120 Treasure \ No newline at end of file diff --git a/disabled yamls/RC1/Forsaken_Terraria.yaml b/disabled yamls/RC1/Forsaken_Terraria.yaml deleted file mode 100644 index d86ba60d4aea..000000000000 --- a/disabled yamls/RC1/Forsaken_Terraria.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# Q. What is this file? -# A. This file contains options which allow you to configure your multiworld experience while allowing -# others to play how they want as well. -# -# Q. How do I use it? -# A. The options in this file are weighted. This means the higher number you assign to a value, the -# more chances you have for that option to be chosen. For example, an option like this: -# -# map_shuffle: -# on: 5 -# off: 15 -# -# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned -# off. -# -# Q. I've never seen a file like this before. What characters am I allowed to use? -# A. This is a .yaml file. You are allowed to use most characters. -# To test if your yaml is valid or not, you can use this website: -# http://www.yamllint.com/ -# You can also verify your Archipelago settings are valid at this site: -# https://archipelago.gg/check - -# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. -# {player} will be replaced with the player's slot number. -# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. -# {number} will be replaced with the counter value of the name. -# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. -name: Forsaken - -# Used to describe your yaml. Useful if you have multiple files. -description: Default Terraria Template - -game: Terraria -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -Terraria: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 50 # equivalent to 50 - extreme: 0 # equivalent to 99 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - {} - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - goal: - # The victory condition for your run. Stuff after the goal will not be shuffled. - mechanical_bosses: 0 - plantera: 0 - golem: 0 - empress_of_light: 0 - lunatic_cultist: 0 - moon_lord: 50 - zenith: 0 - - achievements: - # Adds checks upon collecting achievements. Achievements for clearing bosses and events are excluded. - # "Exclude Grindy" also excludes fishing achievements. - none: 50 - exclude_grindy: 0 - exclude_fishing: 0 - all: 0 - - fill_extra_checks_with: - # Applies if you have achievements enabled. "Useful Items" helps to make the early game less grindy. - # Items are rewarded to all players in your Terraria world. - coins: 0 - useful_items: 50 - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 50 - true: 0 diff --git a/disabled yamls/RC1/KenderUT_Neutral.yaml b/disabled yamls/RC1/KenderUT_Neutral.yaml deleted file mode 100644 index c45d150dbc5a..000000000000 --- a/disabled yamls/RC1/KenderUT_Neutral.yaml +++ /dev/null @@ -1,17 +0,0 @@ -Undertale: - progression_balancing: 50 - accessibility: items - route_required: neutral - key_hunt: random - key_pieces: 5 - rando_love: 'false' - rando_stats: 'false' - temy_include: 'true' - no_equips: 'false' - only_flakes: 'false' - prog_armor: 'false' - prog_weapons: 'false' - rando_item_button: 'true' -description: 'Generated by https://archipelago.gg/ for Undertale' -game: Undertale -name: KenderUT diff --git a/disabled yamls/RC1/Parker.yaml b/disabled yamls/RC1/Parker.yaml deleted file mode 100644 index d17640ebc877..000000000000 --- a/disabled yamls/RC1/Parker.yaml +++ /dev/null @@ -1,24 +0,0 @@ -The Witness: - progression_balancing: 50 - accessibility: items - puzzle_randomization: sigma_normal - shuffle_symbols: 'true' - shuffle_doors: max - shuffle_lasers: 'false' - disable_non_randomized_puzzles: 'false' - shuffle_discarded_panels: 'true' - shuffle_vault_boxes: 'true' - shuffle_EPs: individual - EP_difficulty: normal - shuffle_postgame: 'true' - victory_condition: challenge - mountain_lasers: 7 - challenge_lasers: 11 - early_secret_area: 'false' - trap_percentage: 0 - puzzle_skip_amount: 30 - hint_amount: 49 - death_link: 'true' -description: 'Generated by https://archipelago.gg/ for The Witness' -game: The Witness -name: Parker diff --git a/disabled yamls/RC1/Phar.yaml b/disabled yamls/RC1/Phar.yaml deleted file mode 100644 index 210f28fbdc52..000000000000 --- a/disabled yamls/RC1/Phar.yaml +++ /dev/null @@ -1,504 +0,0 @@ -# What is this file? -# This file contains options which allow you to configure your multiworld experience while allowing others -# to play how they want as well. - -# How do I use it? -# The options in this file are weighted. This means the higher number you assign to a value, the more -# chances you have for that option to be chosen. For example, an option like this: -# -# map_shuffle: -# on: 5 -# off: 15 -# -# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned off - -# I've never seen a file like this before. What characters am I allowed to use? -# This is a .yaml file. You are allowed to use most characters. -# To test if your yaml is valid or not, you can use this website: -# http://www.yamllint.com/ - -description: Template Name # Used to describe your yaml. Useful if you have multiple files -name: Phar # Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit -#{player} will be replaced with the player's slot number. -#{PLAYER} will be replaced with the player's slot number if that slot number is greater than 1. -#{number} will be replaced with the counter value of the name. -#{NUMBER} will be replaced with the counter value of the name if the counter value is greater than 1. -game: # Pick a game to play - A Link to the Past: 1 -requires: - version: 0.3.3 # Version of Archipelago required for this yaml to work as expected. -A Link to the Past: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 0 # equivalent to 50 - extreme: 0 # equivalent to 99 - 15: 5 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [ ] - - non_local_items: - # Forces these items to be outside their native world. - [ ] - - start_inventory: - # Start with these items. - { } - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [ ] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [ ] - - exclude_locations: - # Prevent these locations from having an important item - [ ] - - priority_locations: - # Prevent these locations from having an unimportant item - [ ] - - item_links: - # Share part of your item pool with other players. - [ ] - - ### Logic Section ### - glitches_required: # Determine the logic required to complete the seed - none: 0 # No glitches required - minor_glitches: 50 # Puts fake flipper, waterwalk, super bunny shenanigans, and etc into logic - overworld_glitches: 0 # Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches - hybrid_major_glitches: 0 # In addition to overworld glitches, also requires underworld clips between dungeons. - no_logic: 0 # Your own items are placed with no regard to any logic; such as your Fire Rod can be on your Trinexx. - # Other players items are placed into your world under HMG logic - dark_room_logic: # Logic for unlit dark rooms - lamp: 50 # require the Lamp for these rooms to be considered accessible. - torches: 0 # in addition to lamp, allow the fire rod and presence of easily accessible torches for access - none: 0 # all dark rooms are always considered doable, meaning this may force completion of rooms in complete darkness - restrict_dungeon_item_on_boss: # aka ambrosia boss items - on: 0 # prevents unshuffled compasses, maps and keys to be boss drops, they can still drop keysanity and other players' items - off: 50 - ### End of Logic Section ### - bigkey_shuffle: # Big Key Placement - original_dungeon: 0 - own_dungeons: 0 - own_world: 0 - any_world: 50 - different_world: 0 - start_with: 0 - smallkey_shuffle: # Small Key Placement - original_dungeon: 50 - own_dungeons: 0 - own_world: 0 - any_world: 0 - different_world: 0 - universal: 0 - start_with: 0 - compass_shuffle: # Compass Placement - original_dungeon: 0 - own_dungeons: 0 - own_world: 0 - any_world: 0 - different_world: 0 - start_with: 50 - map_shuffle: # Map Placement - original_dungeon: 0 - own_dungeons: 0 - own_world: 0 - any_world: 0 - different_world: 0 - start_with: 50 - dungeon_counters: - on: 0 # Always display amount of items checked in a dungeon - pickup: 50 # Show when compass is picked up - default: 0 # Show when compass is picked up if the compass itself is shuffled - off: 0 # Never show item count in dungeons - progressive: # Enable or disable progressive items (swords, shields, bow) - on: 50 # All items are progressive - off: 0 # No items are progressive - grouped_random: 0 # Randomly decides for all items. Swords could be progressive, shields might not be - entrance_shuffle: - none: 50 # Vanilla game map. All entrances and exits lead to their original locations. You probably want this option - dungeonssimple: 0 # Shuffle just dungeons amongst each other, swapping dungeons entirely, so Hyrule Castle is always 1 dungeon - dungeonsfull: 0 # Shuffle any dungeon entrance with any dungeon interior, so Hyrule Castle can be 4 different dungeons, but keep dungeons to a specific world - dungeonscrossed: 0 # like dungeonsfull, but allow cross-world traversal through a dungeon. Warning: May force repeated dungeon traversal - simple: 0 # Entrances are grouped together before being randomized. Simple uses the most strict grouping rules - restricted: 0 # Less strict than simple - full: 0 # Less strict than restricted - crossed: 0 # Less strict than full - insanity: 0 # Very few grouping rules. Good luck - # you can also define entrance shuffle seed, like so: - crossed-1000: 0 # using this method, you can have the same layout as another player and share entrance information - # however, many other settings like logic, world state, retro etc. may affect the shuffle result as well. - crossed-group-myfriends: 0 # using this method, everyone with "group-myfriends" will share the same seed - goals: - ganon: 0 # Climb GT, defeat Agahnim 2, and then kill Ganon - crystals: 50 # Only killing Ganon is required. However, items may still be placed in GT - bosses: 0 # Defeat the boss of all dungeons, including Agahnim's tower and GT (Aga 2) - pedestal: 0 # Pull the Triforce from the Master Sword pedestal - ganon_pedestal: 0 # Pull the Master Sword pedestal, then kill Ganon - triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then turn them in to Murahadala in front of Hyrule Castle - local_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout your world, then turn them in to Murahadala in front of Hyrule Castle - ganon_triforce_hunt: 0 # Collect 20 of 30 Triforce pieces spread throughout the worlds, then kill Ganon - local_ganon_triforce_hunt: 50 # Collect 20 of 30 Triforce pieces spread throughout your world, then kill Ganon - ice_rod_hunt: 0 # You start with everything needed to 216 the seed. Find the Ice rod, then kill Trinexx at Turtle rock. - open_pyramid: - goal: 50 # Opens the pyramid if the goal requires you to kill Ganon, unless the goal is Slow Ganon or All Dungeons - auto: 0 # Same as Goal, but also is closed if holes are shuffled and ganon is part of the shuffle pool - open: 0 # Pyramid hole is always open. Ganon's vulnerable condition is still required before he can he hurt - closed: 0 # Pyramid hole is always closed until you defeat Agahnim atop Ganon's Tower - triforce_pieces_mode: #Determine how to calculate the extra available triforce pieces. - extra: 50 # available = triforce_pieces_extra + triforce_pieces_required - percentage: 0 # available = (triforce_pieces_percentage /100) * triforce_pieces_required - available: 0 # available = triforce_pieces_available - triforce_pieces_extra: # Set to how many extra triforces pieces are available to collect in the world. - # Format "pieces: chance" - 0: 0 - 5: 50 - 10: 50 - 15: 0 - 20: 0 - triforce_pieces_percentage: # Set to how many triforce pieces according to a percentage of the required ones, are available to collect in the world. - # Format "pieces: chance" - 100: 0 #No extra - 150: 50 #Half the required will be added as extra - 200: 0 #There are the double of the required ones available. - triforce_pieces_available: # Set to how many triforces pieces are available to collect in the world. Default is 30. Max is 90, Min is 1 - # Format "pieces: chance" - 25: 0 - 30: 50 - 40: 0 - 50: 0 - triforce_pieces_required: # Set to how many out of X triforce pieces you need to win the game in a triforce hunt. Default is 20. Max is 90, Min is 1 - # Format "pieces: chance" - 15: 50 - 20: 50 - 30: 50 - 40: 0 - 50: 0 - crystals_needed_for_gt: # Crystals required to open GT - 0: 0 - random-range-2-5: 50 - random: 0 - random-low: 0 # any valid number, weighted towards the lower end - random-middle: 0 # any valid number, weighted towards the central range - random-high: 0 # any valid number, weighted towards the higher end - crystals_needed_for_ganon: # Crystals required to hurt Ganon - 0: 0 - random-range-4-7: 50 - random: 0 - random-low: 0 - random-middle: 0 - random-high: 0 - mode: - standard: 0 # Begin the game by rescuing Zelda from her cell and escorting her to the Sanctuary - open: 50 # Begin the game from your choice of Link's House or the Sanctuary - inverted: 0 # Begin in the Dark World. The Moon Pearl is required to avoid bunny-state in Light World, and the Light World game map is altered - retro_bow: - on: 0 # Zelda-1 like mode. You have to purchase a quiver to shoot arrows using rupees. - off: 50 - retro_caves: - on: 0 # Zelda-1 like mode. There are randomly placed take-any caves that contain one Sword and choices of Heart Container/Blue Potion. - off: 50 - hints: # On/Full: Put item and entrance placement hints on telepathic tiles and some NPCs, Full removes joke hints. - 'on': 50 - 'off': 0 - full: 0 - scams: # If on, these Merchants will no longer tell you what they're selling. - 'off': 50 - 'king_zora': 0 - 'bottle_merchant': 0 - 'all': 0 - swordless: - on: 2 # Your swords are replaced by rupees. Gameplay changes have been made to accommodate this change - off: 8 - item_pool: - easy: 0 # Doubled upgrades, progressives, and etc - normal: 50 # Item availability remains unchanged from vanilla game - hard: 50 # Reduced upgrade availability (max: 14 hearts, blue mail, tempered sword, fire shield, no silvers unless swordless) - expert: 0 # Minimum upgrade availability (max: 8 hearts, green mail, master sword, fighter shield, no silvers unless swordless) - item_functionality: - easy: 0 # Allow Hammer to damage ganon, Allow Hammer tablet collection, Allow swordless medallion use everywhere. - normal: 50 # Vanilla item functionality - hard: 0 # Reduced helpfulness of items (potions less effective, can't catch faeries, cape uses double magic, byrna does not grant invulnerability, boomerangs do not stun, silvers disabled outside ganon) - expert: 0 # Vastly reduces the helpfulness of items (potions barely effective, can't catch faeries, cape uses double magic, byrna does not grant invulnerability, boomerangs and hookshot do not stun, silvers disabled outside ganon) - tile_shuffle: # Randomize the tile layouts in flying tile rooms - on: 0 - off: 50 - misery_mire_medallion: # required medallion to open Misery Mire front entrance - random: 50 - Ether: 0 - Bombos: 0 - Quake: 0 - turtle_rock_medallion: # required medallion to open Turtle Rock front entrance - random: 50 - Ether: 0 - Bombos: 0 - Quake: 0 - ### Enemizer Section ### - boss_shuffle: - none: 50 # Vanilla bosses - basic: 0 # Existing bosses except Ganon and Agahnim are shuffled throughout dungeons - full: 0 # 3 bosses can occur twice - chaos: 0 # Any boss can appear any amount of times - singularity: 0 # Picks a boss, tries to put it everywhere that works, if there's spaces remaining it picks a boss to fill those - enemy_shuffle: # Randomize enemy placement - on: 0 - off: 50 - killable_thieves: # Make thieves killable - on: 0 # Usually turned on together with enemy_shuffle to make annoying thief placement more manageable - off: 50 - bush_shuffle: # Randomize the chance that bushes have enemies and the enemies under said bush - on: 0 - off: 50 - enemy_damage: - default: 50 # Vanilla enemy damage - shuffled: 0 # Enemies deal 0 to 4 hearts and armor helps - chaos: 0 # Enemies deal 0 to 8 hearts and armor just reshuffles the damage - enemy_health: - default: 50 # Vanilla enemy HP - easy: 0 # Enemies have reduced health - hard: 0 # Enemies have increased health - expert: 0 # Enemies have greatly increased health - pot_shuffle: - 'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile - 'off': 50 # Default pot item locations - ### End of Enemizer Section ### - ### Beemizer ### - # can add weights for any whole number between 0 and 100 - beemizer_total_chance: # Remove items from the global item pool and replace them with single bees (fill bottles) and bee traps - 0: 0 # No junk fill items are replaced (Beemizer is off) - 25: 50 # 25% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees - 50: 0 # 50% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees - 75: 0 # 75% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees - 100: 0 # All junk fill items (rupees, bombs and arrows) are replaced with bees - beemizer_trap_chance: - 60: 50 # 60% chance for each beemizer replacement to be a trap, 40% chance to be a single bee - 70: 0 # 70% chance for each beemizer replacement to be a trap, 30% chance to be a single bee - 80: 0 # 80% chance for each beemizer replacement to be a trap, 20% chance to be a single bee - 90: 0 # 90% chance for each beemizer replacement to be a trap, 10% chance to be a single bee - 100: 0 # All beemizer replacements are traps - ### Shop Settings ### - shop_item_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl) - 0: 50 - 5: 0 - 15: 0 - 30: 0 - random: 0 # 0 to 30 evenly distributed - shop_price_modifier: # Percentage modifier for shuffled item prices in shops - # you can add additional values between minimum and maximum - 0: 0 # minimum value - 400: 0 # maximum value - random: 0 - random-low: 0 - random-high: 0 - 100: 50 - shop_shuffle: - none: 50 - g: 0 # Generate new default inventories for overworld/underworld shops, and unique shops - f: 0 # Generate new default inventories for every shop independently - i: 0 # Shuffle default inventories of the shops around - p: 0 # Randomize the prices of the items in shop inventories - u: 0 # Shuffle capacity upgrades into the item pool (and allow them to traverse the multiworld) - w: 0 # Consider witch's hut like any other shop and shuffle/randomize it too - P: 0 # Prices of the items in shop inventories cost hearts, arrow, or bombs instead of rupees - ip: 0 # Shuffle inventories and randomize prices - fpu: 0 # Generate new inventories, randomize prices and shuffle capacity upgrades into item pool - uip: 0 # Shuffle inventories, randomize prices and shuffle capacity upgrades into the item pool - # You can add more combos - ### End of Shop Section ### - shuffle_prizes: # aka drops - none: 0 # do not shuffle prize packs - g: 50 # shuffle "general" prize packs, as in enemy, tree pull, dig etc. - b: 0 # shuffle "bonk" prize packs - bg: 0 # shuffle both - timer: - none: 50 # No timer will be displayed. - timed: 0 # Starts with clock at zero. Green clocks subtract 4 minutes (total 20). Blue clocks subtract 2 minutes (total 10). Red clocks add two minutes (total 10). Winner is the player with the lowest time at the end. - timed_ohko: 0 # Starts the clock at ten minutes. Green clocks add five minutes (total 25). As long as the clock as at zero, Link will die in one hit. - ohko: 0 # Timer always at zero. Permanent OHKO. - timed_countdown: 0 # Starts the clock with forty minutes. Same clocks as timed mode, but if the clock hits zero you lose. You can still keep playing, though. - display: 0 # Displays a timer, but otherwise does not affect gameplay or the item pool. - countdown_start_time: # For timed_ohko and timed_countdown timer modes, the amount of time in minutes to start with - 0: 0 # For timed_ohko, starts in OHKO mode when starting the game - 10: 50 - 20: 0 - 30: 0 - 60: 0 - red_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a red clock - -2: 50 - 1: 0 - blue_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a blue clock - 1: 0 - 2: 50 - green_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a green clock - 4: 50 - 10: 0 - 15: 0 - glitch_boots: - on: 50 # Start with Pegasus Boots in any glitched logic mode that makes use of them - off: 0 - # rom options section - random_sprite_on_event: # An alternative to specifying randomonhit / randomonexit / etc... in sprite down below. - enabled: # If enabled, sprite down below is ignored completely, (although it may become the sprite pool) - on: 0 - off: 1 - on_hit: # Random sprite on hit. Being hit by things that cause 0 damage still counts. - on: 1 - off: 0 - on_enter: # Random sprite on underworld entry. Note that entering hobo counts. - on: 0 - off: 1 - on_exit: # Random sprite on underworld exit. Exiting hobo does not count. - on: 0 - off: 1 - on_slash: # Random sprite on sword slash. Note, it still counts if you attempt to slash while swordless. - on: 0 - off: 1 - on_item: # Random sprite on getting an item. Anything that causes you to hold an item above your head counts. - on: 0 - off: 1 - on_bonk: # Random sprite on bonk. - on: 0 - off: 1 - on_everything: # Random sprite on ALL currently implemented events, even if not documented at present time. - on: 0 - off: 1 - use_weighted_sprite_pool: # Always on if no sprite_pool exists, otherwise it controls whether to use sprite as a weighted sprite pool - on: 0 - off: 1 - #sprite_pool: # When specified, limits the pool of sprites used for randomon-event to the specified pool. Uncomment to use this. - # - link - # - pride link - # - penguin link - # - random # You can specify random multiple times for however many potentially unique random sprites you want in your pool. - sprite: # Enter the name of your preferred sprite and weight it appropriately - random: 0 - randomonhit: 0 # Random sprite on hit - randomonenter: 0 # Random sprite on entering the underworld. - randomonexit: 0 # Random sprite on exiting the underworld. - randomonslash: 0 # Random sprite on sword slashes - randomonitem: 0 # Random sprite on getting items. - randomonbonk: 0 # Random sprite on bonk. - # You can combine these events like this. randomonhit-enter-exit if you want it on hit, enter, exit. - randomonall: 0 # Random sprite on any and all currently supported events. Refer to above for the supported events. - Lucario: 50 # To add other sprites: open the gui/Creator, go to adjust, select a sprite and write down the name the gui calls it - music: # If "off", all in-game music will be disabled - on: 50 - off: 0 - quickswap: # Enable switching items by pressing the L+R shoulder buttons - on: 50 - off: 0 - triforcehud: # Disable visibility of the triforce hud unless collecting a piece or speaking to Murahadala - normal: 0 # original behavior (always visible) - hide_goal: 0 # hide counter until a piece is collected or speaking to Murahadala - hide_required: 0 # Always visible, but required amount is invisible until determined by Murahadala - hide_both: 50 # Hide both under above circumstances - reduceflashing: # Reduces instances of flashing such as lightning attacks, weather, ether and more. - on: 50 - off: 0 - menuspeed: # Controls how fast the item menu opens and closes - normal: 50 - instant: 0 - double: 0 - triple: 0 - quadruple: 0 - half: 0 - heartcolor: # Controls the color of your health hearts - red: 50 - blue: 0 - green: 0 - yellow: 0 - random: 0 - heartbeep: # Controls the frequency of the low-health beeping - double: 0 - normal: 50 - half: 0 - quarter: 0 - off: 0 - ow_palettes: # Change the colors of the overworld - default: 0 # No changes - good: 50 # Shuffle the colors, with harmony in mind - blackout: 0 # everything black / blind mode - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - uw_palettes: # Change the colors of caves and dungeons - default: 0 # No changes - good: 50 # Shuffle the colors, with harmony in mind - blackout: 0 # everything black / blind mode - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - hud_palettes: # Change the colors of the hud - default: 0 # No changes - good: 50 # Shuffle the colors, with harmony in mind - blackout: 0 # everything black / blind mode - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - sword_palettes: # Change the colors of swords - default: 0 # No changes - good: 50 # Shuffle the colors, with harmony in mind - blackout: 0 # everything black / blind mode - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - shield_palettes: # Change the colors of shields - default: 0 # No changes - good: 50 # Shuffle the colors, with harmony in mind - blackout: 0 # everything black / blind mode - grayscale: 0 - negative: 0 - classic: 0 - dizzy: 0 - sick: 0 - puke: 0 - - death_link: - false: 50 - true: 0 - - allow_collect: # Allows for !collect / co-op to auto-open chests containing items for other players. - # Off by default, because it currently crashes on real hardware. - false: 0 - true: 50 ---- -name: Pharlique -game: Clique -Clique: - hard_mode: true - color: random \ No newline at end of file diff --git a/disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml b/disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml deleted file mode 100644 index ea413ff7fde8..000000000000 --- a/disabled yamls/RC1/Purple_Peak_SMZ3_early_sword_early_sword_normal.yaml +++ /dev/null @@ -1,19 +0,0 @@ -SMZ3: - progression_balancing: 50 - accessibility: items - sm_logic: normal - sword_location: early - morph_location: early - goal: defeatboth - key_shuffle: none - open_tower: 7 - ganon_vulnerable: 7 - open_tourian: 4 - spin_jumps_animation: 'false' - heart_beep_speed: half - heart_color: blue - quick_swap: 'false' - energy_beep: 'true' -description: 'Generated by https://archipelago.gg/' -game: SMZ3 -name: Purple Peak diff --git a/disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml b/disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml deleted file mode 100644 index 5ee2a397c5de..000000000000 --- a/disabled yamls/RC1/RiversHappyMusicAndViciousDemons.yaml +++ /dev/null @@ -1,279 +0,0 @@ -# Q. What is this file? -# A. This file contains options which allow you to configure your multiworld experience while allowing -# others to play how they want as well. -# -# Q. How do I use it? -# A. The options in this file are weighted. This means the higher number you assign to a value, the -# more chances you have for that option to be chosen. For example, an option like this: -# -# map_shuffle: -# on: 5 -# off: 15 -# -# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned -# off. -# -# Q. I've never seen a file like this before. What characters am I allowed to use? -# A. This is a .yaml file. You are allowed to use most characters. -# To test if your yaml is valid or not, you can use this website: -# http://www.yamllint.com/ -# You can also verify your Archipelago settings are valid at this site: -# https://archipelago.gg/check - -# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. -# {player} will be replaced with the player's slot number. -# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. -# {number} will be replaced with the counter value of the name. -# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. -name: DoomedRivers - -# Used to describe your yaml. Useful if you have multiple files. -description: Default DOOM 1993 Template - -game: DOOM 1993 -requires: - version: 0.4.0 # Version of Archipelago required for this yaml to work as expected. - -DOOM 1993: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 1 # equivalent to 50 - extreme: 0 # equivalent to 99 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - difficulty: - # Choose the difficulty option. Those match DOOM's difficulty options. - # baby (I'm too young to die.) double ammos, half damage, less monsters or strength. - # easy (Hey, not too rough.) less monsters or strength. - # medium (Hurt me plenty.) Default. - # hard (Ultra-Violence.) More monsters or strength. - # nightmare (Nightmare!) Monsters attack more rapidly and respawn. - baby: 0 - easy: 0 - medium: 1 - hard: 0 - nightmare: 0 - - random_monsters: - # Choose how monsters are randomized. - # vanilla: No randomization - # shuffle: Monsters are shuffled within the level - # random_balanced: Monsters are completely randomized, but balanced based on existing ratio in the level. (Small monsters vs medium vs big) - vanilla: 0 - shuffle: 0 - random_balanced: 1 - - random_items: - # Choose how items are randomized. - # vanilla: No randomization - # shuffle: Items are shuffled within the level - # random_balanced: Items are completely randomized, but balanced based on existing ratio in the level. (Small item vs Big) - vanilla: 0 - shuffle: 0 - random_balanced: 1 - - allow_death_logic: - # Some locations require a timed puzzle that can only be tried once. - # After which if the player failed to get it, the location cannot be checked anymore. - # No progression items are placed in those are. There is a way, hovewer, to still get them: - # Get killed in the current map. The map will reset, you can now attempt the puzzle again. - false: 50 - true: 0 - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 50 - true: 0 - - episode1: - # Knee-Deep in the Dead - false: 0 - true: 50 - - episode2: - # The Shores of Hell - false: 0 - true: 1 - - episode3: - # Inferno - false: 1 - true: 0 - - start_with_computer_area_maps: - # Give the player all Computer Area Map items from the start. - false: 0 - true: 1 - ---- - -Muse Dash: - progression_balancing: 0 - accessibility: items - available_trap_types: all - # Activates deathlink... you know you want to. - # Default: off - death_link: off - - # How many songs you can start out with. - # Note: Starting songs are first in line to get 2 items under additional_item_percentage - # Range 3-10. Default: 5 - starting_song_count: 3 - - # How many extra songs that are added in between the starting songs and ending songs. - # Note: This value will be lower if other options limit songs too much. - # Range 15-500. Default: 30 - additional_song_count: 50 - - # Whether or not songs that come with the DLC 'Just As Planned' are included. - # Default: false - allow_just_as_planned_dlc_songs: 'true' - - # Whether or not the songs chosen are available in Streamer Mode. Recommended to only switch this on, if you want to stream Muse Dash. - # Default: false - streamer_mode_enabled: 'false' - - # The number of music sheets placed in the multiworld - # Range 5-35. Default: 20 - music_sheet_count_percentage: 20 - - # The number of music sheets required to win - # Range 50-100. Default: 80 - music_sheet_win_count_percentage: 70 - - # The percentage of songs that get a second reward - # Range 50-100. Default: 80 - additional_item_percentage: 80 - - # The number of traps placed in the multiworld - # Range 0-35. Default: 15 - trap_count_percentage: 35 - - # Sets the grade needed to get rewards. - # Accepts the following: 'any'/0, 'c'/1, 'b'/2, 'a'/3, 'pinks'/4, 'silvers'/5. - # Default: 'any' - grade_needed: 'any' - - # Limits the range of songs chosen, such that at least 1 difficulty is within the chosen range. (Does not include secret difficulties) - # Supports the following: - # 'any' / 0 : Difficulty 1-11 - # 'easy' / 1 : Difficulty 1-3 - # 'medium' / 2 : Difficulty 4-5 - # 'hard' / 3 : Difficulty 6-7 - # 'expert' / 4 : Difficulty 8-9 - # 'master' / 5 : Difficulty 10-11 - # 'manual' / 6 : Allows song_difficulty_min and song_difficulty_max - # Default: 'any' - song_difficulty_mode: 'manual' - - # The following Options are only available under 'manual'" Must be between 1 and 11. Should not be randomised. - song_difficulty_min: 6 - song_difficulty_max: 8 - - # Any Traps or Songs you would want when starting the game. Any songs here will be considered as part of Starting Song Count. - start_inventory: - Bad Apple!! feat. Nomico: 1 - # Bad Apple Trap: 10 - # "Bad Apple!! feat. Nomico": 1 - - # Any songs you would want included within the randomiser. Will count as a song for additional_song_count. - # You will need to use the full name of the song. (i.e. "Bad Apple!! feat. Nomico") You can find this in song select at the bottom right while playing a seed. - # Songs here will not be starting songs. Use start_inventory for that. - include_songs: - - Night of Nights - - Cirno's Perfect Math Class - - Brain Power - - Nyan Cat - - Glimmer - - Magic Spell - - Bang!! - - Bit-alize - - PeroPero in the Universe - - I don't care about Christmas though - - Dandelion's Daydream - - Give Me 5 - - Sand Maze - - Fireflies - - Tenri Kaku Jou - # - "Bad Apple!! feat. Nomico" - - # Any songs you would want excluded within the randomiser. - # You will need to use the full name of the song. (i.e. "Bad Apple!! feat. Nomico") You can find this in song select at the bottom right while playing a seed. - exclude_songs: - - PUPA - - sheep in the light - - -+ - - Marry me, Nightmare - - ManiFesto - - bad_apple_mode: - on: 0 - off: 20 - -# non_local_items: -# - Music Sheet -# - Bad Apple Trap -# - Random Wave Trap -# - Background Freeze Trap -# - Pixelate Trap -# - Gray Scale Trap -# - Chromatic Aberration Trap -# - Shadow Edge Trap -triggers: - - option_name: bad_apple_mode - option_result: on - option_category: Muse Dash - options: - Muse Dash: - start_inventory: - Bad Apple Trap: 150 - Bad Apple!! feat. Nomico: 1 - -description: 'Generated by https://archipelago.gg/' -game: Muse Dash -name: Rivers Dash diff --git a/disabled yamls/RC1/Seto_Undertale.yaml b/disabled yamls/RC1/Seto_Undertale.yaml deleted file mode 100644 index 373bd8f93c04..000000000000 --- a/disabled yamls/RC1/Seto_Undertale.yaml +++ /dev/null @@ -1,93 +0,0 @@ -name: Seto Undertale - -description: Undertale Genocide - -game: Undertale -requires: - version: 0.4.2 - -Undertale: - progression_balancing: - random: 0 - random-low: 0 - random-high: 0 - disabled: 1 - normal: 0 - extreme: 0 - - accessibility: - locations: 1 - items: 0 - minimal: 0 - - local_items: - [] - - non_local_items: - [] - - start_inventory: - {Butterscotch Pie: 8} - - start_hints: - [] - - start_location_hints: - [] - - exclude_locations: - [] - - priority_locations: - [] - - item_links: - [] - - route_required: - neutral: 0 - pacifist: 0 - genocide: 1 - all_routes: 0 - - key_hunt: - false: 1 - true: 0 - - key_pieces: - 5: 1 - random: 0 - random-low: 0 - random-high: 0 - - rando_love: - false: 50 - true: 0 - - rando_stats: - false: 0 - true: 1 - - temy_include: - false: 0 - true: 1 - - no_equips: - false: 1 - true: 0 - - only_flakes: - false: 1 - true: 0 - - prog_armor: - false: 1 - true: 0 - - prog_weapons: - false: 0 - true: 1 - - rando_item_button: - false: 1 - true: 0 diff --git a/disabled yamls/RC1/Sheen-SDV4.yaml b/disabled yamls/RC1/Sheen-SDV4.yaml deleted file mode 100644 index 53c22f4f5e16..000000000000 --- a/disabled yamls/RC1/Sheen-SDV4.yaml +++ /dev/null @@ -1,155 +0,0 @@ -description: Stardew Mage Knight -game: Stardew Valley -name: sheen_sdv -Stardew Valley: - progression_balancing: 50 - accessibility: items - goal: greatest_walnut_hunter - # community_center: Complete the community center - # grandpa_evaluation: Get four candles on grandpa's shrine. You do not have to wait for Year3 to get evaluated - # bottom_of_the_mines: Reach the bottom of the local mineshaft - # cryptic_note: Complete the "Cryptic Note" quest, which is to reach level 100 in the Skull Cavern - # master_angler: Catch every fish in the game - # complete_collection: Complete the museum's collection by donating all 95 minerals and artifacts - # full_house: Get married and have two children - # greatest_walnut_hunter: Find all 130 golden walnuts - # perfection: Attain perfection in your world, based on how the vanilla game defines it, using the perfection tracker. This goal is extremely long - starting_money: unlimited - # 0-50000: How much money to start with. The vanilla game starts you with 500, but having more can really streamline Archipelago - # vanilla: 500 - # extra: 2000 - # rich: 5000 - # very rich: 20000 - # filthy rich: 50000 - # unlimited: Play with unlimited money - profit_margin: 200 - # 25-400: Multiplier over all earned money in-game. When below 100, some crops are no longer profitable to grow. - # quarter: 25 - # half: 50 - # normal: 100 - # double: 200 - # triple: 300 - # quadruple: 400 - bundle_randomization: shuffled - # vanilla: The bundles in the Community Center will be the ones from the vanilla game (not remixed) - # thematic: The bundles are randomized while following their original theme. Summer Crops Bundle will contain random summer crops, etc - # shuffled: The bundles are randomized with no regard for their individual themes or even rooms. Any bundle can contain any bundle item - bundle_price: very_cheap - # very_cheap: Every bundle will require two fewer items (capped at 1 item) from their list of accepted items. For Vault bundles, it is a 2/5th discount on the amount - # cheap: Every bundle will require one fewer item (capped at 1 item) from their list of accepted items. For Vault bundles, it is a 1/5th discount on the amount - # normal: Every bundle will require the vanilla number of items. For Vault bundles, it is the vanilla amount - # expensive: Every bundle will require one extra item (capped at the number of possible items) from their list of accepted items. For Vault bundles, it is a 1/5th increase on the amount - entrance_randomization: buildings # This includes entrances from supported mods - # disabled: Entrances are normal - # pelican_town: Entrances in the main Pelican Town map are shuffled with each other - # non_progression: Entrances to all of the areas that are always accessible without needing an archipelago unlock, will be shuffled with each other - # buildings: Every area that is "inside" can be shuffled with one another, included areas that are not immediately accessible - # chaos: Same as "buildings", but entrances are re-shuffled EVERY SINGLE DAY. - season_randomization: randomized # In archipelago, at the end of every in game season, you can choose which season will be next from the ones you have unlocked - # disabled: Seasons are all immediately available and you will start in spring - # randomized: You will start with a random season, and will earn the other 3 in a random order as Archipelago items - # randomized_not_winter: Same as randomized, but you are garanteed not to start in Winter - # progressive: You will start in spring, and unlock season as Archipelago items, but in the vanilla order, as "Progressive Season" items. - cropsanity: disabled # Pierre and Jojamart have been reworked for better lore compatibility and game balance - # disabled: All seeds and saplings can be purchased normally - # shuffled: You need to unlock the ability to purchase individual seed and sapling types as archipelago items. Every unlock comes with a free sample of 1. Growing and harvesting the resulting crop is a check. - backpack_progression: early_progressive # This includes backpacks from supported mods - # vanilla: You buy your backpack upgrades at Pierre's - # progressive: Backpack uprades are in the pool, you can buy two checks at Pierre's - # early_progressive: Backpack uprades are in the pool, but one of them is place early in the multiworld - tool_progression: progressive - # vanilla: You buy your tool upgrades at Clint's - # progressive: Tool upgrades are in the pool, you can go ask Clint for checks using money and metal bars - elevator_progression: progressive # This includes elevators from supported mods - # vanilla: The mineshaft elevator is unlocked normally, as you progress through the mineshaft levels - # progressive: The mineshaft elevator is unlocked by Archipelago progressive items, and every 5 level in the mineshaft is a check. - # progressive_from_previous_floor: Same as progressive, but you need to reach that level by using a ladder from the previous floor. You cannot unlock an elevator check using the elevator - skill_progression: progressive # This includes skills from supported mods - # vanilla: The player skills will gain experience locally, normally - # progressive: The player skills are upgraded through received progressive levels, and earned experience sends checks accordingly - building_progression: progressive # This includes buildings from supported mods - # vanilla: Carpenter buildings are constructed normally - # progressive: Robin sells one-time checks for each buildings, and you receive free buildings as Archipelago items. - # Once received and constructed once, you can pay the vanilla price to construct more iterations of the same building - # progressive_early_shipping_bin: Same as progressive, but the shipping bin will be placed early in the multiworld - festival_locations: disabled - # disabled: There are no checks to be obtained at the festivals - # easy: Participating in the festivals will check locations, but they are easy to do and just showing up is usually enough - # hard: The festival checks are only granted when the player performs well enough in them, so they need to take them seriously - arcade_machine_locations: disabled - # disabled: The Arcade Machines are not included. - # victories: Both Arcade Machines contain one check, obtainable by winning the default gamemode once, with no modifications - # victories_easy: Same as victories, except both arcade machines are made considerably easier through in-game buffs - # Junimo Kart will have 8 Extra lives for every level - # Journey of the Prairie King will start with one of each upgrade, 2 extra lives, and the drop rate of powerups and money is considerable increased - # full_shuffling: Both of the Arcade Machines contain many checks, and many buffs (including the ones from victories_easy) will be received as Archipelago Items, making the games easier over time - special_order_locations: disabled - # disabled: Special orders are not included in the multiworld - # board_only: The Special order board and rewards are items, and completing orders for the first time grants a check - # board_qi: In addition to the board, the difficult Qi Special Orders from the walnut room are also included - help_wanted_locations: 0 - # 0-56 [MUST BE A MULTIPLE OF 7]: The number of help wanted quests that are archipelago checks. For every 7, 4 are item deliveries, and 1 of each [fishing, gathering, slaying] - fishsanity: none - # none: None of the caught fish are AP locations - # legendaries: Catching legendary fish are AP locations - # special: Catching a pre-defined selection of important fish are AP locations - # random_selection: A random selection of fish are chosen and need to be caught as AP locations - # all: Fishsanity! Every single fish being caught is an AP location. - # exclude_legendaries: Every fish except legendary fish - # exclude_hard_fish: Every fish except the ones considered difficult - # only_easy_fish: Only the easy fish are checks - museumsanity: none # On all settings except none, the traveling merchant will assist you in completing your museum - # none: Museum donations are not included in the Archipelago shuffling - # milestones: Every donation milestone that gives a vanilla reward will instead give a check. Museum rewards are in the item pool - # randomized: A random selection of minerals and artifacts are chosen and need to be donated to the museum as AP locations. Museum rewards are in the item pool - # all: Museumsanity! Every single mineral and artifact being donated is an AP location. - friendsanity: all # This includes friendship hearts from supported mod NPCs - # none: Relationships are not included in the Archipelago shuffling - # bachelors: Friendship up to 8 hearts with the town bachelors are shuffled - # starting_npcs: Friendship up to 10 hearts (8 for bachelors) with the starting NPCs are shuffled. This excludes NPCs that require an event or item to be reached, like Sandy, Krobus, Kent, etc. - # all: Friendship up to 10 hearts (8 for bachelors) with every NPC in the game are shuffled. - # all_with_marriage: Same as all, but bachelors must each be befriended up to 14 hearts, which includes marrying every single one in succession. Not recommended for new players - friendsanity_heart_size: 2 # This setting does not do anything if not friendsanity is "none" - # 1-8: How many hearts are granted per heart item, and how many hearts must be earned to send a single check. A higher number reduces heart item clutter in the pool. The last heart is bounded to the relationship maximum. - movement_buff_number: 8 - # 0-12: Number of movement speed buffs in the pool - luck_buff_number: 12 - # 0-12: Number of luck buffs in the pool - exclude_ginger_island: 'false' - # true/false: Forcefully excludes every item and location that is related to Ginger Island, and removes both the Obelisk and the Boat repair from the item pool. - # When activating this setting, you will never need to, nor be able to, go to Ginger Island. This includes island quests, special orders, fish, and Leo's friendsanity hearts. - trap_items: hard # On any setting with traps, the number of traps is semi-random, with a bias towards having one of each, then rolling for more randomly side by side with filler resource packs. - # no_traps: There are no trap items in the pool. Filler items are only resource packs. - # easy: Trap items are intended to be funny and not very punishing - # medium: Trap items are minor annoyances that a competent player will deal with reasonably easily - # hard: Trap items are major annoyances that can be fairly punishing - # hell: trap items are extremely punishing and difficult and will severely impact gameplay - # nightmare: Just, don't. Trust me. - multiple_day_sleep_enabled: 'true' - # true/false: New feature allowing you to sleep several days at once. It is recommended to turn this on to avoid the game taking too long - # It allows the player to quickly skip long periods of time, to reach specific seasons or events. All decay mechanics (friends, animals, fences) will apply. - multiple_day_sleep_cost: 0 - # 0-200: The cost of the multisleep feature, in in-game money, per day skipped. The default value of zero is very strong, so this allows you to customize your experience - experience_multiplier: 800 - # 25-400: Multiplier to the experience gained on player skills. 100 is the vanilla experience gain, 200 is double, and so on. - friendship_multiplier: 800 - # 25-400: Multiplier to the friendship points gained from interactions with NPCs. 100 is vanilla, 200 is double, and so on. - debris_multiplier: half - # vanilla: The farm will start with, and generate over time, the normal amount of debris. Debris are natural grass, weeds, stones, twigs, and trees that are not grown from a seed - # half: Starting and spawned debris are halved - # quarter: Starting and spawned debris are reduced to 25% of their normal rate - # none: The farm will start fully cleared, and no debris will ever spawn on it. You can still plant grass and trees yourself. - # start_clear: The farm is completely cleared at the beginning of the game, but will spawn debris normally afterwards - quick_start: 'true' - # true/false: Starting a new game will give you several quality of life items as gifts when starting the game. - gifting: 'true' - # true/false: Allows sending items as gifts to other Stardew players and receiving gifts from other Stardew players - mods: ["Magic", "Bigger Backpack"] # Choose any combination of the following list of supported mods. Items and locations are added for custom npcs and skills, if using friendsanity and progressive skills. Bigger mods have some unique checks as well. All mod regions can be randomized with the entrance randomizer - # ["DeepWoods", "Tractor Mod", "Bigger Backpack", "Skull Cavern Elevator", - # "Luck Skill", "Magic", "Socializing Skill", "Archaeology", - # "Cooking Skill", "Binning Skill", "Juna - Roommate NPC", - # "Professor Jasper Thomas", "Alec Revisited", "Custom NPC - Yoba", "Custom NPC Eugene", - # "'Prophet' Wellwick", "Mister Ginger (cat npc)", "Shiko - New Custom NPC", "Delores - Custom NPC", - # "Ayeisha - The Postal Worker (Custom NPC)", "Custom NPC - Riley"] - start_inventory: {"Dwarvish Translation Guide": 1, "Rusty Key": 1, "Golden Walnut": 30} - death_link: 'false' diff --git a/disabled yamls/RC1/SilvrisTerraria.yaml b/disabled yamls/RC1/SilvrisTerraria.yaml deleted file mode 100644 index b5e43c6852df..000000000000 --- a/disabled yamls/RC1/SilvrisTerraria.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# Q. What is this file? -# A. This file contains options which allow you to configure your multiworld experience while allowing -# others to play how they want as well. -# -# Q. How do I use it? -# A. The options in this file are weighted. This means the higher number you assign to a value, the -# more chances you have for that option to be chosen. For example, an option like this: -# -# map_shuffle: -# on: 5 -# off: 15 -# -# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned -# off. -# -# Q. I've never seen a file like this before. What characters am I allowed to use? -# A. This is a .yaml file. You are allowed to use most characters. -# To test if your yaml is valid or not, you can use this website: -# http://www.yamllint.com/ -# You can also verify your Archipelago settings are valid at this site: -# https://archipelago.gg/check - -# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. -# {player} will be replaced with the player's slot number. -# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. -# {number} will be replaced with the counter value of the name. -# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. -name: SilvrisTerraria - -# Used to describe your yaml. Useful if you have multiple files. -description: Default Terraria Template - -game: Terraria -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -Terraria: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 50 # equivalent to 50 - extreme: 0 # equivalent to 99 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - {} - - start_hints: - # Start with these item's locations prefilled into the !hint command. - ["Hardmode"] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - goal: - # The victory condition for your run. Stuff after the goal will not be shuffled. - mechanical_bosses: 50 - plantera: 0 - golem: 0 - empress_of_light: 0 - lunatic_cultist: 0 - moon_lord: 0 - zenith: 0 - - achievements: - # Adds checks upon collecting achievements. Achievements for clearing bosses and events are excluded. - # "Exclude Grindy" also excludes fishing achievements. - none: 0 - exclude_grindy: 50 - exclude_fishing: 0 - all: 0 - - fill_extra_checks_with: - # Applies if you have achievements enabled. "Useful Items" helps to make the early game less grindy. - # Items are rewarded to all players in your Terraria world. - coins: 0 - useful_items: 50 - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 50 - true: 0 diff --git a/disabled yamls/RC1/dennisw100_Terraria.yaml b/disabled yamls/RC1/dennisw100_Terraria.yaml deleted file mode 100644 index 08b544f9900d..000000000000 --- a/disabled yamls/RC1/dennisw100_Terraria.yaml +++ /dev/null @@ -1,17 +0,0 @@ -Terraria: - progression_balancing: 50 - accessibility: items - goal: mechanical_bosses - # mechanical_bosses - # plantera - # golem - # empress_of_light - # lunatic_cultist - # moon_lord - # zenith - achievements: exclude_grindy - fill_extra_checks_with: useful_items - death_link: 'false' -description: 'Generated by https://archipelago.gg/ and edited by dennisw100' -game: Terraria -name: dennisw100 diff --git a/disabled yamls/RC1/speedweedDOOM.yaml b/disabled yamls/RC1/speedweedDOOM.yaml deleted file mode 100644 index b34f2390f8e4..000000000000 --- a/disabled yamls/RC1/speedweedDOOM.yaml +++ /dev/null @@ -1,178 +0,0 @@ -# .JYJJ?7~^: .~?~. :^:. -# J55YY5PPGG5PBBBPJ~7YGGGPY?~. -# ^PYYYYY5YJPBBGGGBBBBBBGGBBBBPJ^.. -# ~P5YYJY5PGGBBBBGGGGGGGGGGGGGBBGPP5YYJJ?77~ -# .P5YYY5GBGGGBBBBBBBBBBBBBBGGGPJYYY5555PPGY -# !PY5PGBGGBGGGGGBGBBGGGGGGGGGG5Y55YJJJJYP~ -# ~GGGGPGGP5G5PGPGGGGBGGGGGGGGBP5YJYY5YPJ -# !PGGB#####J!GBP?Y5P5PGGGGPGGGGBPYJYYYPY. -# :J5GG&&&&&&J:Y&#GY?5BPPBGYGYYGGGGGYJ5PP? -# ^~!5PYB&&&&G:?&&&GB#&&&&&B!~P?YGGGGGPB5: -# :P5??JG##&P?#&#BP#&&&&&&7:Y&#JYBGB55GG^ -# .YY??7?GBBBBB#BBBBB#&&&&5:J&&&P?YGB57!J5: -# ~?!~:^?JB##BBBBBB##BBB##JY&&#GJ??5BP?. .: -# :. 7J7!PB##BBBBBBBBBBBBBPYJJ5PGGBBP7. -# .!^. 7??PB####B###BBPYJ?5#########G! -# ~~~J5P5PGPPPYJ?7^7Y############~ -# ^?PBB&&#BBBBG5PPGGJ!YJB##########B! -# .7P#&&BB&&&&#&&&&##&GG#GPGGB#####BBP? -# 5@&#PYY#&&&&&&&&&BB&&&&GYYYYY5P55Y?^ -# !B###P5&&&&&&&&&&PY5GGBB5YY~ .::.. -# YBBB#B&&&&&&&&&BYYY~.:^~~: -# ^B###G#&&&&&&&&#PY5? -# ^####Y?P####BGG5J??!:^:. -# 7PBG7!!7777!!!!!!^^^?J5J^ -# .^~!!!!!!!!!!!!!!^^~!JGBY^ -# ^!!!!!!!!!!!!!!~^^..^?GB? -# ~!!!!!!!!!!!!!!!^^: ^YBY. -# .!!!!!!!!!!!!!!!!^^^. .7B5. -# :!!!!!!!!!!!!!!!!~^^: !BP^ -# ^!!!!!!!!!!!!!!!!!^^^: ~GB7 ?PY^ -# .~!!!!!!!!!!!!!!!!^^:. :YB5!^^YBGY~ -# ^^~~!!!!!!!~~^:^^:. .!5GGGPY7: -# :~~^:...... .^^^. :^^:. -# .:^~~~^: :~^: -# ..:^~~~^:.. .^~~^: -# :!!!~~^^:. .^~~~^. -#:~7~^^:. :~~~^: -# .... :~~~!^:. -# .^~!?~~~. -# .:^^^: -name: speedweed - -# Used to describe your yaml. Useful if you have multiple files. -description: Default DOOM 1993 Template - -game: DOOM 1993 -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -DOOM 1993: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 50 # equivalent to 50 - extreme: 0 # equivalent to 99 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - {} - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - item_links: - # Share part of your item pool with other players. - [] - - difficulty: - # Choose the difficulty option. Those match DOOM's difficulty options. - # baby (I'm too young to die.) double ammos, half damage, less monsters or strength. - # easy (Hey, not too rough.) less monsters or strength. - # medium (Hurt me plenty.) Default. - # hard (Ultra-Violence.) More monsters or strength. - # nightmare (Nightmare!) Monsters attack more rapidly and respawn. - baby: 0 - easy: 0 - medium: 0 - hard: 1 - nightmare: 0 - - random_monsters: - # Choose how monsters are randomized. - # vanilla: No randomization - # shuffle: Monsters are shuffled within the level - # random_balanced: Monsters are completely randomized, but balanced based on existing ratio in the level. (Small monsters vs medium vs big) - vanilla: 0 - shuffle: 50 - random_balanced: 0 - - random_pickups: - # Choose how pickups are randomized. - # vanilla: No randomization - # shuffle: Pickups are shuffled within the level - # random_balanced: Pickups are completely randomized, but balanced based on existing ratio in the level. (Small pickups vs Big) - vanilla: 0 - shuffle: 50 - random_balanced: 0 - - allow_death_logic: - # Some locations require a timed puzzle that can only be tried once. - # After which, if the player failed to get it, the location cannot be checked anymore. - # By default, no progression items are placed here. There is a way, hovewer, to still get them: - # Get killed in the current map. The map will reset, you can now attempt the puzzle again. - false: 50 - true: 0 - - start_with_computer_area_maps: - # Give the player all Computer Area Map items from the start. - false: 50 - true: 0 - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 0 - true: 1 - - episode1: - # Knee-Deep in the Dead. - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 0 - true: 50 - - episode2: - # The Shores of Hell - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 0 - true: 50 - - episode3: - # Inferno - # If none of the episodes are chosen, Episode 1 will be chosen by default. - false: 0 - true: 50 - - episode4: - # Thy Flesh Consumed. - # If none of the episodes are chosen, Episode 1 will be chosen by default. - # This episode is very difficult. - false: 0 - true: 50 diff --git a/disabled yamls/Stardew Valley.yaml b/disabled yamls/Stardew Valley.yaml deleted file mode 100644 index 62fcf783d4a6..000000000000 --- a/disabled yamls/Stardew Valley.yaml +++ /dev/null @@ -1,469 +0,0 @@ -# Q. What is this file? -# A. This file contains options which allow you to configure your multiworld experience while allowing -# others to play how they want as well. -# -# Q. How do I use it? -# A. The options in this file are weighted. This means the higher number you assign to a value, the -# more chances you have for that option to be chosen. For example, an option like this: -# -# map_shuffle: -# on: 5 -# off: 15 -# -# Means you have 5 chances for map shuffle to occur, and 15 chances for map shuffle to be turned -# off. -# -# Q. I've never seen a file like this before. What characters am I allowed to use? -# A. This is a .yaml file. You are allowed to use most characters. -# To test if your yaml is valid or not, you can use this website: -# http://www.yamllint.com/ -# You can also verify your Archipelago settings are valid at this site: -# https://archipelago.gg/check - -# Your name in-game. Spaces will be replaced with underscores and there is a 16-character limit. -# {player} will be replaced with the player's slot number. -# {PLAYER} will be replaced with the player's slot number, if that slot number is greater than 1. -# {number} will be replaced with the counter value of the name. -# {NUMBER} will be replaced with the counter value of the name, if the counter value is greater than 1. -name: Player{number} - -# Used to describe your yaml. Useful if you have multiple files. -description: Default Stardew Valley Template - -game: Stardew Valley -requires: - version: 0.4.2 # Version of Archipelago required for this yaml to work as expected. - -Stardew Valley: - progression_balancing: - # A system that can move progression earlier, to try and prevent the player from getting stuck and bored early. - # A lower setting means more getting stuck. A higher setting means less getting stuck. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 99 - random: 0 - random-low: 0 - random-high: 0 - disabled: 0 # equivalent to 0 - normal: 50 # equivalent to 50 - extreme: 0 # equivalent to 99 - - accessibility: - # Set rules for reachability of your items/locations. - # Locations: ensure everything can be reached and acquired. - # Items: ensure all logically relevant items can be acquired. - # Minimal: ensure what is needed to reach your goal can be acquired. - locations: 0 - items: 50 - minimal: 0 - - local_items: - # Forces these items to be in their native world. - [] - - non_local_items: - # Forces these items to be outside their native world. - [] - - start_inventory: - # Start with these items. - {} - - start_hints: - # Start with these item's locations prefilled into the !hint command. - [] - - start_location_hints: - # Start with these locations and their item prefilled into the !hint command - [] - - exclude_locations: - # Prevent these locations from having an important item - [] - - priority_locations: - # Prevent these locations from having an unimportant item - [] - - goal: - # What's your goal with this play-through? - # Community Center: The world will be completed once you complete the Community Center. - # Grandpa's Evaluation: The world will be completed once 4 candles are lit at Grandpa's Shrine. - # Bottom of the Mines: The world will be completed once you reach level 120 in the mineshaft. - # Cryptic Note: The world will be completed once you complete the quest "Cryptic Note" where Mr Qi asks you to reach floor 100 in the Skull Cavern. - # Master Angler: The world will be completed once you have caught every fish in the game. Pairs well with Fishsanity. - # Complete Collection: The world will be completed once you have completed the museum by donating every possible item. Pairs well with Museumsanity. - # Full House: The world will be completed once you get married and have two kids. Pairs well with Friendsanity. - # Greatest Walnut Hunter: The world will be completed once you find all 130 Golden Walnuts - # Perfection: The world will be completed once you attain Perfection, based on the vanilla definition. - community_center: 50 - grandpa_evaluation: 0 - bottom_of_the_mines: 0 - cryptic_note: 0 - master_angler: 0 - complete_collection: 0 - full_house: 0 - greatest_walnut_hunter: 0 - perfection: 0 - - starting_money: - # Amount of gold when arriving at the farm. - # Set to -1 or unlimited for infinite money in this playthrough - # - # You can define additional values between the minimum and maximum values. - # Minimum value is -1 - # Maximum value is 50000 - random: 0 - random-low: 0 - random-high: 0 - unlimited: 0 # equivalent to -1 - vanilla: 0 # equivalent to 500 - extra: 0 # equivalent to 2000 - rich: 50 # equivalent to 5000 - very rich: 0 # equivalent to 20000 - filthy rich: 0 # equivalent to 50000 - - profit_margin: - # Multiplier over all gold earned in-game by the player. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 400 - random: 0 - random-low: 0 - random-high: 0 - quarter: 0 # equivalent to 25 - half: 0 # equivalent to 50 - normal: 50 # equivalent to 100 - double: 0 # equivalent to 200 - triple: 0 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - bundle_randomization: - # What items are needed for the community center bundles? - # Vanilla: Standard bundles from the vanilla game - # Thematic: Every bundle will require random items compatible with their original theme - # Shuffled: Every bundle will require random items and follow no particular structure - vanilla: 0 - thematic: 50 - shuffled: 0 - - bundle_price: - # How many items are needed for the community center bundles? - # Very Cheap: Every bundle will require 2 items fewer than usual - # Cheap: Every bundle will require 1 item fewer than usual - # Normal: Every bundle will require the vanilla number of items - # Expensive: Every bundle will require 1 extra item when applicable - very_cheap: 0 - cheap: 0 - normal: 50 - expensive: 0 - - entrance_randomization: - # Should area entrances be randomized? - # Disabled: No entrance randomization is done - # Pelican Town: Only buildings in the main town area are randomized among each other - # Non Progression: Only buildings that are always available are randomized with each other - # Buildings: All Entrances that Allow you to enter a building using a door are randomized with each other - # Chaos: Same as above, but the entrances get reshuffled every single day! - disabled: 0 - pelican_town: 0 - non_progression: 0 - buildings: 50 - chaos: 0 - - season_randomization: - # Should seasons be randomized? - # All settings allow you to choose which season you want to play next (from those unlocked) at the end of a season. - # Disabled: You will start in Spring with all seasons unlocked. - # Randomized: The seasons will be unlocked randomly as Archipelago items. - # Randomized Not Winter: The seasons are randomized, but you're guaranteed not to start with winter. - # Progressive: You will start in Spring and unlock the seasons in their original order. - disabled: 0 - randomized: 50 - randomized_not_winter: 0 - progressive: 0 - - cropsanity: - # Formerly named "Seed Shuffle" - # Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. - # Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops - # Shuffled: Seeds are unlocked as archipelago item, for each seed there is a location check for growing and harvesting that crop - disabled: 50 - shuffled: 50 - - backpack_progression: - # How is the backpack progression handled? - # Vanilla: You can buy them at Pierre's General Store. - # Progressive: You will randomly find Progressive Backpack upgrades. - # Early Progressive: You can expect your first Backpack in sphere 1. - vanilla: 0 - progressive: 0 - early_progressive: 50 - - tool_progression: - # How is the tool progression handled? - # Vanilla: Clint will upgrade your tools with ore. - # Progressive: You will randomly find Progressive Tool upgrades. - vanilla: 0 - progressive: 50 - - skill_progression: - # How is the skill progression handled? - # Vanilla: You will level up and get the normal reward at each level. - # Progressive: The xp will be earned internally, locations will be sent when you earn a level. Your real - # levels will be scattered around the multiworld. - vanilla: 0 - progressive: 50 - - building_progression: - # How is the building progression handled? - # Vanilla: You will buy each building normally. - # Progressive: You will receive the buildings and will be able to build the first one of each type for free, - # once it is received. If you want more of the same building, it will cost the vanilla price. - # Progressive early shipping bin: You can expect your shipping bin in sphere 1. - vanilla: 0 - progressive: 0 - progressive_early_shipping_bin: 50 - - festival_locations: - # Locations for attending and participating in festivals - # With Disabled, you do not need to attend festivals - # With Easy, there are checks for participating in festivals - # With Hard, the festival checks are only granted when the player performs well in the festival - disabled: 50 - easy: 0 - hard: 0 - - elevator_progression: - # How is Elevator progression handled? - # Vanilla: You will unlock new elevator floors for yourself. - # Progressive: You will randomly find Progressive Mine Elevators to go deeper. Locations are sent for reaching - # every elevator level. - # Progressive from previous floor: Same as progressive, but you must reach elevator floors on your own, - # you cannot use the elevator to check elevator locations - vanilla: 0 - progressive: 0 - progressive_from_previous_floor: 50 - - arcade_machine_locations: - # How are the Arcade Machines handled? - # Disabled: The arcade machines are not included in the Archipelago shuffling. - # Victories: Each Arcade Machine will contain one check on victory - # Victories Easy: The arcade machines are both made considerably easier to be more accessible for the average - # player. - # Full Shuffling: The arcade machines will contain multiple checks each, and different buffs that make the game - # easier are in the item pool. Junimo Kart has one check at the end of each level. - # Journey of the Prairie King has one check after each boss, plus one check for each vendor equipment. - disabled: 0 - victories: 0 - victories_easy: 0 - full_shuffling: 50 - - special_order_locations: - # How are the Special Orders handled? - # Disabled: The special orders are not included in the Archipelago shuffling. - # Board Only: The Special Orders on the board in town are location checks - # Board and Qi: The Special Orders from Qi's walnut room are checks, as well as the board in town - disabled: 0 - board_only: 00 - board_qi: 50 - - help_wanted_locations: - # How many "Help Wanted" quests need to be completed as Archipelago Locations - # Out of every 7 quests, 4 will be item deliveries, and then 1 of each for: Fishing, Gathering and Slaying Monsters. - # Choosing a multiple of 7 is recommended. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 56 - random: 0 - random-low: 0 - random-high: 0 - none: 0 # equivalent to 0 - minimum: 0 # equivalent to 7 - normal: 0 # equivalent to 14 - lots: 0 # equivalent to 28 - maximum: 50 # equivalent to 56 - - fishsanity: - # Locations for catching fish? - # None: There are no locations for catching fish - # Legendaries: Each of the 5 legendary fish are checks - # Special: A curated selection of strong fish are checks - # Randomized: A random selection of fish are checks - # All: Every single fish in the game is a location that contains an item. Pairs well with the Master Angler Goal - # Exclude Legendaries: Every fish except legendaries - # Exclude Hard Fish: Every fish under difficulty 80 - # Only Easy Fish: Every fish under difficulty 50 - none: 0 - legendaries: 0 - special: 0 - randomized: 0 - all: 50 - exclude_legendaries: 0 - exclude_hard_fish: 0 - only_easy_fish: 0 - - museumsanity: - # Locations for museum donations? - # None: There are no locations for donating artifacts and minerals to the museum - # Milestones: The donation milestones from the vanilla game are checks - # Randomized: A random selection of minerals and artifacts are checks - # All: Every single donation will be a check - none: 0 - milestones: 0 - randomized: 0 - all: 50 - - friendsanity: - # Locations for friendships? - # None: There are no checks for befriending villagers - # Bachelors: Each heart of a bachelor is a check - # Starting NPCs: Each heart for npcs that are immediately available is a check - # All: Every heart with every NPC is a check, including Leo, Kent, Sandy, etc - # All With Marriage: Marriage candidates must also be dated, married, and befriended up to 14 hearts. - none: 0 - bachelors: 0 - starting_npcs: 0 - all: 50 - all_with_marriage: 0 - - friendsanity_heart_size: - # If using friendsanity, how many hearts are received per item, and how many hearts must be earned to send a check - # A higher value will lead to fewer heart items in the item pool, reducing bloat - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 1 - # Maximum value is 8 - 2: 50 - random: 0 - random-low: 0 - random-high: 0 - - movement_buff_number: - # Number of movement speed buffs to the player that exist as items in the pool. - # Each movement speed buff is a +25% multiplier that stacks additively - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 12 - 4: 0 - random: 0 - random-low: 0 - random-high: 20 - - luck_buff_number: - # Number of luck buffs to the player that exist as items in the pool. - # Each luck buff is a bonus to daily luck of 0.025 - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 12 - 4: 0 - random: 0 - random-low: 0 - random-high: 50 - - exclude_ginger_island: - # Exclude Ginger Island? - # This option will forcefully exclude everything related to Ginger Island from the slot. - # If you pick a goal that requires Ginger Island, you cannot exclude it and it will get included anyway - false: 50 - true: 0 - - trap_items: - # When rolling filler items, including resource packs, the game can also roll trap items. - # This setting is for choosing if traps will be in the item pool, and if so, how punishing they will be. - no_traps: 0 - easy: 0 - medium: 50 - hard: 0 - hell: 0 - nightmare: 0 - - multiple_day_sleep_enabled: - # Enable the ability to sleep automatically for multiple days straight? - false: 0 - true: 50 - - multiple_day_sleep_cost: - # How much gold it will cost to use MultiSleep. You will have to pay that amount for each day skipped. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 0 - # Maximum value is 200 - random: 0 - random-low: 0 - random-high: 0 - free: 50 # equivalent to 0 - cheap: 0 # equivalent to 25 - medium: 0 # equivalent to 50 - expensive: 0 # equivalent to 100 - - experience_multiplier: - # How fast you want to earn skill experience. A lower setting mean less experience. - # A higher setting means more experience. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 800 - random: 0 - random-low: 0 - random-high: 0 - half: 0 # equivalent to 50 - vanilla: 0 # equivalent to 100 - double: 50 # equivalent to 200 - triple: 0 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - friendship_multiplier: - # How fast you want to earn friendship points with villagers. - # A lower setting mean less friendship per action. - # A higher setting means more friendship per action. - # - # You can define additional values between the minimum and maximum values. - # Minimum value is 25 - # Maximum value is 800 - random: 0 - random-low: 0 - random-high: 0 - half: 0 # equivalent to 50 - vanilla: 0 # equivalent to 100 - double: 50 # equivalent to 200 - triple: 0 # equivalent to 300 - quadruple: 0 # equivalent to 400 - - debris_multiplier: - # How much debris will spawn on the player's farm? - # Vanilla: debris spawns normally - # Half: debris will spawn at half the normal rate - # Quarter: debris will spawn at one quarter of the normal rate - # None: No debris will spawn on the farm, ever - # Start Clear: debris will spawn at the normal rate, but the farm will be completely clear when starting the game - vanilla: 0 - half: 50 - quarter: 0 - none: 0 - start_clear: 0 - - quick_start: - # Do you want the quick start package? You will get a few items to help early game automation, - # so you can use the multiple day sleep at its maximum. - false: 0 - true: 50 - - gifting: - # Do you want to enable gifting items to and from other Stardew Valley worlds? - false: 0 - true: 50 - - mods: - # List of mods that will be considered for shuffling. - [] - - death_link: - # When you die, everyone dies. Of course the reverse is true too. - false: 50 - true: 0 diff --git a/disabled yamls/Stardew allsanity.yaml b/disabled yamls/Stardew allsanity.yaml deleted file mode 100644 index 343dfce67def..000000000000 --- a/disabled yamls/Stardew allsanity.yaml +++ /dev/null @@ -1,39 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: items - goal: perfection - starting_money: random - profit_margin: 200 - bundle_randomization: shuffled - bundle_price: expensive - entrance_randomization: chaos - season_randomization: randomized - cropsanity: shuffled - backpack_progression: progressive - tool_progression: progressive - skill_progression: progressive - building_progression: progressive - festival_locations: hard - arcade_machine_locations: full_shuffling - special_order_locations: board_qi - help_wanted_locations: 56 - fishsanity: all - museumsanity: all - friendsanity: all_with_marriage - friendsanity_heart_size: 1 - player_buff_number: 12 - exclude_ginger_island: 'false' - trap_items: nightmare - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 200 - friendship_multiplier: 200 - debris_multiplier: half - quick_start: 'true' - gifting: 'true' - gift_tax: 20 - mods: ["DeepWoods", "Tractor Mod", "Bigger Backpack", "Luck Skill", "Magic", "Socializing Skill", "Archaeology", "Cooking Skill", "Binning Skill", "Juna - Roommate NPC", "Professor Jasper Thomas", "Alec Revisited", "Custom NPC - Yoba", "Custom NPC Eugene", "'Prophet' Wellwick", "Mister Ginger (cat npc)", "Shiko - New Custom NPC", "Delores - Custom NPC", "Ayeisha - The Postal Worker (Custom NPC)"] - death_link: 'true' -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: MyName \ No newline at end of file diff --git a/disabled yamls/StardewRace.yaml b/disabled yamls/StardewRace.yaml deleted file mode 100644 index 2e3f89b9409d..000000000000 --- a/disabled yamls/StardewRace.yaml +++ /dev/null @@ -1,42 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: items - goal: community_center - starting_money: rich - profit_margin: 100 - bundle_randomization: thematic - bundle_price: cheap - entrance_randomization: disabled - season_randomization: randomized - cropsanity: shuffled - backpack_progression: early_progressive - tool_progression: progressive - elevator_progression: progressive - skill_progression: progressive - building_progression: progressive - festival_locations: easy - arcade_machine_locations: disabled - special_order_locations: disabled - help_wanted_locations: 0 - fishsanity: none - museumsanity: none - friendsanity: none - friendsanity_heart_size: 4 - movement_buff_number: 4 - luck_buff_number: 4 - exclude_ginger_island: 'true' - trap_items: medium - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 400 - friendship_multiplier: 400 - debris_multiplier: quarter - quick_start: 'true' - gifting: 'true' - mods: [] - start_hints: - [] - death_link: 'true' -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: StardewRacer \ No newline at end of file diff --git a/disabled yamls/StardewTester.yaml b/disabled yamls/StardewTester.yaml deleted file mode 100644 index 11d2b4c54abc..000000000000 --- a/disabled yamls/StardewTester.yaml +++ /dev/null @@ -1,48 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: items - goal: community_center - starting_money: rich - profit_margin: 400 - bundle_randomization: thematic - bundle_price: very_cheap - entrance_randomization: disabled - season_randomization: randomized - cropsanity: shuffled - backpack_progression: early_progressive - tool_progression: progressive_very_cheap - elevator_progression: progressive - skill_progression: progressive - building_progression: progressive_very_cheap - festival_locations: easy - arcade_machine_locations: disabled - special_order_locations: disabled - help_wanted_locations: 0 - fishsanity: none - museumsanity: none - monstersanity: one_per_category - shipsanity: everything - cooksanity: all - chefsanity: all - friendsanity: none - friendsanity_heart_size: 4 - movement_buff_number: 4 - luck_buff_number: 4 - exclude_ginger_island: 'true' - trap_items: medium - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 800 - friendship_multiplier: 800 - debris_multiplier: quarter - quick_start: 'true' - gifting: 'true' - mods: [] - start_inventory: - Return Scepter: 1 - Movement Speed Bonus: 4 - "Adventurer's Guild": 1 - death_link: 'true' -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: Tester \ No newline at end of file diff --git a/disabled yamls/Stardew_Valley.yaml b/disabled yamls/Stardew_Valley.yaml deleted file mode 100644 index dd25859ee9e5..000000000000 --- a/disabled yamls/Stardew_Valley.yaml +++ /dev/null @@ -1,41 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: locations - goal: perfection - starting_money: -1 - profit_margin: 200 - bundle_randomization: thematic - bundle_price: very_cheap - entrance_randomization: buildings - season_randomization: randomized - cropsanity: shuffled - backpack_progression: early_progressive - tool_progression: progressive - skill_progression: progressive - building_progression: progressive_early_shipping_bin - festival_locations: hard - elevator_progression: progressive - arcade_machine_locations: disabled - special_order_locations: board_qi - help_wanted_locations: 0 - fishsanity: only_easy_fish - museumsanity: none - friendsanity: all_with_marriage - friendsanity_heart_size: 4 - movement_buff_number: 4 - luck_buff_number: 4 - exclude_ginger_island: 'false' - trap_items: nightmare - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 800 - friendship_multiplier: 800 - debris_multiplier: none - quick_start: 'true' - gifting: 'true' - death_link: 'false' - start_inventory: - {"Movement Speed Bonus": 4} -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: Tester diff --git a/disabled yamls/Tester - 3.x.x.yaml b/disabled yamls/Tester - 3.x.x.yaml deleted file mode 100644 index aad69a26b96a..000000000000 --- a/disabled yamls/Tester - 3.x.x.yaml +++ /dev/null @@ -1,34 +0,0 @@ -Stardew Valley: - progression_balancing: 50 - accessibility: items - goal: community_center - starting_money: 5000 - resource_pack_multiplier: 100 - bundle_randomization: thematic - bundle_price: normal - entrance_randomization: disabled - season_randomization: randomized - cropsanity: shuffled - backpack_progression: early_progressive - tool_progression: progressive - skill_progression: progressive - building_progression: progressive_early_shipping_bin - elevator_progression: progressive_from_previous_floor - arcade_machine_locations: full_shuffling - help_wanted_locations: 7 - fishsanity: none - museumsanity: milestones - friendsanity: all - player_buff_number: 4 - multiple_day_sleep_enabled: 'true' - multiple_day_sleep_cost: 0 - experience_multiplier: 200 - friendship_multiplier: 200 - debris_multiplier: half - quick_start: 'true' - gifting: 'true' - gift_tax: 20 - death_link: 'false' -description: 'Generated by https://archipelago.gg/' -game: Stardew Valley -name: Tester From a0215b2676be73ed068e593fcefc350047d71109 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 14 Nov 2023 07:53:05 -0500 Subject: [PATCH 147/482] - Fixes to mod stuff for the cache --- worlds/stardew_valley/logic/logic.py | 2 +- .../stardew_valley/mods/logic/quests_logic.py | 8 +++--- .../test/TestLogicSimplification.py | 26 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index a1c58b698ee2..e37c63239bd9 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -726,7 +726,7 @@ def has_walnut(self, number: int) -> StardewRule: return And(reach_walnut_regions) if number <= 50: return reach_entire_island - gems = [Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz] + gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz) return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 24dc9e014d2d..fd815e04b990 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -81,13 +81,13 @@ def _get_sve_quest_rules(self): return {} return { - ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has([Ore.iridium, Material.coal]) & + ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has((Ore.iridium, Material.coal)) & self.region.can_reach(Region.blacksmith) & self.region.can_reach(Region.railroad), - ModQuest.GrandpasShed: self.has([Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone]) & + ModQuest.GrandpasShed: self.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & self.region.can_reach(SVERegion.grandpas_shed_interior), - ModQuest.MarlonsBoat: self.has([Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat]) & + ModQuest.MarlonsBoat: self.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.has([SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root]), + ModQuest.MonsterCrops: self.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(SVEForage.void_soul), } diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index 0bb819f0d7c0..ce58ea557820 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -21,12 +21,13 @@ def test_simplify_false_in_or(self): self.assertEqual((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))) - self.assertEqual(rule.simplify(), - And(Received('Summer', 0, 1), Received('Fall', 0, 1), - Received('Winter', 0, 1), Received('Spring', 0, 1))) + # This feature has been disabled and that seems to save time + # 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))) + # self.assertEqual(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)), @@ -34,12 +35,13 @@ def test_simplify_duplicated_and(self): self.assertEqual(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))) - self.assertEqual(rule.simplify(), - Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), - Received('Spring', 0, 1))) + # This feature has been disabled and that seems to save time + # 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))) + # self.assertEqual(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)), From 477925f53fb234404ed5f0400a5f9d6dbbdf30a9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 09:45:12 -0500 Subject: [PATCH 148/482] - get rid of lru cache # Conflicts: # worlds/stardew_valley/logic/logic.py # worlds/stardew_valley/logic/relationship_logic.py --- worlds/_sc2common/bot/game_data.py | 1 - worlds/stardew_valley/__init__.py | 4 +- worlds/stardew_valley/data/monster_data.py | 2 +- worlds/stardew_valley/logic/action_logic.py | 5 +- worlds/stardew_valley/logic/building_logic.py | 5 +- worlds/stardew_valley/logic/bundle_logic.py | 6 +- worlds/stardew_valley/logic/combat_logic.py | 27 +++--- worlds/stardew_valley/logic/cooking_logic.py | 17 ++-- worlds/stardew_valley/logic/crafting_logic.py | 11 +-- worlds/stardew_valley/logic/crop_logic.py | 6 +- worlds/stardew_valley/logic/fishing_logic.py | 7 +- worlds/stardew_valley/logic/gift_logic.py | 4 +- worlds/stardew_valley/logic/has_logic.py | 3 +- worlds/stardew_valley/logic/logic.py | 54 +++++------ worlds/stardew_valley/logic/mine_logic.py | 12 +-- worlds/stardew_valley/logic/money_logic.py | 11 +-- worlds/stardew_valley/logic/monster_logic.py | 10 +- worlds/stardew_valley/logic/museum_logic.py | 4 +- worlds/stardew_valley/logic/quest_logic.py | 4 +- worlds/stardew_valley/logic/received_logic.py | 3 +- worlds/stardew_valley/logic/region_logic.py | 18 ++-- .../logic/relationship_logic.py | 29 ++++-- worlds/stardew_valley/logic/season_logic.py | 4 +- worlds/stardew_valley/logic/shipping_logic.py | 19 ++-- worlds/stardew_valley/logic/skill_logic.py | 40 ++++---- .../logic/special_order_logic.py | 11 +-- worlds/stardew_valley/logic/time_logic.py | 8 +- worlds/stardew_valley/logic/tool_logic.py | 11 +-- worlds/stardew_valley/logic/wallet_logic.py | 5 +- .../stardew_valley/mods/logic/item_logic.py | 14 +-- .../mods/logic/special_orders_logic.py | 2 +- worlds/stardew_valley/regions.py | 5 +- worlds/stardew_valley/rules.py | 20 ++-- .../test/TestMultiplePlayers.py | 92 +++++++++++++++++++ worlds/stardew_valley/test/TestRules.py | 5 +- .../stardew_valley/test/checks/goal_checks.py | 2 +- .../test/checks/option_checks.py | 3 +- .../test/long/TestOptionsLong.py | 7 +- 38 files changed, 300 insertions(+), 191 deletions(-) create mode 100644 worlds/stardew_valley/test/TestMultiplePlayers.py diff --git a/worlds/_sc2common/bot/game_data.py b/worlds/_sc2common/bot/game_data.py index 50f10bd6692e..85d87fcb2716 100644 --- a/worlds/_sc2common/bot/game_data.py +++ b/worlds/_sc2common/bot/game_data.py @@ -3,7 +3,6 @@ from bisect import bisect_left from dataclasses import dataclass -from functools import lru_cache from typing import Dict, List, Optional, Union from .data import Attribute, Race diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 880930b2b529..de127c8b4364 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -190,7 +190,7 @@ def setup_construction_events(self): def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], - self.logic.bundle.can_complete_community_center(), + self.logic.bundle.can_complete_community_center, Event.victory) elif self.options.goal == Goal.option_grandpa_evaluation: self.create_event_location(location_table[GoalName.grandpa_evaluation], @@ -230,7 +230,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == options.Goal.option_gourmet_chef: self.create_event_location(location_table[GoalName.gourmet_chef], - self.logic.cooking.can_cook_everything(), + self.logic.cooking.can_cook_everything, Event.victory) elif self.options.goal == options.Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 45538ebdaad7..1852735d2609 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -112,4 +112,4 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu for monster in all_monsters: if monster.category not in all_monsters_by_category: all_monsters_by_category[monster.category] = () - all_monsters_by_category[monster.category] = () + (monster,) + all_monsters_by_category[monster.category] = all_monsters_by_category[monster.category] + (monster,) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index c2aba35b4c8a..2b48dda10aac 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,5 +1,4 @@ -from functools import lru_cache - +from Utils import cache_self1 from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic @@ -34,7 +33,7 @@ def can_pan(self) -> StardewRule: def can_pan_at(self, region: str) -> StardewRule: return self.region.can_reach(region) & self.can_pan() - @lru_cache(maxsize=None) + @cache_self1 def can_open_geode(self, geode: str) -> StardewRule: blacksmith_access = self.region.can_reach(Region.blacksmith) geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 76daa01f6b66..762b57fbf53e 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,6 +1,6 @@ -from functools import lru_cache from typing import Dict +from Utils import cache_self1 from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic @@ -64,6 +64,7 @@ def initialize_rules(self): def update_rules(self, new_rules: Dict[str, StardewRule]): self.building_rules.update(new_rules) + @cache_self1 def has_building(self, building: str) -> StardewRule: carpenter_rule = self.received(Event.can_construct_buildings) if not self.building_option & BuildingProgression.option_progressive: @@ -80,7 +81,7 @@ def has_building(self, building: str) -> StardewRule: building = " ".join(["Progressive", *building.split(" ")[1:]]) return self.received(f"{building}", count) & carpenter_rule - @lru_cache(maxsize=None) + @cache_self1 def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level < 1: return True_() diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index a47f0269c4d9..ad4c4a9e0cdc 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,4 +1,4 @@ -from functools import lru_cache +from functools import cached_property from typing import Tuple from .cached_logic import CachedLogic, CachedRules @@ -25,7 +25,7 @@ def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic, region self.money = money self.farming = farming - @lru_cache(maxsize=None) + # Should be cached def can_complete_bundle(self, bundle_requirements: Tuple[BundleItem], number_required: int) -> StardewRule: item_rules = [] highest_quality_yet = 0 @@ -40,7 +40,7 @@ def can_complete_bundle(self, bundle_requirements: Tuple[BundleItem], number_req return can_speak_junimo & self.has(tuple(item_rules), number_required) & self.farming.can_grow_crop_quality( highest_quality_yet) - @lru_cache(maxsize=None) + @cached_property def can_complete_community_center(self) -> StardewRule: return (self.region.can_reach_location("Complete Crafts Room") & self.region.can_reach_location("Complete Pantry") & diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 7192959dd038..a9f764a08815 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,5 +1,6 @@ -from functools import lru_cache +from functools import cached_property +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -24,38 +25,38 @@ def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLog def set_magic(self, magic: MagicLogic): self.magic = magic - @lru_cache(maxsize=None) + @cache_self1 def can_fight_at_level(self, level: str) -> StardewRule: if level == Performance.basic: - return self.has_any_weapon() | self.magic.has_any_spell() + return self.has_any_weapon | self.magic.has_any_spell() if level == Performance.decent: - return self.has_decent_weapon() | self.magic.has_decent_spells() + return self.has_decent_weapon | self.magic.has_decent_spells() if level == Performance.good: - return self.has_good_weapon() | self.magic.has_good_spells() + return self.has_good_weapon | self.magic.has_good_spells() if level == Performance.great: - return self.has_great_weapon() | self.magic.has_great_spells() + return self.has_great_weapon | self.magic.has_great_spells() if level == Performance.galaxy: - return self.has_galaxy_weapon() | self.magic.has_amazing_spells() + return self.has_galaxy_weapon | self.magic.has_amazing_spells() if level == Performance.maximum: - return self.has_galaxy_weapon() | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP + return self.has_galaxy_weapon | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP return False_() - @lru_cache(maxsize=None) + @cached_property def has_any_weapon(self) -> StardewRule: return self.received(valid_weapons, 1) - @lru_cache(maxsize=None) + @cached_property def has_decent_weapon(self) -> StardewRule: return Or(self.received(weapon, 2) for weapon in valid_weapons) - @lru_cache(maxsize=None) + @cached_property def has_good_weapon(self) -> StardewRule: return Or(self.received(weapon, 3) for weapon in valid_weapons) - @lru_cache(maxsize=None) + @cached_property def has_great_weapon(self) -> StardewRule: return Or(self.received(weapon, 4) for weapon in valid_weapons) - @lru_cache(maxsize=None) + @cached_property def has_galaxy_weapon(self) -> StardewRule: return Or(self.received(weapon, 5) for weapon in valid_weapons) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index d30fdc5852a0..235f630a954d 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,5 +1,6 @@ -from functools import lru_cache +from functools import cached_property +from Utils import cache_self1 from .action_logic import ActionLogic from .building_logic import BuildingLogic from .cached_logic import CachedLogic @@ -59,11 +60,11 @@ def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanit self.relationship = relationship self.skill = skill - @lru_cache(maxsize=None) + @cached_property def can_cook_in_kitchen(self) -> StardewRule: return self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) - @lru_cache(maxsize=None) + # Should be cached def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: cook_rule = self.region.can_reach(Region.kitchen) if recipe is None: @@ -75,7 +76,7 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: time_rule = self.time.has_lived_months(number_ingredients) return cook_rule & recipe_rule & ingredients_rule & time_rule - @lru_cache(maxsize=None) + # Should be cached def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: if self.chefsanity_option == Chefsanity.option_none: return self.can_learn_recipe(source) @@ -95,7 +96,7 @@ def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: return self.received_recipe(meal_name) return self.can_learn_recipe(source) - @lru_cache(maxsize=None) + @cache_self1 def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() @@ -110,15 +111,15 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, FriendshipSource): return self.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, QueenOfSauceSource): - year_rule = self.time.has_year_two() if source.year == 2 else self.time.has_year_three() + year_rule = self.time.has_year_two if source.year == 2 else self.time.has_year_three return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule return False_() - @lru_cache(maxsize=None) + @cache_self1 def received_recipe(self, meal_name: str): return self.received(f"{meal_name} Recipe") - @lru_cache(maxsize=None) + @cached_property def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " all_recipes_names = [] diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index fd81566106e0..e7b78b578b78 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,5 +1,4 @@ -from functools import lru_cache - +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic from .money_logic import MoneyLogic @@ -51,7 +50,7 @@ def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: C self.skill = skill self.special_orders = special_orders - @lru_cache(maxsize=None) + @cache_self1 def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: craft_rule = True_() if recipe is None: @@ -63,7 +62,7 @@ def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: time_rule = self.time.has_lived_months(number_ingredients) return craft_rule & learn_rule & ingredients_rule & time_rule - @lru_cache(maxsize=None) + @cache_self1 def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, ArchipelagoSource): return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) @@ -82,7 +81,7 @@ def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: return self.received_recipe(recipe.item) return self.can_learn_recipe(recipe) - @lru_cache(maxsize=None) + @cache_self1 def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, StarterSource): return True_() @@ -109,6 +108,6 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: return False_() - @lru_cache(maxsize=None) + @cache_self1 def received_recipe(self, item_name: str): return self.received(f"{item_name} Recipe") diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index f71b8fd9fa79..c4434495a81e 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,6 +1,6 @@ -from functools import lru_cache from typing import Union, Iterable +from Utils import cache_self1 from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic @@ -42,7 +42,7 @@ def __init__(self, player: int, cached_rules: CachedRules, cropsanity_option: Cr self.money = money self.tool = tool - @lru_cache(maxsize=None) + @cache_self1 def can_grow(self, crop: CropItem) -> StardewRule: season_rule = self.season.has_any(crop.farm_growth_seasons) seed_rule = self.has(crop.seed.name) @@ -62,7 +62,7 @@ def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> Stardew def has_island_farm(self) -> StardewRule: return self.region.can_reach(Region.island_south) - @lru_cache(maxsize=None) + @cache_self1 def can_buy_seed(self, seed: SeedItem) -> StardewRule: if self.cropsanity_option == Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 9b913fca107b..a47bfcccff40 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,5 +1,4 @@ -from functools import lru_cache - +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -51,7 +50,7 @@ def can_fish_chests(self) -> StardewRule: def can_fish_at(self, region: str) -> StardewRule: return self.skill.can_fish() & self.region.can_reach(region) - @lru_cache(maxsize=None) + @cache_self1 def can_catch_fish(self, fish: FishItem) -> StardewRule: quest_rule = True_() if fish.extended_family: @@ -59,7 +58,7 @@ def can_catch_fish(self, fish: FishItem) -> StardewRule: region_rule = self.region.can_reach_any(fish.locations) season_rule = self.season.has_any(fish.seasons) if fish.difficulty == -1: - difficulty_rule = self.skill.can_crab_pot() + difficulty_rule = self.skill.can_crab_pot else: difficulty_rule = self.skill.can_fish(difficulty=(120 if fish.legendary else fish.difficulty)) if fish.name == SVEFish.kittyfish: diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 79079a722c81..7ac88086be23 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,4 +1,4 @@ -from functools import lru_cache +from functools import cached_property from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules @@ -14,7 +14,7 @@ def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic): super().__init__(player, cached_rules) self.has = has - @lru_cache(maxsize=None) + @cached_property def has_any_universal_love(self) -> StardewRule: return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has( AnimalProduct.rabbit_foot) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 972db3f1ea68..27e9902802ae 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,4 +1,3 @@ -from functools import lru_cache from typing import Dict, Union, Optional, Tuple from .cached_logic import CachedLogic, CachedRules @@ -18,7 +17,7 @@ def __call__(self, *args, **kwargs) -> StardewRule: count = args[1] return self.has(args[0], count) - @lru_cache(maxsize=None) + # Should be cached def has(self, items: Union[str, Tuple[str]], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): return Has(items, self.item_rules) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index e37c63239bd9..6d0a41a61f50 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -293,18 +293,18 @@ def __post_init__(self): Decoration.rotten_plant: self.has(Lighting.jack_o_lantern) & self.season.has(Season.winter), Fertilizer.basic: (self.has(Material.sap) & self.skill.has_farming_level(1)) | (self.time.has_lived_months(1) & self.money.can_spend_at(Region.pierre_store, 100)), Fertilizer.deluxe: False_(), - Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two() & self.money.can_spend_at(Region.pierre_store, 150)), + Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150)), Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), Fish.any: Or([self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)]), - Fish.crab: self.skill.can_crab_pot(Region.beach), - Fish.crayfish: self.skill.can_crab_pot(Region.town), - Fish.lobster: self.skill.can_crab_pot(Region.beach), + Fish.crab: self.skill.can_crab_pot_at(Region.beach), + Fish.crayfish: self.skill.can_crab_pot_at(Region.town), + Fish.lobster: self.skill.can_crab_pot_at(Region.beach), Fish.mussel: self.tool.can_forage(Generic.any, Region.beach) or self.has(Fish.mussel_node), Fish.mussel_node: self.region.can_reach(Region.island_west), Fish.oyster: self.tool.can_forage(Generic.any, Region.beach), - Fish.periwinkle: self.skill.can_crab_pot(Region.town), - Fish.shrimp: self.skill.can_crab_pot(Region.beach), - Fish.snail: self.skill.can_crab_pot(Region.town), + Fish.periwinkle: self.skill.can_crab_pot_at(Region.town), + Fish.shrimp: self.skill.can_crab_pot_at(Region.beach), + Fish.snail: self.skill.can_crab_pot_at(Region.town), Fishing.curiosity_lure: self.monster.can_kill(all_monsters_by_name[Monster.mummy]), Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200), Forageable.blackberry: self.tool.can_forage(Season.fall), @@ -360,7 +360,7 @@ def __post_init__(self): Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Consumable.rain_totem), Gift.movie_ticket: self.money.can_spend_at(Region.movie_ticket_stand, 1000), Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), - Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months(), + Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months, Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200), Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), @@ -420,12 +420,12 @@ def __post_init__(self): Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), Seed.mixed: self.tool.has_tool(Tool.scythe) & self.region.can_reach_all((Region.farm, Region.forest, Region.town)), - Trash.broken_cd: self.skill.can_crab_pot(), - Trash.broken_glasses: self.skill.can_crab_pot(), - Trash.driftwood: self.skill.can_crab_pot(), + Trash.broken_cd: self.skill.can_crab_pot, + Trash.broken_glasses: self.skill.can_crab_pot, + Trash.driftwood: self.skill.can_crab_pot, Trash.joja_cola: self.money.can_spend_at(Region.saloon, 75), - Trash.soggy_newspaper: self.skill.can_crab_pot(), - Trash.trash: self.skill.can_crab_pot(), + Trash.soggy_newspaper: self.skill.can_crab_pot, + Trash.trash: self.skill.can_crab_pot, TreeSeed.acorn: self.skill.has_level(Skill.foraging, 1) & self.ability.can_chop_trees(), TreeSeed.mahogany: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.iron) & self.skill.has_level(Skill.foraging, 1), TreeSeed.maple: self.skill.has_level(Skill.foraging, 1) & self.ability.can_chop_trees(), @@ -495,13 +495,13 @@ def __post_init__(self): FestivalCheck.lupini_red_eagle: self.money.can_spend(1200), FestivalCheck.lupini_portrait_mermaid: self.money.can_spend(1200), FestivalCheck.lupini_solar_kingdom: self.money.can_spend(1200), - FestivalCheck.lupini_clouds: self.time.has_year_two() & self.money.can_spend(1200), - FestivalCheck.lupini_1000_years: self.time.has_year_two() & self.money.can_spend(1200), - FestivalCheck.lupini_three_trees: self.time.has_year_two() & self.money.can_spend(1200), - FestivalCheck.lupini_the_serpent: self.time.has_year_three() & self.money.can_spend(1200), - FestivalCheck.lupini_tropical_fish: self.time.has_year_three() & self.money.can_spend(1200), - FestivalCheck.lupini_land_of_clay: self.time.has_year_three() & self.money.can_spend(1200), - FestivalCheck.secret_santa: self.gifts.has_any_universal_love(), + FestivalCheck.lupini_clouds: self.time.has_year_two & self.money.can_spend(1200), + FestivalCheck.lupini_1000_years: self.time.has_year_two & self.money.can_spend(1200), + FestivalCheck.lupini_three_trees: self.time.has_year_two & self.money.can_spend(1200), + FestivalCheck.lupini_the_serpent: self.time.has_year_three & self.money.can_spend(1200), + FestivalCheck.lupini_tropical_fish: self.time.has_year_three & self.money.can_spend(1200), + FestivalCheck.lupini_land_of_clay: self.time.has_year_three & self.money.can_spend(1200), + FestivalCheck.secret_santa: self.gifts.has_any_universal_love, FestivalCheck.legend_of_the_winter_star: True_(), FestivalCheck.all_rarecrows: self.region.can_reach(Region.farm) & self.has_all_rarecrows(), }) @@ -572,20 +572,20 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: self.relationship.has_hearts("5", 8), # 5 Friends self.relationship.has_hearts("10", 8), # 10 friends self.pet.has_hearts(5), # Max Pet - self.bundle.can_complete_community_center(), # Community Center Completion - self.bundle.can_complete_community_center(), # CC Ceremony first point - self.bundle.can_complete_community_center(), # CC Ceremony second point + self.bundle.can_complete_community_center, # Community Center Completion + self.bundle.can_complete_community_center, # CC Ceremony first point + self.bundle.can_complete_community_center, # CC Ceremony second point self.received(Wallet.skull_key), # Skull Key obtained - self.wallet.has_rusty_key(), # Rusty key obtained + self.wallet.has_rusty_key, # Rusty key obtained ] return Count(12, rules_worth_a_point) def can_complete_all_monster_slaying_goals(self) -> StardewRule: - rules = [self.time.has_lived_max_months()] + rules = [self.time.has_lived_max_months] exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true - island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west] + island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern] for category in all_monsters_by_category: - if exclude_island and all(monster.locations[0] in island_regions for monster in all_monsters_by_category[category]): + if exclude_island and all(all(location in island_regions for location in monster.locations) for monster in all_monsters_by_category[category]): continue rules.append(self.monster.can_kill_any(all_monsters_by_category[category])) diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 9847cf53efe1..5b4d82cb0bbd 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,5 +1,4 @@ -from functools import lru_cache - +from Utils import cache_self1 from .cached_logic import CachedLogic from .combat_logic import CombatLogic, CachedRules from .received_logic import ReceivedLogic @@ -58,6 +57,7 @@ def can_mine_in_the_skull_cavern(self) -> StardewRule: return (self.can_progress_in_the_mines_from_floor(120) & self.region.can_reach(Region.skull_cavern)) + @cache_self1 def get_weapon_rule_for_floor_tier(self, tier: int): if tier >= 4: return self.combat.can_fight_at_level(Performance.galaxy) @@ -69,7 +69,7 @@ def get_weapon_rule_for_floor_tier(self, tier: int): return self.combat.can_fight_at_level(Performance.decent) return self.combat.can_fight_at_level(Performance.basic) - @lru_cache(maxsize=None) + @cache_self1 def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: tier = floor // 40 rules = [] @@ -83,7 +83,7 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: rules.append(self.skill.has_level(Skill.mining, skill_tier)) return And(rules) - @lru_cache(maxsize=None) + @cache_self1 def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: if floor < 0: floor = 0 @@ -91,11 +91,11 @@ def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: return self.received("Progressive Mine Elevator", floor // 5) return True_() - @lru_cache(maxsize=None) + @cache_self1 def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: tier = floor // 50 rules = [] - weapon_rule = self.combat.has_great_weapon() + weapon_rule = self.combat.has_great_weapon rules.append(weapon_rule) if self.tool_option & ToolProgression.option_progressive: rules.append(self.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 14662bf46518..22629a66f681 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,5 +1,4 @@ -from functools import lru_cache - +from Utils import cache_self1 from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic @@ -33,23 +32,23 @@ def __init__(self, player: int, cached_rules: CachedRules, starting_money_option self.region = region self.time = time - @lru_cache(maxsize=None) + @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() return self.time.has_lived_months(amount // MONEY_PER_MONTH) - @lru_cache(maxsize=None) + @cache_self1 def can_spend(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() return self.time.has_lived_months(amount // (MONEY_PER_MONTH // DISPOSABLE_INCOME_DIVISOR)) - @lru_cache(maxsize=None) + # Should be cached def can_spend_at(self, region: str, amount: int) -> StardewRule: return self.region.can_reach(region) & self.can_spend(amount) - @lru_cache(maxsize=None) + # Should be cached def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index d6040875831f..07c640b9868a 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,6 +1,6 @@ -from functools import lru_cache from typing import Iterable, Union, Hashable +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .combat_logic import CombatLogic from .region_logic import RegionLogic @@ -21,7 +21,7 @@ def __init__(self, player: int, cached_rules: CachedRules, region: RegionLogic, self.time = time self.combat = combat - @lru_cache(maxsize=None) + # Should be cached def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): monster = all_monsters_by_name[monster] @@ -32,16 +32,16 @@ def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> time_rule = self.time.has_lived_months(amount_tier * 2) return region_rule & combat_rule & time_rule - @lru_cache(maxsize=None) + @cache_self1 def can_kill_max(self, monster: StardewMonster) -> StardewRule: return self.can_kill(monster, MAX_MONTHS) - @lru_cache(maxsize=None) + # Should be cached def can_kill_any(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] return Or(rules) - @lru_cache(maxsize=None) + # Should be cached def can_kill_all(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] return And(rules) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 8f069c66223a..d4e98771c95b 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -1,6 +1,6 @@ -from functools import lru_cache from typing import List +from Utils import cache_self1 from .action_logic import ActionLogic from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules @@ -37,7 +37,7 @@ def can_donate_museum_items(self, number: int) -> StardewRule: def can_donate_museum_artifacts(self, number: int) -> StardewRule: return self.region.can_reach(Region.museum) & self.can_find_museum_artifacts(number) - @lru_cache(maxsize=None) + @cache_self1 def can_find_museum_item(self, item: MuseumItem) -> StardewRule: region_rule = self.region.can_reach_all_except_one(item.locations) geodes_rule = And([self.action.can_open_geode(geode) for geode in item.geodes]) diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 62ac54fe280b..88a63f6cfbb8 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -114,7 +114,7 @@ def initialize_rules(self): Quest.cryptic_note: self.has(Forageable.secret_note), Quest.fresh_fruit: self.season.has(Season.spring) & self.has(Fruit.apricot) & self.relationship.can_meet(NPC.emily), Quest.aquatic_research: self.season.has(Season.summer) & self.has(Fish.pufferfish) & self.relationship.can_meet(NPC.demetrius), - Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two() & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), + Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), Quest.mayors_need: self.season.has(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.relationship.can_meet(NPC.lewis), Quest.wanted_lobster: self.season.has(Season.fall) & self.season.has(Season.fall) & self.has(Fish.lobster) & self.relationship.can_meet(NPC.gus), Quest.pam_needs_juice: self.season.has(Season.fall) & self.has(ArtisanGood.battery_pack) & self.relationship.can_meet(NPC.pam), @@ -128,7 +128,7 @@ def initialize_rules(self): Quest.grannys_gift: self.season.has(Season.spring) & self.has(Forageable.leek) & self.relationship.can_meet(NPC.evelyn), Quest.exotic_spirits: self.season.has(Season.winter) & self.has(Forageable.coconut) & self.relationship.can_meet(NPC.gus), Quest.catch_a_lingcod: self.season.has(Season.winter) & self.has(Fish.lingcod) & self.relationship.can_meet(NPC.willy), - Quest.dark_talisman: self.region.can_reach(Region.railroad) & self.wallet.has_rusty_key() & self.relationship.can_meet(NPC.krobus), + Quest.dark_talisman: self.region.can_reach(Region.railroad) & self.wallet.has_rusty_key & self.relationship.can_meet(NPC.krobus), Quest.goblin_problem: self.region.can_reach(Region.witch_swamp), Quest.magic_ink: self.relationship.can_meet(NPC.wizard), Quest.the_pirates_wife: self.relationship.can_meet(NPC.kent) & self.relationship.can_meet(NPC.gus) & diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 389c4c3b9880..f7d70c793756 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,4 +1,3 @@ -from functools import lru_cache from typing import Union, Optional, Tuple from .cached_logic import CachedLogic, CachedRules @@ -16,7 +15,7 @@ def __call__(self, *args, **kwargs) -> StardewRule: count = args[1] return self.received(args[0], count) - @lru_cache(maxsize=None) + # Should be cached def received(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = 1) -> StardewRule: if count <= 0 or not items: return True_() diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index f91beb519920..be7a9ec0bc3b 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,6 +1,6 @@ -from functools import lru_cache from typing import Tuple +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, And, Or, Reach, Count @@ -10,19 +10,19 @@ class RegionLogic(CachedLogic): def __init__(self, player: int, cached_rules: CachedRules): super().__init__(player, cached_rules) - @lru_cache(maxsize=None) + @cache_self1 def can_reach(self, region_name: str) -> StardewRule: return Reach(region_name, "Region", self.player) - @lru_cache(maxsize=None) + @cache_self1 def can_reach_any(self, region_names: Tuple[str, ...]) -> StardewRule: return Or(self.can_reach(spot) for spot in region_names) - @lru_cache(maxsize=None) + @cache_self1 def can_reach_all(self, region_names: Tuple[str, ...]) -> StardewRule: return And(self.can_reach(spot) for spot in region_names) - @lru_cache(maxsize=None) + @cache_self1 def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule: region_names = list(region_names) num_required = len(region_names) - 1 @@ -30,10 +30,10 @@ def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule num_required = len(region_names) return Count(num_required, [self.can_reach(spot) for spot in region_names]) - @lru_cache(maxsize=None) - def can_reach_location(self, location_names: str) -> StardewRule: - return Reach(location_names, "Location", self.player) + @cache_self1 + def can_reach_location(self, location_name: str) -> StardewRule: + return Reach(location_name, "Location", self.player) - @lru_cache(maxsize=None) + @cache_self1 def can_reach_entrance(self, entrance_name: str) -> StardewRule: return Reach(entrance_name, "Entrance", self.player) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 34ee0645aafe..c66ddb919e02 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -1,7 +1,7 @@ import math -from functools import lru_cache from typing import Iterable, Union +from Utils import cache_self1 from .building_logic import BuildingLogic from .cached_logic import CachedLogic, cache_rule, profile_rule from .gift_logic import GiftLogic @@ -71,7 +71,7 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule: self.has_children(number_children - 1)] return And(baby_rules) - @lru_cache(maxsize=None) + # Should be cached def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() @@ -114,18 +114,18 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) return self.received_hearts(villager.name, hearts) - @lru_cache(maxsize=None) + # Should be cached def received_hearts(self, npc: str, hearts: int) -> StardewRule: return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) - @lru_cache(maxsize=None) + @cache_self1 def can_meet(self, npc: str) -> StardewRule: if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): return True_() villager = all_villagers_by_name[npc] rules = [self.region.can_reach_any(villager.locations)] if npc == NPC.kent: - rules.append(self.time.has_year_two()) + rules.append(self.time.has_year_two) elif npc == NPC.leo: rules.append(self.received("Island West Turtle")) elif npc == ModNPC.lance: @@ -140,10 +140,10 @@ def can_give_loved_gifts_to_everyone(self) -> StardewRule: continue meet_rule = self.can_meet(npc) rules.append(meet_rule) - loved_gifts_rules = And(rules) & self.gifts.has_any_universal_love() - return loved_gifts_rules + rules.append(self.gifts.has_any_universal_love) + return And(*rules) - @lru_cache(maxsize=None) + # Should be cached def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: if hearts <= 0: return True_() @@ -168,8 +168,17 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: else: earn_rule = self.time.has_lived_months(min(hearts // 2, 8)) - return previous_heart_rule & earn_rule - + rules = [previous_heart_rule, self.can_meet(npc)] + villager = all_villagers_by_name[npc] + if hearts > 2 or hearts > self.heart_size_option: + rules.append(self.season.has(villager.birthday)) + if villager.bachelor: + if hearts > 8: + rules.append(self.can_date(npc)) + if hearts > 10: + rules.append(self.can_marry(npc)) + + @cache_self1 def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] mod = npc.mod_name diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 182ebd80c7bd..3d7c287e65c5 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,6 +1,6 @@ -from functools import lru_cache from typing import Iterable +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .time_logic import TimeLogic @@ -22,7 +22,7 @@ def __init__(self, player: int, cached_rules: CachedRules, season_option: Season self.received = received_logic self.time = time - @lru_cache(maxsize=None) + @cache_self1 def has(self, season: str) -> StardewRule: if season == Generic.any: return True_() diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index df95ba1e3e76..0d09058a5f70 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,5 +1,6 @@ -from functools import lru_cache +from functools import cached_property +from Utils import cache_self1 from .building_logic import BuildingLogic from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic @@ -29,15 +30,17 @@ def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island self.region = region self.buildings = buildings - def can_use_shipping_bin(self, item: str = "") -> StardewRule: + @cached_property + def can_use_shipping_bin(self) -> StardewRule: return self.buildings.has_building(Building.shipping_bin) - @lru_cache(maxsize=None) - def can_ship(self, item: str = "") -> StardewRule: - shipping_rule = self.region.can_reach(Region.shipping) - if item == "": - return shipping_rule - return shipping_rule & self.has(item) + @cache_self1 + def can_ship(self, item: str) -> StardewRule: + return self.can_ship_items & self.has(item) + + @cached_property + def can_ship_items(self) -> StardewRule: + return self.region.can_reach(Region.shipping) def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index de6cdf058f00..7c6197a47222 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -1,6 +1,7 @@ -from functools import lru_cache +from functools import cached_property from typing import Union, Tuple +from Utils import cache_self1 from worlds.stardew_valley.strings.craftable_names import Fishing from .cached_logic import CachedLogic from .combat_logic import CombatLogic @@ -58,7 +59,7 @@ def set_mod_logic(self, magic: MagicLogic, mods: Mods): self.magic = magic self.mods = mods - @lru_cache(maxsize=None) + # Should be cached def can_earn_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -89,7 +90,7 @@ def can_earn_level(self, skill: str, level: int) -> StardewRule: return previous_level_rule & months_rule & xp_rule - @lru_cache(maxsize=None) + # Should be cached def has_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() @@ -99,11 +100,11 @@ def has_level(self, skill: str, level: int) -> StardewRule: return self.can_earn_level(skill, level) - @lru_cache(maxsize=None) + @cache_self1 def has_farming_level(self, level: int) -> StardewRule: return self.has_level(Skill.farming, level) - @lru_cache(maxsize=None) + # Should be cached def has_total_level(self, level: int, allow_modded_skills: bool = False) -> StardewRule: if level <= 0: return True_() @@ -116,45 +117,45 @@ def has_total_level(self, level: int, allow_modded_skills: bool = False) -> Star months_with_4_skills = max(1, (level // 4) - 1) months_with_5_skills = max(1, (level // 5) - 1) - rule_with_fishing = self.time.has_lived_months(months_with_5_skills) & self.can_get_fishing_xp() + rule_with_fishing = self.time.has_lived_months(months_with_5_skills) & self.can_get_fishing_xp if level > 40: return rule_with_fishing return self.time.has_lived_months(months_with_4_skills) | rule_with_fishing - @lru_cache(maxsize=None) + @cached_property def can_get_farming_xp(self) -> StardewRule: crop_rules = [] for crop in all_crops: crop_rules.append(self.crop.can_grow(crop)) return Or(crop_rules) - @lru_cache(maxsize=None) + @cached_property def can_get_foraging_xp(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.axe) tree_rule = self.region.can_reach(Region.forest) & self.season.has_any_not_winter() stump_rule = self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.copper) return tool_rule & (tree_rule | stump_rule) - @lru_cache(maxsize=None) + @cached_property def can_get_mining_xp(self) -> StardewRule: tool_rule = self.tool.has_tool(Tool.pickaxe) stone_rule = self.region.can_reach_any((Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5)) return tool_rule & stone_rule - @lru_cache(maxsize=None) + @cached_property def can_get_combat_xp(self) -> StardewRule: tool_rule = self.combat.has_any_weapon() enemy_rule = self.region.can_reach_any((Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5)) return tool_rule & enemy_rule - @lru_cache(maxsize=None) + @cached_property def can_get_fishing_xp(self) -> StardewRule: if self.skill_option == options.SkillProgression.option_progressive: - return self.can_fish() | self.can_crab_pot() + return self.can_fish() | self.can_crab_pot return self.can_fish() - @lru_cache(maxsize=None) + # Should be cached def can_fish(self, regions: Union[str, Tuple[str, ...]] = None, difficulty: int = 0) -> StardewRule: if isinstance(regions, str): regions = regions, @@ -168,16 +169,17 @@ def can_fish(self, regions: Union[str, Tuple[str, ...]] = None, difficulty: int number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule - @lru_cache(maxsize=None) - def can_crab_pot(self, region: str = Generic.any) -> StardewRule: + @cache_self1 + def can_crab_pot_at(self, region: str) -> StardewRule: + return self.can_crab_pot & self.region.can_reach(region) + + @cached_property + def can_crab_pot(self) -> StardewRule: crab_pot_rule = self.has(Fishing.bait) if self.skill_option == options.SkillProgression.option_progressive: crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) else: - crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp() - - if region != Generic.any: - return crab_pot_rule & self.region.can_reach(region) + crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp water_region_rules = self.region.can_reach_any(fishing_regions) return crab_pot_rule & water_region_rules diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index a3bd2ff97955..82429231d4c3 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -3,7 +3,6 @@ from .ability_logic import AbilityLogic from .arcade_logic import ArcadeLogic from .artisan_logic import ArtisanLogic -from .cached_logic import profile_rule from .cooking_logic import CookingLogic from .has_logic import HasLogic from .mine_logic import MineLogic @@ -88,8 +87,8 @@ def initialize_rules(self): SpecialOrder.gifts_for_george: self.season.has(Season.spring) & self.has(Forageable.leek), SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), - SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.shipping.can_ship(), - SpecialOrder.community_cleanup: self.skill.can_crab_pot(), + SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.shipping.can_ship_items, + SpecialOrder.community_cleanup: self.skill.can_crab_pot, SpecialOrder.the_strong_stuff: self.artisan.can_keg(Vegetable.potato), SpecialOrder.pierres_prime_produce: self.ability.can_farm_perfectly(), SpecialOrder.robins_project: self.relationship.can_meet(NPC.robin) & self.ability.can_chop_perfectly() & self.has(Material.hardwood), @@ -102,12 +101,12 @@ def initialize_rules(self): SpecialOrder.prismatic_jelly: self.region.can_reach(Region.wizard_tower), SpecialOrder.qis_crop: self.ability.can_farm_perfectly() & self.region.can_reach(Region.greenhouse) & self.region.can_reach(Region.island_west) & self.skill.has_total_level(50) & - self.has(Machine.seed_maker) & self.shipping.can_ship(), + self.has(Machine.seed_maker) & self.shipping.can_ship_items, SpecialOrder.lets_play_a_game: self.arcade.has_junimo_kart_max_level(), - SpecialOrder.four_precious_stones: self.time.has_lived_max_months() & self.has("Prismatic Shard") & + SpecialOrder.four_precious_stones: self.time.has_lived_max_months & self.has("Prismatic Shard") & self.ability.can_mine_perfectly_in_the_skull_cavern(), SpecialOrder.qis_hungry_challenge: self.ability.can_mine_perfectly_in_the_skull_cavern() & self.ability.has_max_buffs(), - SpecialOrder.qis_cuisine: self.cooking.can_cook() & self.shipping.can_ship() & + SpecialOrder.qis_cuisine: self.cooking.can_cook() & self.shipping.can_ship_items & (self.money.can_spend_at(Region.saloon, 205000) | self.money.can_spend_at(Region.pierre_store, 170000)), SpecialOrder.qis_kindness: self.relationship.can_give_loved_gifts_to_everyone(), SpecialOrder.extended_family: self.ability.can_fish_perfectly() & self.has(Fish.angler) & self.has(Fish.glacierfish) & diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index bd4611e94d7d..18e4e4cb96db 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,5 +1,6 @@ -from functools import lru_cache +from functools import cached_property +from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule @@ -15,16 +16,19 @@ def __init__(self, player: int, cached_rules: CachedRules, received_logic: Recei super().__init__(player, cached_rules) self.received = received_logic - @lru_cache(maxsize=None) + @cache_self1 def has_lived_months(self, number: int) -> StardewRule: number = max(0, min(number, MAX_MONTHS)) return self.received(Event.month_end, number) + @cached_property def has_lived_max_months(self) -> StardewRule: return self.has_lived_months(MAX_MONTHS) + @cached_property def has_year_two(self) -> StardewRule: return self.has_lived_months(4) + @cached_property def has_year_three(self) -> StardewRule: return self.has_lived_months(8) diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 03d30e4d42d7..77108a53b244 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,5 +1,4 @@ -from functools import lru_cache - +from Utils import cache_self1 from .cached_logic import CachedLogic from .has_logic import HasLogic, CachedRules from .money_logic import MoneyLogic @@ -52,7 +51,7 @@ def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProg def set_magic(self, magic: MagicLogic): self.magic = magic - @lru_cache(maxsize=None) + # Should be cached def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: if material == ToolMaterial.basic or tool == Tool.scythe: return True_() @@ -62,7 +61,7 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) - @lru_cache(maxsize=None) + @cache_self1 def has_fishing_rod(self, level: int) -> StardewRule: if self.tool_option & ToolProgression.option_progressive: return self.received(f"Progressive {Tool.fishing_rod}", level) @@ -73,7 +72,7 @@ def has_fishing_rod(self, level: int) -> StardewRule: level = min(level, 4) return self.money.can_spend_at(Region.fish_shop, prices[level]) - @lru_cache(maxsize=None) + # Should be cached def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: season_rule = self.season.has(season) region_rule = self.region.can_reach(region) @@ -81,7 +80,7 @@ def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = return season_rule & region_rule & self.has_tool(Tool.hoe) return season_rule & region_rule - @lru_cache(maxsize=None) + @cache_self1 def can_water(self, level: int) -> StardewRule: tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) spell_rule = self.received(MagicSpell.water) & self.magic.can_use_altar() & self.received( diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index c2f2110fa25f..97d7c9d27afb 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,4 +1,5 @@ -from .cached_logic import profile_rule +from functools import cached_property + from .museum_logic import MuseumLogic from ..stardew_rule import StardewRule from .received_logic import ReceivedLogic @@ -15,8 +16,10 @@ def __init__(self, player: int, received: ReceivedLogic, museum: MuseumLogic): self.received = received self.museum = museum + @cached_property def can_speak_dwarf(self) -> StardewRule: return self.received(Wallet.dwarvish_translation_guide) + @cached_property def has_rusty_key(self) -> StardewRule: return self.received(Wallet.rusty_key) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index c160816a8f13..412c8390623b 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -59,19 +59,19 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: def _get_sve_item_rules(self): return {SVEGift.aged_blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 28000), SVEGift.blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 3000), - SVESeed.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), + SVESeed.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon, ModLoot.green_mushroom: self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(SVESeed.stalk_seed), SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(SVESeed.fungus_seed), - SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon() & + SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon & self.tool.has_tool(Tool.axe,ToolMaterial.iron), SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(SVESeed.slime_seed), - SVESeed.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - SVESeed.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon(), - SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon(), + SVESeed.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon, + SVESeed.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon, + SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, SVEVegetable.void_root: self.season.has(Season.winter) & self.has(SVESeed.void_seed), - SVESeed.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon(), - SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon() & self.cooking.can_cook(), + SVESeed.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon, + SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon & self.cooking.can_cook(), SVEForage.winter_star_rose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.winter), SVEForage.bearberry: self.region.can_reach(Region.secret_woods) & self.season.has(Season.winter), SVEForage.poison_mushroom: self.region.can_reach(Region.secret_woods) & (self.season.has(Season.summer) | self.season.has(Season.fall)), diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index 121bff87a777..caa3e3e068db 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -60,7 +60,7 @@ def get_modded_special_orders_rules(self, vanilla_rules): special_orders.update({ ModSpecialOrder.junas_monster_mash: self.relationship.has_hearts(ModNPC.juna, 4) & vanilla_rules[SpecialOrder.a_curious_substance] & - self.wallet.has_rusty_key() & + self.wallet.has_rusty_key & self.region.can_reach(Region.forest) & self.has(Consumable.monster_musk) & self.has("Energy Tonic") & self.has(Material.sap) & self.has(Loot.bug_meat) & self.has(Edible.oil_of_garlic) & self.has(Meal.strange_bun) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 58846d0fe21a..e3bcfc336324 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -149,9 +149,8 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.skull_cavern_100, [Entrance.mine_to_skull_cavern_floor_125]), RegionData(Region.skull_cavern_125, [Entrance.mine_to_skull_cavern_floor_150]), RegionData(Region.skull_cavern_150, [Entrance.mine_to_skull_cavern_floor_175]), - RegionData(Region.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200, - Entrance.enter_dangerous_skull_cavern]), - RegionData(Region.skull_cavern_200), + RegionData(Region.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200]), + RegionData(Region.skull_cavern_200, [Entrance.enter_dangerous_skull_cavern]), RegionData(Region.dangerous_skull_cavern), RegionData(Region.island_south, [Entrance.island_south_to_west, Entrance.island_south_to_north, Entrance.island_south_to_east, Entrance.island_south_to_southeast, diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index ecbc47c141a0..df461a4ce31f 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -212,9 +212,9 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), - logic.wallet.has_rusty_key()) + logic.wallet.has_rusty_key) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), - logic.wallet.has_rusty_key()) + logic.wallet.has_rusty_key) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_abandoned_jojamart, player), logic.has_abandoned_jojamart()) movie_theater_rule = logic.has_movie_theater() @@ -229,7 +229,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_dangerous_skull_cavern, player), (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), - logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + logic.wallet.can_speak_dwarf & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), logic.traveling_merchant.has_days()) @@ -243,16 +243,16 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), - ((logic.wallet.has_rusty_key() & logic.region.can_reach(Region.railroad) & + ((logic.wallet.has_rusty_key & logic.region.can_reach(Region.railroad) & logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), logic.received("Club Card")) set_bedroom_entrance_rules(logic, multiworld, player, world_options) set_festival_entrance_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin()) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce)) @@ -315,9 +315,9 @@ def set_blacksmith_entrance_rules(logic, multiworld, player): def set_skill_entrance_rules(logic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), - logic.skill.can_get_farming_xp()) + logic.skill.can_get_farming_xp) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fishing, player), - logic.skill.can_get_fishing_xp()) + logic.skill.can_get_fishing_xp) def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, item_name: str, tool_material: str): @@ -397,7 +397,7 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), - logic.wallet.can_speak_dwarf()) + logic.wallet.can_speak_dwarf) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, diff --git a/worlds/stardew_valley/test/TestMultiplePlayers.py b/worlds/stardew_valley/test/TestMultiplePlayers.py new file mode 100644 index 000000000000..70552eceb010 --- /dev/null +++ b/worlds/stardew_valley/test/TestMultiplePlayers.py @@ -0,0 +1,92 @@ +from . import SVTestCase, setup_multiworld +from .. import True_ +from ..options import FestivalLocations, StartingMoney +from ..strings.festival_check_names import FestivalCheck + + +def get_access_rule(multiworld, player: int, location_name: str): + return multiworld.get_location(location_name, player).access_rule + + +class TestDifferentSettings(SVTestCase): + + def test_different_festival_settings(self): + options_no_festivals = {FestivalLocations.internal_name: FestivalLocations.option_disabled} + options_easy_festivals = {FestivalLocations.internal_name: FestivalLocations.option_easy} + options_hard_festivals = {FestivalLocations.internal_name: FestivalLocations.option_hard} + + multiplayer_options = [options_no_festivals, options_easy_festivals, options_hard_festivals] + multiworld = setup_multiworld(multiplayer_options) + + self.check_location_rule(multiworld, 1, FestivalCheck.egg_hunt, False) + self.check_location_rule(multiworld, 2, FestivalCheck.egg_hunt, True, False) + self.check_location_rule(multiworld, 3, FestivalCheck.egg_hunt, True, True) + + def test_different_money_settings(self): + options_no_festivals_unlimited_money = {FestivalLocations.internal_name: FestivalLocations.option_disabled, + StartingMoney.internal_name: -1} + options_no_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_disabled, + StartingMoney.internal_name: 5000} + options_easy_festivals_unlimited_money = {FestivalLocations.internal_name: FestivalLocations.option_easy, + StartingMoney.internal_name: -1} + options_easy_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_easy, + StartingMoney.internal_name: 5000} + options_hard_festivals_unlimited_money = {FestivalLocations.internal_name: FestivalLocations.option_hard, + StartingMoney.internal_name: -1} + options_hard_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_hard, + StartingMoney.internal_name: 5000} + + multiplayer_options = [options_no_festivals_unlimited_money, options_no_festivals_limited_money, + options_easy_festivals_unlimited_money, options_easy_festivals_limited_money, + options_hard_festivals_unlimited_money, options_hard_festivals_limited_money] + multiworld = setup_multiworld(multiplayer_options) + + self.check_location_rule(multiworld, 1, FestivalCheck.rarecrow_4, False) + self.check_location_rule(multiworld, 2, FestivalCheck.rarecrow_4, False) + + self.check_location_rule(multiworld, 3, FestivalCheck.rarecrow_4, True, True) + self.check_location_rule(multiworld, 4, FestivalCheck.rarecrow_4, True, False) + + self.check_location_rule(multiworld, 5, FestivalCheck.rarecrow_4, True, True) + self.check_location_rule(multiworld, 6, FestivalCheck.rarecrow_4, True, False) + + def test_money_rule_caching(self): + options_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_easy, + StartingMoney.internal_name: 5000} + options_festivals_limited_money = {FestivalLocations.internal_name: FestivalLocations.option_easy, + StartingMoney.internal_name: 5000} + + multiplayer_options = [options_festivals_limited_money, options_festivals_limited_money] + multiworld = setup_multiworld(multiplayer_options) + + player_1_rarecrow_2 = get_access_rule(multiworld, 1, FestivalCheck.rarecrow_2) + player_1_rarecrow_4 = get_access_rule(multiworld, 1, FestivalCheck.rarecrow_4) + player_2_rarecrow_2 = get_access_rule(multiworld, 2, FestivalCheck.rarecrow_2) + player_2_rarecrow_4 = get_access_rule(multiworld, 2, FestivalCheck.rarecrow_4) + + with self.subTest("Rules are not cached between players"): + self.assertNotEquals(id(player_1_rarecrow_2), id(player_2_rarecrow_2)) + self.assertNotEquals(id(player_1_rarecrow_4), id(player_2_rarecrow_4)) + + with self.subTest("Rules are cached for the same player"): + self.assertEquals(id(player_1_rarecrow_2), id(player_1_rarecrow_4)) + self.assertEquals(id(player_2_rarecrow_2), id(player_2_rarecrow_4)) + + def check_location_rule(self, multiworld, player: int, location_name: str, should_exist: bool, should_be_true: bool = False): + has = "has" if should_exist else "doesn't have" + rule = "without access rule" if should_be_true else f"with access rule" + rule_text = f" {rule}" if should_exist else "" + with self.subTest(f"Player {player} {has} {location_name}{rule_text}"): + locations = multiworld.get_locations(player) + locations_names = {location.name for location in locations} + if not should_exist: + self.assertNotIn(location_name, locations_names) + return None + + self.assertIn(location_name, locations_names) + access_rule = get_access_rule(multiworld, player, location_name) + if should_be_true: + self.assertEqual(access_rule, True_()) + else: + self.assertNotEqual(access_rule, True_()) + return access_rule diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index d88ad335d1d3..51ae535fec4f 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -625,10 +625,9 @@ class TestFriendsanityDatingRules(SVTestBase): } def test_earning_dating_heart_requires_dating(self): - month_name = "Month End" for i in range(12): - month_item = self.world.create_item(month_name) - self.multiworld.state.collect(month_item, event=True) + self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + 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) self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False) diff --git a/worlds/stardew_valley/test/checks/goal_checks.py b/worlds/stardew_valley/test/checks/goal_checks.py index 314904e9cd81..d525084b61e5 100644 --- a/worlds/stardew_valley/test/checks/goal_checks.py +++ b/worlds/stardew_valley/test/checks/goal_checks.py @@ -1,6 +1,6 @@ from BaseClasses import MultiWorld from .option_checks import get_stardew_options -from ... import options +from ... import options, ExcludeGingerIsland from .. import SVTestBase diff --git a/worlds/stardew_valley/test/checks/option_checks.py b/worlds/stardew_valley/test/checks/option_checks.py index 7a014747c256..418f9b3cd3e2 100644 --- a/worlds/stardew_valley/test/checks/option_checks.py +++ b/worlds/stardew_valley/test/checks/option_checks.py @@ -92,7 +92,8 @@ def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestBase, multiwo def assert_has_festival_recipes(tester: SVTestBase, multiworld: MultiWorld): - has_festivals = is_not_setting(multiworld, options.FestivalLocations.internal_name, options.FestivalLocations.option_disabled) + stardew_options = get_stardew_options(multiworld) + has_festivals = stardew_options.festival_locations.value != options.FestivalLocations.option_disabled festival_items = ["Tub o' Flowers Recipe", "Jack-O-Lantern Recipe", "Moonlight Jellies Banner", "Starport Decal"] for festival_item in festival_items: if has_festivals: diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index 3edf4616f43f..63f119d792f6 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -1,4 +1,5 @@ import unittest +from random import random from typing import Dict from BaseClasses import MultiWorld @@ -34,10 +35,12 @@ def test_given_option_pair_when_generate_then_basic_checks(self): option2_choices = get_option_choices(option2) for key1 in option1_choices: for key2 in option2_choices: - with self.subTest(f"{option1.internal_name}: {key1}, {option2.internal_name}: {key2}"): + # seed = int(random() * pow(10, 18) - 1) + seed = 738592514038774912 + with self.subTest(f"{option1.internal_name}: {key1}, {option2.internal_name}: {key2} [SEED: {seed}]"): choices = {option1.internal_name: option1_choices[key1], option2.internal_name: option2_choices[key2]} - multiworld = setup_solo_multiworld(choices) + multiworld = setup_solo_multiworld(choices, seed) basic_checks(self, multiworld) From 6bec30fd49689c9aa99a77c6a8eeb9f9d1f5258b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:13:40 -0500 Subject: [PATCH 149/482] - Revert accidental SC2 change --- worlds/_sc2common/bot/game_data.py | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/_sc2common/bot/game_data.py b/worlds/_sc2common/bot/game_data.py index 85d87fcb2716..50f10bd6692e 100644 --- a/worlds/_sc2common/bot/game_data.py +++ b/worlds/_sc2common/bot/game_data.py @@ -3,6 +3,7 @@ from bisect import bisect_left from dataclasses import dataclass +from functools import lru_cache from typing import Dict, List, Optional, Union from .data import Attribute, Race From fca2ff3e1d011b17279d3c2ce852f870281c5c03 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 13:22:03 -0500 Subject: [PATCH 150/482] - Add a test to detect if island access can get locked behind the island --- worlds/stardew_valley/regions.py | 1 + worlds/stardew_valley/test/TestRegions.py | 83 +++++++++++++++++++---- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index e3bcfc336324..28461a63ac5d 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -514,6 +514,7 @@ def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionD return updated_region + def create_regions(region_factory: RegionFactory, random: Random, world_options) -> Tuple[ Dict[str, Region], Dict[str, str]]: final_regions = create_final_regions(world_options) diff --git a/worlds/stardew_valley/test/TestRegions.py b/worlds/stardew_valley/test/TestRegions.py index 71794cf9a119..c975798906e3 100644 --- a/worlds/stardew_valley/test/TestRegions.py +++ b/worlds/stardew_valley/test/TestRegions.py @@ -1,11 +1,16 @@ import random import sys import unittest +from argparse import Namespace +from typing import Iterable, Dict, Set +from BaseClasses import Region, Entrance from . import SVTestCase, setup_solo_multiworld -from .. import options, StardewValleyWorld, StardewValleyOptions -from ..options import EntranceRandomization, ExcludeGingerIsland -from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag +from .. import StardewValleyWorld +from ..options import EntranceRandomization, ExcludeGingerIsland, StardewValleyOptions +from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag, create_final_regions +from ..strings.entrance_names import Entrance as EntranceName +from ..strings.region_names import Region as RegionName connections_by_name = {connection.name for connection in vanilla_connections} regions_by_name = {region.name for region in vanilla_regions} @@ -26,12 +31,35 @@ def test_connection_lead_somewhere(self): f"{connection.name} is leading to {connection.destination} but it does not exist.") -class TestEntranceRando(unittest.TestCase): +def explore_connections_tree_up_to_blockers(blocked_entrances: Set[str], connections_by_name, regions_by_name): + explored_entrances = set() + explored_regions = set() + entrances_to_explore = set() + current_node_name = "Menu" + current_node = regions_by_name[current_node_name] + entrances_to_explore.update(current_node.exits) + while entrances_to_explore: + current_entrance_name = entrances_to_explore.pop() + current_entrance = connections_by_name[current_entrance_name] + current_node_name = current_entrance.destination + + explored_entrances.add(current_entrance_name) + explored_regions.add(current_node_name) + + if current_entrance_name in blocked_entrances: + continue + + current_node = regions_by_name[current_node_name] + entrances_to_explore.update({entrance for entrance in current_node.exits if entrance not in explored_entrances}) + return explored_regions + + +class TestEntranceRando(SVTestCase): def test_entrance_randomization(self): - for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), - (options.EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION), - (options.EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: + for option, flag in [(EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), + (EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION), + (EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: # option = options.EntranceRandomization.option_buildings # flag = RandomizationFlag.BUILDINGS # for i in range(0, 100000): @@ -58,9 +86,9 @@ def test_entrance_randomization(self): f"Connections are duplicated in randomization. Seed = {seed}") def test_entrance_randomization_without_island(self): - for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), - (options.EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION), - (options.EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: + for option, flag in [(EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), + (EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION), + (EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]: with self.subTest(option=option, flag=flag): seed = random.randrange(sys.maxsize) rand = random.Random(seed) @@ -87,15 +115,44 @@ def test_entrance_randomization_without_island(self): self.assertEqual(len(set(randomized_connections.values())), len(randomized_connections.values()), f"Connections are duplicated in randomization. Seed = {seed}") + def test_cannot_put_island_access_on_island(self): + entrance_option = EntranceRandomization.option_buildings + buildings_flag = RandomizationFlag.BUILDINGS + string_options = {EntranceRandomization.internal_name: entrance_option, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false} + player = 1 + for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): + if name in string_options: + continue + string_options[name] = option.from_any(option.default) + world_options = StardewValleyOptions(**{option_key: string_options[option_key] for option_key in StardewValleyOptions.type_hints}) + + for i in range(0, 100 if self.skip_long_tests else 10000): + seed = random.randrange(sys.maxsize) + with self.subTest(msg=f"Seed: {seed}"): + rand = random.Random(seed) + final_regions = create_final_regions(world_options) + regions_by_name = {region.name: region for region in final_regions} + randomized_connections, randomized_data = randomize_connections(rand, world_options, regions_by_name) + connections_by_name = {connection.name: connection for connection in randomized_connections} + + blocked_entrances = {EntranceName.use_island_obelisk, EntranceName.boat_to_ginger_island} + required_regions = {RegionName.wizard_tower, RegionName.boat_tunnel} + self.assert_can_reach_any_region_before_blockers(required_regions, blocked_entrances, connections_by_name, regions_by_name) + + def assert_can_reach_any_region_before_blockers(self, required_regions, blocked_entrances, connections_by_name, regions_by_name): + explored_regions = explore_connections_tree_up_to_blockers(blocked_entrances, connections_by_name, regions_by_name) + self.assertTrue(any(region in explored_regions for region in required_regions)) + class TestEntranceClassifications(SVTestCase): def test_non_progression_are_all_accessible_with_empty_inventory(self): - for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), - (options.EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION)]: + for option, flag in [(EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN), + (EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION)]: seed = random.randrange(sys.maxsize) with self.subTest(flag=flag, msg=f"Seed: {seed}"): - multiworld_options = {options.EntranceRandomization.internal_name: option} + multiworld_options = {EntranceRandomization.internal_name: option} multiworld = setup_solo_multiworld(multiworld_options, seed) sv_world: StardewValleyWorld = multiworld.worlds[1] ap_entrances = {entrance.name: entrance for entrance in multiworld.get_entrances()} From f63c05dd36fc4a538f96ae32c5b4b4a03a006ba3 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 19:38:24 -0500 Subject: [PATCH 151/482] Fix entrance rando island bug # Conflicts: # worlds/stardew_valley/test/checks/option_checks.py --- worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/regions.py | 26 +++++++++++-------- .../test/{long => }/TestRandomWorlds.py | 12 ++++----- worlds/stardew_valley/test/__init__.py | 1 + .../stardew_valley/test/checks/goal_checks.py | 10 +++---- .../test/checks/option_checks.py | 26 +++++++++---------- .../test/long/TestOptionsLong.py | 4 +-- 7 files changed, 43 insertions(+), 38 deletions(-) rename worlds/stardew_valley/test/{long => }/TestRandomWorlds.py (84%) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 6d0a41a61f50..f3931b8f101a 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -754,4 +754,4 @@ def has_movie_theater(self) -> StardewRule: return self.received(CommunityUpgrade.movie_theater, 2) def can_use_obelisk(self, obelisk: str) -> StardewRule: - return self.region.can_reach(Region.wizard_tower) & self.received(obelisk) + return self.region.can_reach(Region.farm) & self.received(obelisk) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 28461a63ac5d..3cc07cb837ed 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -24,7 +24,6 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.farm, [Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse, - Entrance.use_desert_obelisk, Entrance.use_island_obelisk, Entrance.enter_coop, Entrance.enter_barn, Entrance.enter_shed, Entrance.enter_slime_hutch, Entrance.farming, Entrance.shipping]), @@ -83,7 +82,8 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: RegionData(Region.leah_house), RegionData(Region.sewer, [Entrance.enter_mutant_bug_lair]), RegionData(Region.mutant_bug_lair), - RegionData(Region.wizard_tower, [Entrance.enter_wizard_basement]), + RegionData(Region.wizard_tower, [Entrance.enter_wizard_basement, + Entrance.use_desert_obelisk, Entrance.use_island_obelisk]), RegionData(Region.wizard_basement), RegionData(Region.tent), RegionData(Region.carpenter, [Entrance.enter_sebastian_room]), @@ -642,8 +642,8 @@ def swap_connections_until_valid(regions_by_name, connections_by_name, randomize reachable_regions, unreachable_regions = find_reachable_regions(regions_by_name, connections_by_name, randomized_connections) if not unreachable_regions: return randomized_connections - swap_one_connection(regions_by_name, connections_by_name, randomized_connections, reachable_regions, - unreachable_regions, connections_to_randomize, random) + swap_one_random_connection(regions_by_name, connections_by_name, randomized_connections, reachable_regions, + unreachable_regions, connections_to_randomize, random) def find_reachable_regions(regions_by_name, connections_by_name, @@ -667,9 +667,9 @@ def find_reachable_regions(regions_by_name, connections_by_name, return reachable_regions, unreachable_regions -def swap_one_connection(regions_by_name, connections_by_name,randomized_connections: Dict[ConnectionData, ConnectionData], - reachable_regions: Set[str], unreachable_regions: Set[str], - connections_to_randomize: List[ConnectionData], random: Random): +def swap_one_random_connection(regions_by_name, connections_by_name, randomized_connections: Dict[ConnectionData, ConnectionData], + reachable_regions: Set[str], unreachable_regions: Set[str], + connections_to_randomize: List[ConnectionData], random: Random): randomized_connections_already_shuffled = {connection: randomized_connections[connection] for connection in randomized_connections if connection != randomized_connections[connection]} @@ -691,7 +691,11 @@ def swap_one_connection(regions_by_name, connections_by_name,randomized_connecti chosen_reachable_entrance_name = random.choice(chosen_reachable_region.exits) chosen_reachable_entrance = connections_by_name[chosen_reachable_entrance_name] - reachable_destination = randomized_connections[chosen_reachable_entrance] - unreachable_destination = randomized_connections[chosen_unreachable_entrance] - randomized_connections[chosen_reachable_entrance] = unreachable_destination - randomized_connections[chosen_unreachable_entrance] = reachable_destination + swap_two_connections(chosen_reachable_entrance, chosen_unreachable_entrance, randomized_connections) + + +def swap_two_connections(entrance_1, entrance_2, randomized_connections): + reachable_destination = randomized_connections[entrance_1] + unreachable_destination = randomized_connections[entrance_2] + randomized_connections[entrance_1] = unreachable_destination + randomized_connections[entrance_2] = reachable_destination diff --git a/worlds/stardew_valley/test/long/TestRandomWorlds.py b/worlds/stardew_valley/test/TestRandomWorlds.py similarity index 84% rename from worlds/stardew_valley/test/long/TestRandomWorlds.py rename to worlds/stardew_valley/test/TestRandomWorlds.py index 502f2ad51a0e..ab677a869627 100644 --- a/worlds/stardew_valley/test/long/TestRandomWorlds.py +++ b/worlds/stardew_valley/test/TestRandomWorlds.py @@ -3,12 +3,12 @@ from BaseClasses import MultiWorld from Options import NamedRange, Range -from .option_names import options_to_include -from .. import setup_solo_multiworld, SVTestCase -from ..checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid -from ..checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ +from worlds.stardew_valley.test.long.option_names import options_to_include +from worlds.stardew_valley.test import setup_solo_multiworld, SVTestCase +from worlds.stardew_valley.test.checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid +from worlds.stardew_valley.test.checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ assert_festivals_give_access_to_deluxe_scarecrow, assert_has_festival_recipes -from ..checks.world_checks import assert_same_number_items_locations, assert_victory_exists +from worlds.stardew_valley.test.checks.world_checks import assert_same_number_items_locations, assert_victory_exists def get_option_choices(option) -> Dict[str, int]: @@ -95,6 +95,6 @@ class TestGenerateManyWorlds(SVTestCase): def test_generate_many_worlds_then_check_results(self): if self.skip_long_tests: return - number_worlds = 1000 + number_worlds = 10 if self.skip_long_tests else 1000 start_index = random.Random().randint(0, 9999999999) multiworlds = generate_and_check_many_worlds(self, number_worlds, start_index) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index ff95453c3ce1..fdee41473398 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -155,6 +155,7 @@ def setUp(self) -> None: performance_tests_key = "performance" if performance_tests_key in os.environ: self.skip_performance_tests = not bool(os.environ[performance_tests_key]) + self.skip_performance_tests = False class SVTestBase(WorldTestBase, SVTestCase): diff --git a/worlds/stardew_valley/test/checks/goal_checks.py b/worlds/stardew_valley/test/checks/goal_checks.py index d525084b61e5..82b2c51d9c56 100644 --- a/worlds/stardew_valley/test/checks/goal_checks.py +++ b/worlds/stardew_valley/test/checks/goal_checks.py @@ -1,7 +1,7 @@ from BaseClasses import MultiWorld from .option_checks import get_stardew_options from ... import options, ExcludeGingerIsland -from .. import SVTestBase +from .. import SVTestCase def is_goal(multiworld: MultiWorld, goal: int) -> bool: @@ -32,24 +32,24 @@ def is_not_perfection(multiworld: MultiWorld) -> bool: return not is_perfection(multiworld) -def assert_ginger_island_is_included(tester: SVTestBase, multiworld: MultiWorld): +def assert_ginger_island_is_included(tester: SVTestCase, multiworld: MultiWorld): tester.assertEqual(get_stardew_options(multiworld).exclude_ginger_island, ExcludeGingerIsland.option_false) -def assert_walnut_hunter_world_is_valid(tester: SVTestBase, multiworld: MultiWorld): +def assert_walnut_hunter_world_is_valid(tester: SVTestCase, multiworld: MultiWorld): if is_not_walnut_hunter(multiworld): return assert_ginger_island_is_included(tester, multiworld) -def assert_perfection_world_is_valid(tester: SVTestBase, multiworld: MultiWorld): +def assert_perfection_world_is_valid(tester: SVTestCase, multiworld: MultiWorld): if is_not_perfection(multiworld): return assert_ginger_island_is_included(tester, multiworld) -def assert_goal_world_is_valid(tester: SVTestBase, multiworld: MultiWorld): +def assert_goal_world_is_valid(tester: SVTestCase, multiworld: MultiWorld): assert_walnut_hunter_world_is_valid(tester, multiworld) assert_perfection_world_is_valid(tester, multiworld) diff --git a/worlds/stardew_valley/test/checks/option_checks.py b/worlds/stardew_valley/test/checks/option_checks.py index 418f9b3cd3e2..5caa1c9fa150 100644 --- a/worlds/stardew_valley/test/checks/option_checks.py +++ b/worlds/stardew_valley/test/checks/option_checks.py @@ -1,6 +1,6 @@ from BaseClasses import MultiWorld from .world_checks import get_all_item_names, get_all_location_names -from .. import SVTestBase +from .. import SVTestCase from ... import StardewValleyWorld, options, item_table, Group, location_table, ExcludeGingerIsland from ...locations import LocationTags from ...strings.ap_names.transport_names import Transportation @@ -18,39 +18,39 @@ def get_stardew_options(multiworld: MultiWorld) -> options.StardewValleyOptions: return get_stardew_world(multiworld).options -def assert_has_item(tester: SVTestBase, multiworld: MultiWorld, item: str): +def assert_has_item(tester: SVTestCase, multiworld: MultiWorld, item: str): all_item_names = set(get_all_item_names(multiworld)) tester.assertIn(item, all_item_names) -def assert_has_not_item(tester: SVTestBase, multiworld: MultiWorld, item: str): +def assert_has_not_item(tester: SVTestCase, multiworld: MultiWorld, item: str): all_item_names = set(get_all_item_names(multiworld)) tester.assertNotIn(item, all_item_names) -def assert_has_location(tester: SVTestBase, multiworld: MultiWorld, item: str): +def assert_has_location(tester: SVTestCase, multiworld: MultiWorld, item: str): all_location_names = set(get_all_location_names(multiworld)) tester.assertIn(item, all_location_names) -def assert_has_not_location(tester: SVTestBase, multiworld: MultiWorld, item: str): +def assert_has_not_location(tester: SVTestCase, multiworld: MultiWorld, item: str): all_location_names = set(get_all_location_names(multiworld)) tester.assertNotIn(item, all_location_names) -def assert_can_reach_island(tester: SVTestBase, multiworld: MultiWorld): +def assert_can_reach_island(tester: SVTestCase, multiworld: MultiWorld): all_item_names = get_all_item_names(multiworld) tester.assertIn(Transportation.boat_repair, all_item_names) tester.assertIn(Transportation.island_obelisk, all_item_names) -def assert_cannot_reach_island(tester: SVTestBase, multiworld: MultiWorld): +def assert_cannot_reach_island(tester: SVTestCase, multiworld: MultiWorld): all_item_names = get_all_item_names(multiworld) tester.assertNotIn(Transportation.boat_repair, all_item_names) tester.assertNotIn(Transportation.island_obelisk, all_item_names) -def assert_can_reach_island_if_should(tester: SVTestBase, multiworld: MultiWorld): +def assert_can_reach_island_if_should(tester: SVTestCase, multiworld: MultiWorld): stardew_options = get_stardew_options(multiworld) include_island = stardew_options.exclude_ginger_island.value == ExcludeGingerIsland.option_false if include_island: @@ -59,7 +59,7 @@ def assert_can_reach_island_if_should(tester: SVTestBase, multiworld: MultiWorld assert_cannot_reach_island(tester, multiworld) -def assert_cropsanity_same_number_items_and_locations(tester: SVTestBase, multiworld: MultiWorld): +def assert_cropsanity_same_number_items_and_locations(tester: SVTestCase, multiworld: MultiWorld): is_cropsanity = get_stardew_options(multiworld).cropsanity.value == options.Cropsanity.option_enabled if not is_cropsanity: return @@ -71,17 +71,17 @@ def assert_cropsanity_same_number_items_and_locations(tester: SVTestBase, multiw tester.assertEqual(len(all_cropsanity_item_names), len(all_cropsanity_location_names)) -def assert_all_rarecrows_exist(tester: SVTestBase, multiworld: MultiWorld): +def assert_all_rarecrows_exist(tester: SVTestCase, multiworld: MultiWorld): all_item_names = set(get_all_item_names(multiworld)) for rarecrow_number in range(1, 9): tester.assertIn(f"Rarecrow #{rarecrow_number}", all_item_names) -def assert_has_deluxe_scarecrow_recipe(tester: SVTestBase, multiworld: MultiWorld): +def assert_has_deluxe_scarecrow_recipe(tester: SVTestCase, multiworld: MultiWorld): assert_has_item(tester, multiworld, "Deluxe Scarecrow Recipe") -def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestBase, multiworld: MultiWorld): +def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestCase, multiworld: MultiWorld): stardew_options = get_stardew_options(multiworld) has_festivals = stardew_options.festival_locations.value != options.FestivalLocations.option_disabled if not has_festivals: @@ -91,7 +91,7 @@ def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestBase, multiwo assert_has_deluxe_scarecrow_recipe(tester, multiworld) -def assert_has_festival_recipes(tester: SVTestBase, multiworld: MultiWorld): +def assert_has_festival_recipes(tester: SVTestCase, multiworld: MultiWorld): stardew_options = get_stardew_options(multiworld) has_festivals = stardew_options.festival_locations.value != options.FestivalLocations.option_disabled festival_items = ["Tub o' Flowers Recipe", "Jack-O-Lantern Recipe", "Moonlight Jellies Banner", "Starport Decal"] diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index 63f119d792f6..f7f9ee8fd179 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -35,8 +35,8 @@ def test_given_option_pair_when_generate_then_basic_checks(self): option2_choices = get_option_choices(option2) for key1 in option1_choices: for key2 in option2_choices: - # seed = int(random() * pow(10, 18) - 1) - seed = 738592514038774912 + seed = int(random() * pow(10, 18) - 1) + # seed = 738592514038774912 with self.subTest(f"{option1.internal_name}: {key1}, {option2.internal_name}: {key2} [SEED: {seed}]"): choices = {option1.internal_name: option1_choices[key1], option2.internal_name: option2_choices[key2]} From d0a00121ca1e5edb49b10dc7c25ec0d4147b2dab Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 21:10:11 -0500 Subject: [PATCH 152/482] removed debug line --- worlds/stardew_valley/test/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index fdee41473398..ff95453c3ce1 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -155,7 +155,6 @@ def setUp(self) -> None: performance_tests_key = "performance" if performance_tests_key in os.environ: self.skip_performance_tests = not bool(os.environ[performance_tests_key]) - self.skip_performance_tests = False class SVTestBase(WorldTestBase, SVTestCase): From 7eee1c19d6ce1800bdbd690a7647f21a7ddab4a8 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 22:43:36 -0500 Subject: [PATCH 153/482] - Added craft master goal # Conflicts: # worlds/stardew_valley/options.py --- worlds/stardew_valley/__init__.py | 4 +++ worlds/stardew_valley/locations.py | 1 + worlds/stardew_valley/logic/cooking_logic.py | 8 +++--- worlds/stardew_valley/logic/crafting_logic.py | 25 ++++++++++++++++--- worlds/stardew_valley/logic/logic.py | 6 ++--- worlds/stardew_valley/options.py | 4 +-- worlds/stardew_valley/strings/goal_names.py | 1 + 7 files changed, 37 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index de127c8b4364..6d890667272a 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -232,6 +232,10 @@ def setup_victory(self): self.create_event_location(location_table[GoalName.gourmet_chef], self.logic.cooking.can_cook_everything, Event.victory) + elif self.options.goal == options.Goal.option_craft_master: + self.create_event_location(location_table[GoalName.craft_master], + self.logic.crafting.can_craft_everything, + Event.victory) elif self.options.goal == options.Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], self.logic.has_everything(frozenset(self.all_progression_items)).simplify(), diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 3a43344b9377..5885262b0de2 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -140,6 +140,7 @@ def load_location_csv() -> List[LocationData]: LocationData(None, Region.adventurer_guild, Goal.protector_of_the_valley), LocationData(None, Region.shipping, Goal.full_shipment), LocationData(None, Region.kitchen, Goal.gourmet_chef), + LocationData(None, Region.farm, Goal.craft_master), LocationData(None, Region.qi_walnut_room, Goal.perfection), ] diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 235f630a954d..181078faf058 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -26,9 +26,9 @@ class CookingLogic(CachedLogic): - mods: Mods chefsanity_option: Chefsanity exclude_ginger_island: ExcludeGingerIsland + mods: Mods received: ReceivedLogic has: HasLogic region: RegionLogic @@ -40,15 +40,15 @@ class CookingLogic(CachedLogic): relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, cached_rules: CachedRules, mods: Mods, chefsanity_option: Chefsanity, - exclude_ginger_island: ExcludeGingerIsland, received: ReceivedLogic, + def __init__(self, player: int, cached_rules: CachedRules, chefsanity_option: Chefsanity, + exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): super().__init__(player, cached_rules) - self.mods = mods self.chefsanity_option = chefsanity_option self.exclude_ginger_island = exclude_ginger_island + self.mods = mods self.received = received self.has = has self.region = region diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index e7b78b578b78..3f9624bd7235 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,3 +1,5 @@ +from functools import cached_property + from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic @@ -9,17 +11,20 @@ from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogic from .. import options -from ..data.craftable_data import CraftingRecipe +from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name from ..data.recipe_data import StarterSource, ShopSource, SkillSource, FriendshipSource from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, \ FestivalShopSource -from ..options import Craftsanity, FestivalLocations, SpecialOrderLocations +from ..locations import locations_by_tag, LocationTags +from ..options import Craftsanity, FestivalLocations, SpecialOrderLocations, ExcludeGingerIsland, Mods from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region class CraftingLogic(CachedLogic): craftsanity_option: Craftsanity + exclude_ginger_island: ExcludeGingerIsland + mods: Mods festivals_option: FestivalLocations special_orders_option: SpecialOrderLocations received: ReceivedLogic @@ -32,7 +37,7 @@ class CraftingLogic(CachedLogic): special_orders: SpecialOrderLogic def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: Craftsanity, - festivals_option: FestivalLocations, + exclude_ginger_island: ExcludeGingerIsland, mods: Mods, festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, @@ -111,3 +116,17 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: @cache_self1 def received_recipe(self, item_name: str): return self.received(f"{item_name} Recipe") + + @cached_property + def can_craft_everything(self) -> StardewRule: + craftsanity_prefix = "Craft " + all_recipes_names = [] + exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true + for location in locations_by_tag[LocationTags.CRAFTSANITY]: + if exclude_island and LocationTags.GINGER_ISLAND in location.tags: + continue + if location.mod_name and location.mod_name not in self.mods: + continue + all_recipes_names.append(location.name[len(craftsanity_prefix):]) + all_recipes = [all_crafting_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] + return And(*(self.can_craft(recipe) for recipe in all_recipes)) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index f3931b8f101a..6e941f81e52d 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -142,7 +142,7 @@ def __post_init__(self): self.tool, self.skill) self.mine = MineLogic(self.player, self.cached_rules, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.cached_rules, mods_option, self.options.chefsanity, exclude_ginger_island, self.received, self.has, + self.cooking = CookingLogic(self.player, self.cached_rules, self.options.chefsanity, exclude_ginger_island, mods_option, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) @@ -150,8 +150,8 @@ def __post_init__(self): self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, self.time, self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, self.wallet, mods_option) - self.crafting = CraftingLogic(self.player, self.cached_rules, self.options.craftsanity, self.options.festival_locations, - special_order_locations, self.received, self.has, self.region, self.time, self.money, + self.crafting = CraftingLogic(self.player, self.cached_rules, self.options.craftsanity, exclude_ginger_island, mods_option, + self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 4d6435756d3a..0abec73920f8 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -18,6 +18,7 @@ class Goal(Choice): Protector of the Valley: Complete all the monster slayer goals. Pairs well with Monstersanity Full Shipment: Ship every item in the collection tab. Pairs well with Shipsanity Gourmet Chef: Cook every recipe. Pairs well with Chefsanity and Cooksanity + Craft Master: Craft every item. Pairs well with Craftsanity Perfection: Attain Perfection, based on the vanilla definition. """ internal_name = "goal" @@ -34,12 +35,11 @@ class Goal(Choice): option_protector_of_the_valley = 8 option_full_shipment = 9 option_gourmet_chef = 10 + option_craft_master = 11 # option_junimo_kart = # option_prairie_king = # option_fector_challenge = - # option_craft_master = # option_mystery_of_the_stardrops = - # option_full_shipment = # option_legend = # option_beloved_farmer = # option_master_of_the_five_ways = diff --git a/worlds/stardew_valley/strings/goal_names.py b/worlds/stardew_valley/strings/goal_names.py index 6df0fd208168..84b942714eda 100644 --- a/worlds/stardew_valley/strings/goal_names.py +++ b/worlds/stardew_valley/strings/goal_names.py @@ -10,4 +10,5 @@ class Goal: protector_of_the_valley = "Protector of the Valley" full_shipment = "Full Shipment" gourmet_chef = "Gourmet Chef" + craft_master = "Craft Master" perfection = "Perfection" From 2ebc5d78fea77bfc00597bfc7877ba97add2404b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 22:46:11 -0500 Subject: [PATCH 154/482] - Fix craft master condition --- worlds/stardew_valley/logic/crafting_logic.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 3f9624bd7235..76258b760d6e 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -44,6 +44,8 @@ def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: C special_orders: SpecialOrderLogic): super().__init__(player, cached_rules) self.craftsanity_option = craftsanity_option + self.exclude_ginger_island = exclude_ginger_island + self.mods = mods self.festivals_option = festivals_option self.special_orders_option = special_orders_option self.received = received @@ -123,6 +125,8 @@ def can_craft_everything(self) -> StardewRule: all_recipes_names = [] exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true for location in locations_by_tag[LocationTags.CRAFTSANITY]: + if not location.name.startswith(craftsanity_prefix): + continue if exclude_island and LocationTags.GINGER_ISLAND in location.tags: continue if location.mod_name and location.mod_name not in self.mods: From 4db66b6740090a1e702e66fefabcb2779fc16efa Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 23:07:45 -0500 Subject: [PATCH 155/482] - Fix Craft Master requiring the QI recipes --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/items.py | 3 ++- worlds/stardew_valley/test/__init__.py | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 89cd08318f89..258419cd5965 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -419,7 +419,7 @@ id,name,classification,groups,mod_name 441,Crystal Path Recipe,progression,"CRAFTSANITY", 442,Wedding Ring Recipe,progression,"CRAFTSANITY", 443,Warp Totem: Desert Recipe,progression,"CRAFTSANITY", -444,Warp Totem: Island Recipe,progression,"CRAFTSANITY", +444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", 445,Torch Recipe,progression,"CRAFTSANITY", 446,Campfire Recipe,progression,"CRAFTSANITY", 447,Wooden Brazier Recipe,progression,"CRAFTSANITY", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f4197d1dd6b1..c3f00fb846a7 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1887,7 +1887,7 @@ id,region,name,tags,mod_name 3419,Farm,Craft Preserves Jar,"CRAFTSANITY", 3420,Farm,Craft Basic Fertilizer,"CRAFTSANITY", 3421,Farm,Craft Quality Fertilizer,"CRAFTSANITY", -3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY", +3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY,GINGER_ISLAND", 3423,Farm,Craft Speed-Gro,"CRAFTSANITY", 3424,Farm,Craft Deluxe Speed-Gro,"CRAFTSANITY", 3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 5d44cceef889..d10e8925895d 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -511,7 +511,8 @@ def create_tv_channels(item_factory: StardewItemFactory, items: List[Item]): def create_crafting_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): has_shipsanity = options.shipsanity == Shipsanity.option_everything has_craftsanity = options.craftsanity == Craftsanity.option_all - need_qi_recipes = has_shipsanity or has_craftsanity + has_craft_master = options.goal == Goal.option_craft_master + need_qi_recipes = has_shipsanity or has_craftsanity or has_craft_master crafting_recipes = [] if need_qi_recipes: crafting_recipes.extend([recipe for recipe in items_by_group[Group.QI_CRAFTING_RECIPE]]) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index ff95453c3ce1..101c07fb9928 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -60,7 +60,7 @@ def get_minsanity_options(): @cache_argsless def minimal_locations_maximal_items(): min_max_options = { - Goal.internal_name: Goal.option_bottom_of_the_mines, + Goal.internal_name: Goal.option_craft_master, BundleRandomization.internal_name: BundleRandomization.option_vanilla, BundlePrice.internal_name: BundlePrice.option_very_cheap, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, From b81e382b071ae8b0602862c24db641315c0fdfd5 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 15 Nov 2023 23:33:07 -0500 Subject: [PATCH 156/482] - Fixed deluxe retaining soil's ginger island flag --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 258419cd5965..64c502b56c3f 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -402,7 +402,7 @@ id,name,classification,groups,mod_name 419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 425,Gate Recipe,progression,"CRAFTSANITY", 426,Wood Fence Recipe,progression,"CRAFTSANITY", -427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY", +427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", 428,Grass Starter Recipe,progression,"CRAFTSANITY", 429,Wood Floor Recipe,progression,"CRAFTSANITY", 430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c3f00fb846a7..75b5cdb991b3 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1887,13 +1887,13 @@ id,region,name,tags,mod_name 3419,Farm,Craft Preserves Jar,"CRAFTSANITY", 3420,Farm,Craft Basic Fertilizer,"CRAFTSANITY", 3421,Farm,Craft Quality Fertilizer,"CRAFTSANITY", -3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY,GINGER_ISLAND", +3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY", 3423,Farm,Craft Speed-Gro,"CRAFTSANITY", 3424,Farm,Craft Deluxe Speed-Gro,"CRAFTSANITY", 3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", 3426,Farm,Craft Basic Retaining Soil,"CRAFTSANITY", 3427,Farm,Craft Quality Retaining Soil,"CRAFTSANITY", -3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY", +3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", 3429,Farm,Craft Tree Fertilizer,"CRAFTSANITY", 3430,Farm,Craft Spring Seeds,"CRAFTSANITY", 3431,Farm,Craft Summer Seeds,"CRAFTSANITY", From 5c7805f45569dd226c1a75232bf1dfbb9ebf8a44 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 16 Nov 2023 18:33:12 -0500 Subject: [PATCH 157/482] - Only have babies and baby checks if some level of friendsanity is enabled --- worlds/stardew_valley/data/locations.csv | 4 ++-- worlds/stardew_valley/items.py | 4 ++-- worlds/stardew_valley/locations.py | 17 +++++++++-------- .../stardew_valley/logic/relationship_logic.py | 2 ++ worlds/stardew_valley/rules.py | 17 ++++++++++------- worlds/stardew_valley/test/TestItems.py | 4 +++- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 75b5cdb991b3..e45de3e254f6 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -240,8 +240,8 @@ id,region,name,tags,mod_name 701,Secret Woods,Old Master Cannoli,MANDATORY, 702,Beach,Beach Bridge Repair,MANDATORY, 703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,MANDATORY, -705,Farmhouse,Have Another Baby,MANDATORY, +704,Farmhouse,Have a Baby,"BABY", +705,Farmhouse,Have Another Baby,"BABY", 801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, 802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, 803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index d10e8925895d..b5273b2fc90e 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -206,7 +206,6 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_seeds(item_factory, options, items) create_friendsanity_items(item_factory, options, items, random) create_festival_rewards(item_factory, options, items) - create_babies(item_factory, items, random) create_special_order_board_rewards(item_factory, options, items) create_special_order_qi_rewards(item_factory, options, items) create_walnut_purchase_rewards(item_factory, options, items) @@ -354,10 +353,11 @@ def create_museum_items(item_factory: StardewItemFactory, options: StardewValley items.append(item_factory("Stardrop", get_stardrop_classification(options))) -def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item], random): +def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item], random: Random): island_villagers = [NPC.leo, ModNPC.lance] if options.friendsanity == Friendsanity.option_none: return + create_babies(item_factory, items, random) exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors exclude_locked_villagers = options.friendsanity == Friendsanity.option_starting_npcs or \ options.friendsanity == Friendsanity.option_bachelors diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 5885262b0de2..e6ef95c17e1f 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -64,7 +64,8 @@ class LocationTags(enum.Enum): REQUIRES_QI_ORDERS = enum.auto() GINGER_ISLAND = enum.auto() WALNUT_PURCHASE = enum.auto() - REQUIRES_MUSEUM = enum.auto() + + BABY = enum.auto() MONSTERSANITY = enum.auto() MONSTERSANITY_GOALS = enum.auto() MONSTERSANITY_PROGRESSIVE_GOALS = enum.auto() @@ -229,6 +230,7 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti if options.friendsanity == Friendsanity.option_none: return + extend_baby_locations(randomized_locations) exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors exclude_locked_villagers = options.friendsanity == Friendsanity.option_starting_npcs or \ @@ -256,6 +258,11 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti randomized_locations.append(location_table[f"Friendsanity: Pet {heart} <3"]) +def extend_baby_locations(randomized_locations: List[LocationData]): + baby_locations = [location for location in locations_by_tag[LocationTags.BABY]] + randomized_locations.extend(baby_locations) + + def extend_festival_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): if options.festival_locations == FestivalLocations.option_disabled: return @@ -450,11 +457,6 @@ def create_locations(location_collector: StardewLocationCollector, location_collector(location_data.name, location_data.code, location_data.region) -def filter_museum_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: - include_museum = options.museumsanity != Museumsanity.option_none - return [location for location in locations if include_museum or LocationTags.REQUIRES_MUSEUM not in location.tags] - - def filter_ginger_island(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: include_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false return [location for location in locations if include_island or LocationTags.GINGER_ISLAND not in location.tags] @@ -470,8 +472,7 @@ def filter_modded_locations(options: StardewValleyOptions, locations: List[Locat def filter_disabled_locations(options: StardewValleyOptions, locations: List[LocationData]) -> List[LocationData]: - locations_museum_filter = filter_museum_locations(options, locations) - locations_island_filter = filter_ginger_island(options, locations_museum_filter) + locations_island_filter = filter_ginger_island(options, locations) locations_qi_filter = filter_qi_order_locations(options, locations_island_filter) locations_mod_filter = filter_modded_locations(options, locations_qi_filter) return locations_mod_filter diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index c66ddb919e02..cb6e2b36dde0 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -62,6 +62,8 @@ def can_get_married(self) -> StardewRule: def has_children(self, number_children: int) -> StardewRule: if number_children <= 0: return True_() + if self.friendsanity_option == Friendsanity.option_none: + return self.can_reproduce(number_children) return self.received(possible_kids, number_children) & self.buildings.has_house(2) def can_reproduce(self, number_children: int = 1) -> StardewRule: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index df461a4ce31f..3f97a1c32b2e 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -14,7 +14,7 @@ from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices from .mods.mod_data import ModNames -from .options import StardewValleyOptions +from .options import StardewValleyOptions, Friendsanity from .options import ToolProgression, BuildingProgression, ExcludeGingerIsland, SpecialOrderLocations, Museumsanity, BackpackProgression, Shipsanity, \ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And @@ -59,7 +59,7 @@ def set_rules(world): set_fishsanity_rules(all_location_names, logic, multiworld, player) set_museumsanity_rules(all_location_names, logic, multiworld, player, world_options) - set_friendsanity_rules(all_location_names, logic, multiworld, player) + set_friendsanity_rules(all_location_names, logic, multiworld, player, world_options) set_backpack_rules(logic, multiworld, player, world_options) set_festival_rules(all_location_names, logic, multiworld, player) set_monstersanity_rules(all_location_names, logic, multiworld, player, world_options) @@ -81,10 +81,6 @@ def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): logic.has("Sweet Gem Berry")) MultiWorldRules.add_rule(multiworld.get_location("Galaxy Sword Shrine", player), logic.has("Prismatic Shard")) - MultiWorldRules.add_rule(multiworld.get_location("Have a Baby", player), - logic.relationship.can_reproduce(1)) - MultiWorldRules.add_rule(multiworld.get_location("Have Another Baby", player), - logic.relationship.can_reproduce(2)) def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -800,7 +796,14 @@ def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player logic.has("JotPK Max Buff")) -def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int): +def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if world_options.friendsanity == Friendsanity.option_none: + return + MultiWorldRules.add_rule(multiworld.get_location("Have a Baby", player), + logic.relationship.can_reproduce(1)) + MultiWorldRules.add_rule(multiworld.get_location("Have Another Baby", player), + logic.relationship.can_reproduce(2)) + friend_prefix = "Friendsanity: " friend_suffix = " <3" for friend_location in locations.locations_by_tag[LocationTags.FRIENDSANITY]: diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index adfa21eba843..70972bb1c049 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -9,6 +9,7 @@ from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods from .. import ItemData, StardewValleyWorld from ..items import Group, item_table +from ..options import Friendsanity class TestItems(SVTestCase): @@ -33,12 +34,13 @@ def test_items_table_footprint_is_between_717000_and_737000(self): def test_babies_come_in_all_shapes_and_sizes(self): baby_permutations = set() + options = {Friendsanity.internal_name: Friendsanity.option_bachelors} for attempt_number in range(50): if len(baby_permutations) >= 4: print(f"Already got all 4 baby permutations, breaking early [{attempt_number} generations]") break seed = random.randrange(sys.maxsize) - multiworld = setup_solo_multiworld(seed=seed) + multiworld = setup_solo_multiworld(options, seed=seed) baby_items = [item for item in multiworld.get_items() if "Baby" in item.name] self.assertEqual(len(baby_items), 2) baby_permutations.add(f"{baby_items[0]} - {baby_items[1]}") From 274ef9b6c5166144213551f706a67ef289089939 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 16 Nov 2023 18:39:54 -0500 Subject: [PATCH 158/482] - Updated number of minsanity locations --- worlds/stardew_valley/test/TestGeneration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index c40fa5804797..80e6a12a0273 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -344,7 +344,7 @@ def test_minimal_location_maximal_items_still_valid(self): print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items}") def test_minsanity_has_fewer_than_locations(self): - expected_locations = 123 + expected_locations = 121 minsanity_options = get_minsanity_options() multiworld = setup_solo_multiworld(minsanity_options) real_locations = get_real_locations(self, multiworld) From eb1ced772e00791d627b35666fb8768f7f0be4cd Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 16 Nov 2023 22:23:23 -0500 Subject: [PATCH 159/482] - Added randomized farm type --- worlds/stardew_valley/__init__.py | 18 +++++++++++- worlds/stardew_valley/data/items.csv | 7 +++++ worlds/stardew_valley/items.py | 1 + worlds/stardew_valley/test/TestItems.py | 38 +++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 6d890667272a..eff4fab6043d 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -121,6 +121,7 @@ def add_location(name: str, code: Optional[int], region: str): self.multiworld.regions.extend(world_regions.values()) def create_items(self): + self.precollect_farm_type() self.precollect_starting_season() items_to_exclude = [excluded_items for excluded_items in self.multiworld.precollected_items[self.player] @@ -145,7 +146,22 @@ def create_items(self): self.setup_construction_events() self.setup_victory() - def precollect_starting_season(self) -> Optional[StardewItem]: + def precollect_farm_type(self): + all_farm_types = items_by_group[Group.FARM_TYPE] + all_farm_type_names = [farm_type.name for farm_type in all_farm_types] + + chosen_farm_types = [] + for item in self.multiworld.precollected_items[self.player]: + if item.name in all_farm_type_names: + chosen_farm_types.append(item.name) + + if not chosen_farm_types: + chosen_farm_types = all_farm_type_names + + starting_season = self.create_item(self.multiworld.random.choice(chosen_farm_types)) + self.multiworld.push_precollected(starting_season) + + def precollect_starting_season(self): if self.options.season_randomization == SeasonRandomization.option_progressive: return diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 64c502b56c3f..0ee00e2856ab 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -437,6 +437,13 @@ id,name,classification,groups,mod_name 459,Chest Recipe,progression,"CRAFTSANITY", 460,Wood Sign Recipe,progression,"CRAFTSANITY", 461,Stone Sign Recipe,progression,"CRAFTSANITY", +462,Standard Farm,progression,"FARM_TYPE", +463,Riverland Farm,progression,"FARM_TYPE", +464,Forest Farm,progression,"FARM_TYPE", +465,Hill-top Farm,progression,"FARM_TYPE", +466,Wilderness Farm,progression,"FARM_TYPE", +467,Four Corners Farm,progression,"FARM_TYPE", +468,Beach Farm,progression,"FARM_TYPE", 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index b5273b2fc90e..f42297756a21 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -78,6 +78,7 @@ class Group(enum.Enum): CHEFSANITY_FRIENDSHIP = enum.auto() CHEFSANITY_SKILL = enum.auto() CRAFTSANITY = enum.auto() + FARM_TYPE = enum.auto() # Mods MAGIC_SPELL = enum.auto() MOD_WARP = enum.auto() diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index 70972bb1c049..0057accef58a 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -6,10 +6,13 @@ from typing import Set from BaseClasses import ItemClassification, MultiWorld -from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods +from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods, SVTestBase from .. import ItemData, StardewValleyWorld from ..items import Group, item_table -from ..options import Friendsanity +from ..options import Friendsanity, SeasonRandomization + +all_seasons = ["Spring", "Summer", "Fall", "Winter"] +all_farms = ["Standard Farm", "Riverland Farm", "Forest Farm", "Hill-top Farm", "Wilderness Farm", "Four Corners Farm", "Beach Farm"] class TestItems(SVTestCase): @@ -59,3 +62,34 @@ def test_no_duplicate_rings(self): multiworld = setup_solo_multiworld(allsanity_options, seed=seed) ring_items = [item.name for item in multiworld.get_items() if Group.RING in item_table[item.name].groups] self.assertEqual(len(ring_items), len(set(ring_items))) + + def test_can_start_in_any_season(self): + starting_seasons_rolled = set() + options = {SeasonRandomization.internal_name: SeasonRandomization.option_randomized} + for attempt_number in range(50): + if len(starting_seasons_rolled) >= 4: + print(f"Already got all 4 starting seasons, breaking early [{attempt_number} generations]") + break + seed = random.randrange(sys.maxsize) + multiworld = setup_solo_multiworld(options, seed=seed) + starting_season_items = [item for item in multiworld.precollected_items[1] if item.name in all_seasons] + season_items = [item for item in multiworld.get_items() if item.name in all_seasons] + self.assertEqual(len(starting_season_items), 1) + self.assertEqual(len(season_items), 3) + starting_seasons_rolled.add(f"{starting_season_items[0]}") + self.assertEqual(len(starting_seasons_rolled), 4) + + def test_can_start_on_any_farm(self): + starting_farms_rolled = set() + for attempt_number in range(50): + if len(starting_farms_rolled) >= 7: + print(f"Already got all 7 farm types, breaking early [{attempt_number} generations]") + break + seed = random.randrange(sys.maxsize) + multiworld = setup_solo_multiworld(seed=seed) + starting_farm_items = [item for item in multiworld.precollected_items[1] if item.name in all_farms] + farm_items = [item for item in multiworld.get_items() if item.name in all_farms] + self.assertEqual(len(starting_farm_items), 1) + self.assertEqual(len(farm_items), 0) + starting_farms_rolled.add(f"{starting_farm_items[0]}") + self.assertEqual(len(starting_farms_rolled), 7) From c7dff5f365270c36da8771d8fe6220b4b83bedde Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 17 Nov 2023 16:33:24 -0500 Subject: [PATCH 160/482] - Added goals Legend, Mystery of the stardrops and Allsanity # Conflicts: # worlds/stardew_valley/options.py # Conflicts: # worlds/stardew_valley/logic/logic.py --- worlds/stardew_valley/__init__.py | 12 +++ worlds/stardew_valley/data/crops.csv | 82 ++++++++--------- worlds/stardew_valley/data/crops_data.py | 6 +- worlds/stardew_valley/data/locations.csv | 6 +- worlds/stardew_valley/items.py | 13 ++- worlds/stardew_valley/locations.py | 4 + worlds/stardew_valley/logic/crop_logic.py | 16 ++-- worlds/stardew_valley/logic/logic.py | 37 ++++++-- worlds/stardew_valley/options.py | 8 +- worlds/stardew_valley/regions.py | 93 +++++++++----------- worlds/stardew_valley/rules.py | 7 +- worlds/stardew_valley/strings/goal_names.py | 3 + worlds/stardew_valley/test/TestGeneration.py | 8 +- worlds/stardew_valley/test/TestItems.py | 2 +- worlds/stardew_valley/test/mods/TestMods.py | 2 + 15 files changed, 185 insertions(+), 114 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index eff4fab6043d..1fff5d4f7b74 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -252,6 +252,18 @@ def setup_victory(self): self.create_event_location(location_table[GoalName.craft_master], self.logic.crafting.can_craft_everything, Event.victory) + elif self.options.goal == options.Goal.option_legend: + self.create_event_location(location_table[GoalName.legend], + self.logic.money.can_have_earned_total(10_000_000), + Event.victory) + elif self.options.goal == options.Goal.option_mystery_of_the_stardrops: + self.create_event_location(location_table[GoalName.mystery_of_the_stardrops], + self.logic.has_all_stardrops(), + Event.victory) + elif self.options.goal == options.Goal.option_allsanity: + self.create_event_location(location_table[GoalName.allsanity], + self.logic.has_everything(frozenset(self.all_progression_items)), + Event.victory) elif self.options.goal == options.Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], self.logic.has_everything(frozenset(self.all_progression_items)).simplify(), diff --git a/worlds/stardew_valley/data/crops.csv b/worlds/stardew_valley/data/crops.csv index c6cdf71733c2..51524f63e957 100644 --- a/worlds/stardew_valley/data/crops.csv +++ b/worlds/stardew_valley/data/crops.csv @@ -1,41 +1,41 @@ -crop,farm_growth_seasons,seed,seed_seasons,seed_regions -Amaranth,Fall,Amaranth Seeds,Fall,"Pierre's General Store,JojaMart" -Artichoke,Fall,Artichoke Seeds,Fall,"Pierre's General Store,JojaMart" -Beet,Fall,Beet Seeds,Fall,Oasis -Blue Jazz,Spring,Jazz Seeds,Spring,"Pierre's General Store,JojaMart" -Blueberry,Summer,Blueberry Seeds,Summer,"Pierre's General Store,JojaMart" -Bok Choy,Fall,Bok Choy Seeds,Fall,"Pierre's General Store,JojaMart" -Cactus Fruit,,Cactus Seeds,,Oasis -Cauliflower,Spring,Cauliflower Seeds,Spring,"Pierre's General Store,JojaMart" -Coffee Bean,"Spring,Summer",Coffee Bean,"Summer,Fall","Traveling Cart" -Corn,"Summer,Fall",Corn Seeds,"Summer,Fall","Pierre's General Store,JojaMart" -Cranberries,Fall,Cranberry Seeds,Fall,"Pierre's General Store,JojaMart" -Eggplant,Fall,Eggplant Seeds,Fall,"Pierre's General Store,JojaMart" -Fairy Rose,Fall,Fairy Seeds,Fall,"Pierre's General Store,JojaMart" -Garlic,Spring,Garlic Seeds,Spring,"Pierre's General Store,JojaMart" -Grape,Fall,Grape Starter,Fall,"Pierre's General Store,JojaMart" -Green Bean,Spring,Bean Starter,Spring,"Pierre's General Store,JojaMart" -Hops,Summer,Hops Starter,Summer,"Pierre's General Store,JojaMart" -Hot Pepper,Summer,Pepper Seeds,Summer,"Pierre's General Store,JojaMart" -Kale,Spring,Kale Seeds,Spring,"Pierre's General Store,JojaMart" -Melon,Summer,Melon Seeds,Summer,"Pierre's General Store,JojaMart" -Parsnip,Spring,Parsnip Seeds,Spring,"Pierre's General Store,JojaMart" -Pineapple,Summer,Pineapple Seeds,Summer,"Island Trader" -Poppy,Summer,Poppy Seeds,Summer,"Pierre's General Store,JojaMart" -Potato,Spring,Potato Seeds,Spring,"Pierre's General Store,JojaMart" -Qi Fruit,"Spring,Summer,Fall,Winter",Qi Bean,"Spring,Summer,Fall,Winter","Qi's Walnut Room" -Pumpkin,Fall,Pumpkin Seeds,Fall,"Pierre's General Store,JojaMart" -Radish,Summer,Radish Seeds,Summer,"Pierre's General Store,JojaMart" -Red Cabbage,Summer,Red Cabbage Seeds,Summer,"Pierre's General Store,JojaMart" -Rhubarb,Spring,Rhubarb Seeds,Spring,Oasis -Starfruit,Summer,Starfruit Seeds,Summer,Oasis -Strawberry,Spring,Strawberry Seeds,Spring,"Pierre's General Store,JojaMart" -Summer Spangle,Summer,Spangle Seeds,Summer,"Pierre's General Store,JojaMart" -Sunflower,"Summer,Fall",Sunflower Seeds,"Summer,Fall","Pierre's General Store,JojaMart" -Sweet Gem Berry,Fall,Rare Seed,"Spring,Summer",Traveling Cart -Taro Root,Summer,Taro Tuber,Summer,"Island Trader" -Tomato,Summer,Tomato Seeds,Summer,"Pierre's General Store,JojaMart" -Tulip,Spring,Tulip Bulb,Spring,"Pierre's General Store,JojaMart" -Unmilled Rice,Spring,Rice Shoot,Spring,"Pierre's General Store,JojaMart" -Wheat,"Summer,Fall",Wheat Seeds,"Summer,Fall","Pierre's General Store,JojaMart" -Yam,Fall,Yam Seeds,Fall,"Pierre's General Store,JojaMart" +crop,farm_growth_seasons,seed,seed_seasons,seed_regions,requires_island +Amaranth,Fall,Amaranth Seeds,Fall,"Pierre's General Store,JojaMart",False +Artichoke,Fall,Artichoke Seeds,Fall,"Pierre's General Store,JojaMart",False +Beet,Fall,Beet Seeds,Fall,Oasis,False +Blue Jazz,Spring,Jazz Seeds,Spring,"Pierre's General Store,JojaMart",False +Blueberry,Summer,Blueberry Seeds,Summer,"Pierre's General Store,JojaMart",False +Bok Choy,Fall,Bok Choy Seeds,Fall,"Pierre's General Store,JojaMart",False +Cactus Fruit,,Cactus Seeds,,Oasis,False +Cauliflower,Spring,Cauliflower Seeds,Spring,"Pierre's General Store,JojaMart",False +Coffee Bean,"Spring,Summer",Coffee Bean,"Summer,Fall","Traveling Cart",False +Corn,"Summer,Fall",Corn Seeds,"Summer,Fall","Pierre's General Store,JojaMart",False +Cranberries,Fall,Cranberry Seeds,Fall,"Pierre's General Store,JojaMart",False +Eggplant,Fall,Eggplant Seeds,Fall,"Pierre's General Store,JojaMart",False +Fairy Rose,Fall,Fairy Seeds,Fall,"Pierre's General Store,JojaMart",False +Garlic,Spring,Garlic Seeds,Spring,"Pierre's General Store,JojaMart",False +Grape,Fall,Grape Starter,Fall,"Pierre's General Store,JojaMart",False +Green Bean,Spring,Bean Starter,Spring,"Pierre's General Store,JojaMart",False +Hops,Summer,Hops Starter,Summer,"Pierre's General Store,JojaMart",False +Hot Pepper,Summer,Pepper Seeds,Summer,"Pierre's General Store,JojaMart",False +Kale,Spring,Kale Seeds,Spring,"Pierre's General Store,JojaMart",False +Melon,Summer,Melon Seeds,Summer,"Pierre's General Store,JojaMart",False +Parsnip,Spring,Parsnip Seeds,Spring,"Pierre's General Store,JojaMart",False +Pineapple,Summer,Pineapple Seeds,Summer,"Island Trader",True +Poppy,Summer,Poppy Seeds,Summer,"Pierre's General Store,JojaMart",False +Potato,Spring,Potato Seeds,Spring,"Pierre's General Store,JojaMart",False +Qi Fruit,"Spring,Summer,Fall,Winter",Qi Bean,"Spring,Summer,Fall,Winter","Qi's Walnut Room",True +Pumpkin,Fall,Pumpkin Seeds,Fall,"Pierre's General Store,JojaMart",False +Radish,Summer,Radish Seeds,Summer,"Pierre's General Store,JojaMart",False +Red Cabbage,Summer,Red Cabbage Seeds,Summer,"Pierre's General Store,JojaMart",False +Rhubarb,Spring,Rhubarb Seeds,Spring,Oasis,False +Starfruit,Summer,Starfruit Seeds,Summer,Oasis,False +Strawberry,Spring,Strawberry Seeds,Spring,"Pierre's General Store,JojaMart",False +Summer Spangle,Summer,Spangle Seeds,Summer,"Pierre's General Store,JojaMart",False +Sunflower,"Summer,Fall",Sunflower Seeds,"Summer,Fall","Pierre's General Store,JojaMart",False +Sweet Gem Berry,Fall,Rare Seed,"Spring,Summer",Traveling Cart,False +Taro Root,Summer,Taro Tuber,Summer,"Island Trader",True +Tomato,Summer,Tomato Seeds,Summer,"Pierre's General Store,JojaMart",False +Tulip,Spring,Tulip Bulb,Spring,"Pierre's General Store,JojaMart",False +Unmilled Rice,Spring,Rice Shoot,Spring,"Pierre's General Store,JojaMart",False +Wheat,"Summer,Fall",Wheat Seeds,"Summer,Fall","Pierre's General Store,JojaMart",False +Yam,Fall,Yam Seeds,Fall,"Pierre's General Store,JojaMart",False diff --git a/worlds/stardew_valley/data/crops_data.py b/worlds/stardew_valley/data/crops_data.py index f540246dfdf6..7144ccfbcf9b 100644 --- a/worlds/stardew_valley/data/crops_data.py +++ b/worlds/stardew_valley/data/crops_data.py @@ -9,6 +9,7 @@ class SeedItem: name: str seasons: Tuple[str] regions: Tuple[str] + requires_island: bool @dataclass(frozen=True) @@ -35,10 +36,11 @@ def load_crop_csv(): tuple(season for season in item["seed_seasons"].split(",")) if item["seed_seasons"] else tuple(), tuple(region for region in item["seed_regions"].split(",")) - if item["seed_regions"] else tuple())) + if item["seed_regions"] else tuple(), + item["requires_island"] == "True")) crops.append(CropItem(item["crop"], tuple(season for season in item["farm_growth_seasons"].split(",")) - if item["farm_growth_seasons"] else (), + if item["farm_growth_seasons"] else tuple(), seeds[-1])) return crops, seeds diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index e45de3e254f6..a6d683bd2e8e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -240,8 +240,10 @@ id,region,name,tags,mod_name 701,Secret Woods,Old Master Cannoli,MANDATORY, 702,Beach,Beach Bridge Repair,MANDATORY, 703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,"BABY", -705,Farmhouse,Have Another Baby,"BABY", +704,Farmhouse,Have a Baby,"BABY", +705,Farmhouse,Have Another Baby,"BABY", +706,Farmhouse,Spouse Stardrop,, +707,Sewer,Krobus Stardrop,"MANDATORY", 801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, 802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, 803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index f42297756a21..ccf349c6b6ef 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -336,22 +336,25 @@ def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOpt stardrops_classification = get_stardrop_classification(options) items.append(item_factory("Stardrop", stardrops_classification)) # The Mines level 100 items.append(item_factory("Stardrop", stardrops_classification)) # Old Master Cannoli + items.append(item_factory("Stardrop", stardrops_classification)) # Krobus Stardrop if options.fishsanity != Fishsanity.option_none: items.append(item_factory("Stardrop", stardrops_classification)) # Master Angler Stardrop if ModNames.deepwoods in options.mods: items.append(item_factory("Stardrop", stardrops_classification)) # Petting the Unicorn + if options.friendsanity != Friendsanity.option_none: + items.append(item_factory("Stardrop", stardrops_classification)) # Spouse Stardrop def create_museum_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): items.append(item_factory(Wallet.rusty_key)) items.append(item_factory(Wallet.dwarvish_translation_guide)) items.append(item_factory("Ancient Seeds Recipe")) + items.append(item_factory("Stardrop", get_stardrop_classification(options))) if options.museumsanity == Museumsanity.option_none: return items.extend(item_factory(item) for item in ["Magic Rock Candy"] * 10) items.extend(item_factory(item) for item in ["Ancient Seeds"] * 5) items.extend(item_factory(item) for item in ["Traveling Merchant Metal Detector"] * 4) - items.append(item_factory("Stardrop", get_stardrop_classification(options))) def create_friendsanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item], random: Random): @@ -653,8 +656,8 @@ def filter_mod_items(options: StardewValleyOptions, items: List[ItemData]) -> Li return [item for item in items if item.mod_name is None or item.mod_name in options.mods] -def remove_excluded_items(packs, options): - deprecated_filter = filter_deprecated_items(options, packs) +def remove_excluded_items(items, options): + deprecated_filter = filter_deprecated_items(options, items) ginger_island_filter = filter_ginger_island_items(options, deprecated_filter) mod_filter = filter_mod_items(options, ginger_island_filter) return mod_filter @@ -679,3 +682,7 @@ def get_stardrop_classification(world_options) -> ItemClassification: def world_is_perfection(options) -> bool: return options.goal == Goal.option_perfection + + +def world_is_stardrops(options) -> bool: + return options.goal == Goal.option_mystery_of_the_stardrops diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index e6ef95c17e1f..5cd63adcc3dc 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -142,6 +142,9 @@ def load_location_csv() -> List[LocationData]: LocationData(None, Region.shipping, Goal.full_shipment), LocationData(None, Region.kitchen, Goal.gourmet_chef), LocationData(None, Region.farm, Goal.craft_master), + LocationData(None, Region.shipping, Goal.legend), + LocationData(None, Region.farm, Goal.mystery_of_the_stardrops), + LocationData(None, Region.farm, Goal.allsanity), LocationData(None, Region.qi_walnut_room, Goal.perfection), ] @@ -230,6 +233,7 @@ def extend_friendsanity_locations(randomized_locations: List[LocationData], opti if options.friendsanity == Friendsanity.option_none: return + randomized_locations.append(location_table[f"Spouse Stardrop"]) extend_baby_locations(randomized_locations) exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true exclude_non_bachelors = options.friendsanity == Friendsanity.option_bachelors diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index c4434495a81e..c9ab8802a233 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -10,8 +10,8 @@ from .tool_logic import ToolLogic from .traveling_merchant_logic import TravelingMerchantLogic from ..data import CropItem, SeedItem -from ..options import Cropsanity -from ..stardew_rule import StardewRule, True_ +from ..options import Cropsanity, ExcludeGingerIsland +from ..stardew_rule import StardewRule, True_, False_ from ..strings.forageable_names import Forageable from ..strings.metal_names import Fossil from ..strings.region_names import Region @@ -22,6 +22,7 @@ class CropLogic(CachedLogic): player: int cropsanity_option: Cropsanity + exclude_ginger_island_option: ExcludeGingerIsland received: ReceivedLogic has: HasLogic region: RegionLogic @@ -30,10 +31,11 @@ class CropLogic(CachedLogic): money: MoneyLogic tool: ToolLogic - def __init__(self, player: int, cached_rules: CachedRules, cropsanity_option: Cropsanity, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + def __init__(self, player: int, cached_rules: CachedRules, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, region: RegionLogic, traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): super().__init__(player, cached_rules) self.cropsanity_option = cropsanity_option + self.exclude_ginger_island_option = exclude_ginger_island_option self.received = received self.has = has self.region = region @@ -48,7 +50,7 @@ def can_grow(self, crop: CropItem) -> StardewRule: seed_rule = self.has(crop.seed.name) farm_rule = self.region.can_reach(Region.farm) & season_rule tool_rule = self.tool.has_tool(Tool.hoe) & self.tool.has_tool(Tool.watering_can) - region_rule = farm_rule | self.region.can_reach(Region.greenhouse) | self.region.can_reach(Region.island_west) + region_rule = farm_rule | self.region.can_reach(Region.greenhouse) | self.has_island_farm() return seed_rule & region_rule & tool_rule def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> StardewRule: @@ -60,10 +62,14 @@ def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> Stardew return season_rule & farm_rule def has_island_farm(self) -> StardewRule: - return self.region.can_reach(Region.island_south) + if self.exclude_ginger_island_option == ExcludeGingerIsland.option_false: + return self.region.can_reach(Region.island_west) + return False_() @cache_self1 def can_buy_seed(self, seed: SeedItem) -> StardewRule: + if seed.requires_island and self.exclude_ginger_island_option == ExcludeGingerIsland.option_true: + return False_() if self.cropsanity_option == Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() else: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 6e941f81e52d..401a1cc3f14d 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -43,7 +43,8 @@ from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..mods.logic.mod_logic import ModLogic -from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions +from ..mods.mod_data import ModNames +from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions, Fishsanity, Museumsanity, Friendsanity from ..regions import vanilla_regions from ..stardew_rule import False_, Or, True_, Count, And, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals @@ -132,7 +133,7 @@ def __post_init__(self): self.monster = MonsterLogic(self.player, self.cached_rules, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, self.cached_rules, tool_option, self.received, self.has, self.region, self.season, self.money) self.pet = PetLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) - self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, self.received, self.has, self.region, self.traveling_merchant, + self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, exclude_ginger_island, self.received, self.has, self.region, self.traveling_merchant, self.season, self.money, self.tool) self.skill = SkillLogic(self.player, self.cached_rules, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) @@ -730,10 +731,36 @@ def has_walnut(self, number: int) -> StardewRule: return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) + def has_all_stardrops(self) -> StardewRule: + other_rules = [] + number_of_stardrops_to_receive = 0 + number_of_stardrops_to_receive += 1 # The Mines level 100 + number_of_stardrops_to_receive += 1 # Old Master Cannoli + number_of_stardrops_to_receive += 1 # Museum Stardrop + number_of_stardrops_to_receive += 1 # Krobus Stardrop + + if self.options.fishsanity == Fishsanity.option_none: # Master Angler Stardrop + other_rules.append(self.can_catch_every_fish()) + else: + number_of_stardrops_to_receive += 1 + + if self.options.festival_locations == FestivalLocations.option_disabled: # Fair Stardrop + other_rules.append(self.season.has(Season.fall)) + else: + number_of_stardrops_to_receive += 1 + + if self.options.friendsanity == Friendsanity.option_none: # Spouse Stardrop + other_rules.append(self.relationship.has_hearts(Generic.bachelor, 13)) + else: + number_of_stardrops_to_receive += 1 + + if ModNames.deepwoods in self.options.mods: # Petting the Unicorn + number_of_stardrops_to_receive += 1 + + return self.received("Stardrop", number_of_stardrops_to_receive) & And(*other_rules) + def has_everything(self, all_progression_items: frozenset[str]) -> StardewRule: - all_regions = tuple(region.name for region in vanilla_regions) - rules = self.received(all_progression_items, len(all_progression_items)) & \ - self.region.can_reach_all(all_regions) + rules = self.received(all_progression_items, len(all_progression_items)) return rules def has_prismatic_jelly_reward_access(self) -> StardewRule: diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 0abec73920f8..d62f8b0bdb6c 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -19,6 +19,9 @@ class Goal(Choice): Full Shipment: Ship every item in the collection tab. Pairs well with Shipsanity Gourmet Chef: Cook every recipe. Pairs well with Chefsanity and Cooksanity Craft Master: Craft every item. Pairs well with Craftsanity + Legend: Earn 10 000 000g + Mystery of the Stardrops: Find every stardrop + Allsanity: Complete every check in your slot Perfection: Attain Perfection, based on the vanilla definition. """ internal_name = "goal" @@ -36,13 +39,14 @@ class Goal(Choice): option_full_shipment = 9 option_gourmet_chef = 10 option_craft_master = 11 + option_legend = 12 + option_mystery_of_the_stardrops = 13 # option_junimo_kart = # option_prairie_king = # option_fector_challenge = - # option_mystery_of_the_stardrops = - # option_legend = # option_beloved_farmer = # option_master_of_the_five_ways = + option_allsanity = 24 option_perfection = 25 @classmethod diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 3cc07cb837ed..20d8a5b0e88a 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -2,7 +2,7 @@ from typing import Iterable, Dict, Protocol, List, Tuple, Set from BaseClasses import Region, Entrance -from .options import EntranceRandomization, ExcludeGingerIsland, Museumsanity +from .options import EntranceRandomization, ExcludeGingerIsland, Museumsanity, StardewValleyOptions from .strings.entrance_names import Entrance from .strings.region_names import Region from .region_classes import RegionData, ConnectionData, RandomizationFlag, ModificationFlag @@ -382,9 +382,9 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.dig_to_mines_floor_110, Region.mines_floor_110), ConnectionData(Entrance.dig_to_mines_floor_115, Region.mines_floor_115), ConnectionData(Entrance.dig_to_mines_floor_120, Region.mines_floor_120), - ConnectionData(Entrance.dig_to_dangerous_mines_20, Region.dangerous_mines_20), - ConnectionData(Entrance.dig_to_dangerous_mines_60, Region.dangerous_mines_60), - ConnectionData(Entrance.dig_to_dangerous_mines_100, Region.dangerous_mines_100), + ConnectionData(Entrance.dig_to_dangerous_mines_20, Region.dangerous_mines_20, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.dig_to_dangerous_mines_60, Region.dangerous_mines_60, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.dig_to_dangerous_mines_100, Region.dangerous_mines_100, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.enter_skull_cavern_entrance, Region.skull_cavern_entrance, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.enter_oasis, Region.oasis, @@ -399,7 +399,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.mine_to_skull_cavern_floor_150, Region.skull_cavern_150), ConnectionData(Entrance.mine_to_skull_cavern_floor_175, Region.skull_cavern_175), ConnectionData(Entrance.mine_to_skull_cavern_floor_200, Region.skull_cavern_200), - ConnectionData(Entrance.enter_dangerous_skull_cavern, Region.dangerous_skull_cavern), + ConnectionData(Entrance.enter_dangerous_skull_cavern, Region.dangerous_skull_cavern, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.enter_witch_warp_cave, Region.witch_warp_cave, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.enter_witch_swamp, Region.witch_swamp, flag=RandomizationFlag.BUILDINGS), ConnectionData(Entrance.enter_witch_hut, Region.witch_hut, flag=RandomizationFlag.BUILDINGS), @@ -423,8 +423,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_west_to_shipwreck, Region.shipwreck, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.island_west_to_qi_walnut_room, Region.qi_walnut_room, - flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.island_west_to_qi_walnut_room, Region.qi_walnut_room, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_east_to_leo_hut, Region.leo_hut, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_east_to_island_shrine, Region.island_shrine, @@ -440,21 +439,21 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.volcano_to_secret_beach, Region.volcano_secret_beach, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.talk_to_island_trader, Region.island_trader, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.climb_to_volcano_5, Region.volcano_floor_5), - ConnectionData(Entrance.talk_to_volcano_dwarf, Region.volcano_dwarf_shop), - ConnectionData(Entrance.climb_to_volcano_10, Region.volcano_floor_10), - ConnectionData(Entrance.parrot_express_jungle_to_docks, Region.island_south), - ConnectionData(Entrance.parrot_express_dig_site_to_docks, Region.island_south), - ConnectionData(Entrance.parrot_express_volcano_to_docks, Region.island_south), - ConnectionData(Entrance.parrot_express_volcano_to_jungle, Region.island_west), - ConnectionData(Entrance.parrot_express_docks_to_jungle, Region.island_west), - ConnectionData(Entrance.parrot_express_dig_site_to_jungle, Region.island_west), - ConnectionData(Entrance.parrot_express_docks_to_dig_site, Region.dig_site), - ConnectionData(Entrance.parrot_express_volcano_to_dig_site, Region.dig_site), - ConnectionData(Entrance.parrot_express_jungle_to_dig_site, Region.dig_site), - ConnectionData(Entrance.parrot_express_dig_site_to_volcano, Region.island_north), - ConnectionData(Entrance.parrot_express_docks_to_volcano, Region.island_north), - ConnectionData(Entrance.parrot_express_jungle_to_volcano, Region.island_north), + ConnectionData(Entrance.climb_to_volcano_5, Region.volcano_floor_5, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.talk_to_volcano_dwarf, Region.volcano_dwarf_shop, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.climb_to_volcano_10, Region.volcano_floor_10, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_jungle_to_docks, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_dig_site_to_docks, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_volcano_to_docks, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_volcano_to_jungle, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_docks_to_jungle, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_dig_site_to_jungle, Region.island_west, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_docks_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_volcano_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_jungle_to_dig_site, Region.dig_site, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_dig_site_to_volcano, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_docks_to_volcano, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(Entrance.parrot_express_jungle_to_volcano, Region.island_north, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.attend_egg_festival, Region.egg_festival), ConnectionData(Entrance.attend_flower_dance, Region.flower_dance), ConnectionData(Entrance.attend_luau, Region.luau), @@ -515,14 +514,11 @@ def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionD return updated_region -def create_regions(region_factory: RegionFactory, random: Random, world_options) -> Tuple[ +def create_regions(region_factory: RegionFactory, random: Random, world_options: StardewValleyOptions) -> Tuple[ Dict[str, Region], Dict[str, str]]: final_regions = create_final_regions(world_options) - regions: Dict[str: Region] = {region.name: region_factory(region.name, region.exits) for region in - final_regions} - entrances: Dict[str: Entrance] = {entrance.name: entrance - for region in regions.values() - for entrance in region.exits} + regions: Dict[str: Region] = {region.name: region_factory(region.name, region.exits) for region in final_regions} + entrances: Dict[str: Entrance] = {entrance.name: entrance for region in regions.values() for entrance in region.exits} regions_by_name: Dict[str, RegionData] = {region.name: region for region in final_regions} connections, randomized_data = randomize_connections(random, world_options, regions_by_name) @@ -530,13 +526,12 @@ def create_regions(region_factory: RegionFactory, random: Random, world_options) for connection in connections: if connection.name in entrances: entrances[connection.name].connect(regions[connection.destination]) - return regions, randomized_data -def randomize_connections(random: Random, world_options, regions_by_name) -> Tuple[ - List[ConnectionData], Dict[str, str]]: - connections_to_randomize = [] +def randomize_connections(random: Random, world_options: StardewValleyOptions, regions_by_name: Dict[str, RegionData])\ + -> Tuple[List[ConnectionData], Dict[str, str]]: + connections_to_randomize: List[ConnectionData] = [] final_connections = create_final_connections(world_options) connections_by_name: Dict[str, ConnectionData] = {connection.name: connection for connection in final_connections} if world_options.entrance_randomization == EntranceRandomization.option_pelican_town: @@ -551,7 +546,7 @@ def randomize_connections(random: Random, world_options, regions_by_name) -> Tup elif world_options.entrance_randomization == EntranceRandomization.option_chaos: connections_to_randomize = [connection for connection in final_connections if RandomizationFlag.BUILDINGS in connection.flag] - connections_to_randomize = exclude_island_if_necessary(connections_to_randomize, world_options) + connections_to_randomize = remove_excluded_entrances(connections_to_randomize, world_options) # On Chaos, we just add the connections to randomize, unshuffled, and the client does it every day randomized_data_for_mod = {} @@ -561,7 +556,6 @@ def randomize_connections(random: Random, world_options, regions_by_name) -> Tup return final_connections, randomized_data_for_mod connections_to_randomize = remove_excluded_entrances(connections_to_randomize, world_options) - random.shuffle(connections_to_randomize) destination_pool = list(connections_to_randomize) random.shuffle(destination_pool) @@ -576,25 +570,14 @@ def randomize_connections(random: Random, world_options, regions_by_name) -> Tup return randomized_connections_for_generation, randomized_data_for_mod -def remove_excluded_entrances(connections_to_randomize, world_options): +def remove_excluded_entrances(connections_to_randomize: List[ConnectionData], world_options: StardewValleyOptions) -> List[ConnectionData]: exclude_island = world_options.exclude_ginger_island == ExcludeGingerIsland.option_true - exclude_sewers = world_options.museumsanity == Museumsanity.option_none if exclude_island: connections_to_randomize = [connection for connection in connections_to_randomize if RandomizationFlag.GINGER_ISLAND not in connection.flag] - if exclude_sewers: - connections_to_randomize = [connection for connection in connections_to_randomize if Region.sewer not in connection.name or Region.sewer not in connection.reverse] return connections_to_randomize -def exclude_island_if_necessary(connections_to_randomize: List[ConnectionData], world_options) -> List[ConnectionData]: - exclude_island = world_options.exclude_ginger_island == ExcludeGingerIsland.option_true - if exclude_island: - connections_to_randomize = [connection for connection in connections_to_randomize if - RandomizationFlag.GINGER_ISLAND not in connection.flag] - return connections_to_randomize - - def randomize_chosen_connections(connections_to_randomize: List[ConnectionData], destination_pool: List[ConnectionData]) -> Dict[ConnectionData, ConnectionData]: randomized_connections = {} @@ -628,15 +611,15 @@ def add_to_mod_data(connection: ConnectionData, destination: ConnectionData, ran randomized_data_for_mod[destination.reverse] = connection.reverse -def add_non_randomized_connections(connections, connections_to_randomize: List[ConnectionData], +def add_non_randomized_connections(all_connections: List[ConnectionData], connections_to_randomize: List[ConnectionData], randomized_connections: Dict[ConnectionData, ConnectionData]): - for connection in connections: + for connection in all_connections: if connection in connections_to_randomize: continue randomized_connections[connection] = connection -def swap_connections_until_valid(regions_by_name, connections_by_name, randomized_connections: Dict[ConnectionData, ConnectionData], +def swap_connections_until_valid(regions_by_name, connections_by_name: Dict[str, ConnectionData], randomized_connections: Dict[ConnectionData, ConnectionData], connections_to_randomize: List[ConnectionData], random: Random): while True: reachable_regions, unreachable_regions = find_reachable_regions(regions_by_name, connections_by_name, randomized_connections) @@ -646,14 +629,26 @@ def swap_connections_until_valid(regions_by_name, connections_by_name, randomize unreachable_regions, connections_to_randomize, random) +def region_should_be_reachable(region_name: str, connections_in_slot: Iterable[ConnectionData]) -> bool: + if region_name == Region.menu: + return True + for connection in connections_in_slot: + if region_name == connection.destination: + return True + return False + + def find_reachable_regions(regions_by_name, connections_by_name, randomized_connections: Dict[ConnectionData, ConnectionData]): reachable_regions = {Region.menu} unreachable_regions = {region for region in regions_by_name.keys()} + # unreachable_regions = {region for region in regions_by_name.keys() if region_should_be_reachable(region, connections_by_name.values())} unreachable_regions.remove(Region.menu) exits_to_explore = list(regions_by_name[Region.menu].exits) while exits_to_explore: exit_name = exits_to_explore.pop() + # if exit_name not in connections_by_name: + # continue exit_connection = connections_by_name[exit_name] replaced_connection = randomized_connections[exit_connection] target_region_name = replaced_connection.destination diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 3f97a1c32b2e..565ea5ab95be 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -3,7 +3,7 @@ from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules -from worlds.stardew_valley.strings.craftable_names import Bomb +from .strings.craftable_names import Bomb from . import locations from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name @@ -24,6 +24,7 @@ from .strings.calendar_names import Weekday from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance, \ SVEEntrance +from .strings.generic_names import Generic from .strings.material_names import Material from .strings.metal_names import MetalBar from .strings.quest_names import Quest, ModQuest @@ -81,6 +82,8 @@ def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): logic.has("Sweet Gem Berry")) MultiWorldRules.add_rule(multiworld.get_location("Galaxy Sword Shrine", player), logic.has("Prismatic Shard")) + MultiWorldRules.add_rule(multiworld.get_location("Krobus Stardrop", player), + logic.money.can_spend(20000)) def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -799,6 +802,8 @@ def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if world_options.friendsanity == Friendsanity.option_none: return + MultiWorldRules.add_rule(multiworld.get_location("Spouse Stardrop", player), + logic.relationship.has_hearts(Generic.bachelor, 13)) MultiWorldRules.add_rule(multiworld.get_location("Have a Baby", player), logic.relationship.can_reproduce(1)) MultiWorldRules.add_rule(multiworld.get_location("Have Another Baby", player), diff --git a/worlds/stardew_valley/strings/goal_names.py b/worlds/stardew_valley/strings/goal_names.py index 84b942714eda..601b00510428 100644 --- a/worlds/stardew_valley/strings/goal_names.py +++ b/worlds/stardew_valley/strings/goal_names.py @@ -11,4 +11,7 @@ class Goal: full_shipment = "Full Shipment" gourmet_chef = "Gourmet Chef" craft_master = "Craft Master" + legend = "Legend" + mystery_of_the_stardrops = "Mystery of the Stardrops" + allsanity = "Allsanity" perfection = "Perfection" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 80e6a12a0273..9190640aa35e 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -40,6 +40,7 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) + items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] for progression_item in progression_items: @@ -90,6 +91,7 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) + items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] for progression_item in progression_items: with self.subTest(f"{progression_item.name}"): @@ -344,7 +346,7 @@ def test_minimal_location_maximal_items_still_valid(self): print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items}") def test_minsanity_has_fewer_than_locations(self): - expected_locations = 121 + expected_locations = 122 minsanity_options = get_minsanity_options() multiworld = setup_solo_multiworld(minsanity_options) real_locations = get_real_locations(self, multiworld) @@ -358,7 +360,7 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1950 + expected_locations = 1952 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -372,7 +374,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2423 + expected_locations = 2425 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index 0057accef58a..540418df2cbc 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -54,7 +54,7 @@ def test_correct_number_of_stardrops(self): allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options, seed=seed) stardrop_items = [item for item in multiworld.get_items() if "Stardrop" in item.name] - self.assertEqual(len(stardrop_items), 5) + self.assertEqual(len(stardrop_items), 7) def test_no_duplicate_rings(self): seed = random.randrange(sys.maxsize) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 93a97b41ab5b..de4f5a5c76a4 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -66,6 +66,7 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) + items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] @@ -92,6 +93,7 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) + items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] From 4aeb41df3fba643b755d92b08ffc66475710a9e8 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 17 Nov 2023 17:18:49 -0500 Subject: [PATCH 161/482] - Fixed deprecated assert method --- worlds/stardew_valley/test/TestMultiplePlayers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/TestMultiplePlayers.py b/worlds/stardew_valley/test/TestMultiplePlayers.py index 70552eceb010..39be7d6f7ab2 100644 --- a/worlds/stardew_valley/test/TestMultiplePlayers.py +++ b/worlds/stardew_valley/test/TestMultiplePlayers.py @@ -65,12 +65,12 @@ def test_money_rule_caching(self): player_2_rarecrow_4 = get_access_rule(multiworld, 2, FestivalCheck.rarecrow_4) with self.subTest("Rules are not cached between players"): - self.assertNotEquals(id(player_1_rarecrow_2), id(player_2_rarecrow_2)) - self.assertNotEquals(id(player_1_rarecrow_4), id(player_2_rarecrow_4)) + self.assertNotEqual(id(player_1_rarecrow_2), id(player_2_rarecrow_2)) + self.assertNotEqual(id(player_1_rarecrow_4), id(player_2_rarecrow_4)) with self.subTest("Rules are cached for the same player"): - self.assertEquals(id(player_1_rarecrow_2), id(player_1_rarecrow_4)) - self.assertEquals(id(player_2_rarecrow_2), id(player_2_rarecrow_4)) + self.assertEqual(id(player_1_rarecrow_2), id(player_1_rarecrow_4)) + self.assertEqual(id(player_2_rarecrow_2), id(player_2_rarecrow_4)) def check_location_rule(self, multiworld, player: int, location_name: str, should_exist: bool, should_be_true: bool = False): has = "has" if should_exist else "doesn't have" From 6b91f833044a53d2e0dc376daa255646f70d6b11 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 17 Nov 2023 23:40:23 -0500 Subject: [PATCH 162/482] - Remove extra precollected seasons --- worlds/stardew_valley/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 1fff5d4f7b74..f9b2b0e22882 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -154,6 +154,7 @@ def precollect_farm_type(self): for item in self.multiworld.precollected_items[self.player]: if item.name in all_farm_type_names: chosen_farm_types.append(item.name) + self.multiworld.precollected_items[self.player].remove(item) if not chosen_farm_types: chosen_farm_types = all_farm_type_names From da685f12b067eed6da1ccf1b39294838713db975 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 17:25:25 -0500 Subject: [PATCH 163/482] - Fixed some recipes that were not marked as special orders or festivals properly --- worlds/stardew_valley/data/craftable_data.py | 14 +++++++------- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/items.py | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 386625ae019d..d3b20f483399 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -187,7 +187,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) life_elixir = skill_recipe(Edible.life_elixir, Skill.combat, 2, {Forageable.red_mushroom: 1, Forageable.purple_mushroom: 1, Forageable.morel: 1, Forageable.chanterelle: 1}) oil_of_garlic = skill_recipe(Edible.oil_of_garlic, Skill.combat, 6, {Vegetable.garlic: 10, Ingredient.oil: 1}) -monster_musk = ap_recipe(Consumable.monster_musk, {Loot.bat_wing: 30, Loot.slime: 30}) +monster_musk = special_order_recipe(Consumable.monster_musk, SpecialOrder.prismatic_jelly, {Loot.bat_wing: 30, Loot.slime: 30}) fairy_dust = ap_recipe(Consumable.fairy_dust, {Mineral.diamond: 1, Flower.fairy_rose: 1}) warp_totem_beach = skill_recipe(Consumable.warp_totem_beach, Skill.foraging, 6, {Material.hardwood: 1, WaterItem.coral: 2, Material.fiber: 10}) warp_totem_mountains = skill_recipe(Consumable.warp_totem_mountains, Skill.foraging, 7, {Material.hardwood: 1, MetalBar.iron: 1, Material.stone: 25}) @@ -210,11 +210,11 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) iron_lamp_post = shop_recipe(Lighting.iron_lamp_post, Region.carpenter, 1000, {MetalBar.iron: 1, ArtisanGood.battery_pack: 1}) jack_o_lantern = festival_shop_recipe(Lighting.jack_o_lantern, Region.spirit_eve, 2000, {Vegetable.pumpkin: 1, Lighting.torch: 1}) -bone_mill = ap_recipe(Machine.bone_mill, {Fossil.bone_fragment: 10, Material.clay: 3, Material.stone: 20}) +bone_mill = special_order_recipe(Machine.bone_mill, SpecialOrder.fragments_of_the_past, {Fossil.bone_fragment: 10, Material.clay: 3, Material.stone: 20}) charcoal_kiln = skill_recipe(Machine.charcoal_kiln, Skill.foraging, 4, {Material.wood: 20, MetalBar.copper: 2}) crystalarium = skill_recipe(Machine.crystalarium, Skill.mining, 9, {Material.stone: 99, MetalBar.gold: 5, MetalBar.iridium: 2, ArtisanGood.battery_pack: 1}) furnace = starter_recipe(Machine.furnace, {Ore.copper: 20, Material.stone: 25}) -geode_crusher = ap_recipe(Machine.geode_crusher, {MetalBar.gold: 2, Material.stone: 50, Mineral.diamond: 1}) +geode_crusher = special_order_recipe(Machine.geode_crusher, SpecialOrder.cave_patrol, {MetalBar.gold: 2, Material.stone: 50, Mineral.diamond: 1}) heavy_tapper = ap_recipe(Machine.heavy_tapper, {Material.hardwood: 30, MetalBar.radioactive: 1}) lightning_rod = skill_recipe(Machine.lightning_rod, Skill.foraging, 6, {MetalBar.iron: 1, MetalBar.quartz: 1, Loot.bat_wing: 5}) ostrich_incubator = ap_recipe(Machine.ostrich_incubator, {Fossil.bone_fragment: 50, Material.hardwood: 50, Currency.cinder_shard: 20}) @@ -222,7 +222,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) seed_maker = skill_recipe(Machine.seed_maker, Skill.farming, 9, {Material.wood: 25, Material.coal: 10, MetalBar.gold: 1}) slime_egg_press = skill_recipe(Machine.slime_egg_press, Skill.combat, 6, {Material.coal: 25, Mineral.fire_quartz: 1, ArtisanGood.battery_pack: 1}) slime_incubator = skill_recipe(Machine.slime_incubator, Skill.combat, 8, {MetalBar.iridium: 2, Loot.slime: 100}) -solar_panel = ap_recipe(Machine.solar_panel, {MetalBar.quartz: 10, MetalBar.iron: 5, MetalBar.gold: 5}) +solar_panel = special_order_recipe(Machine.solar_panel, SpecialOrder.island_ingredients, {MetalBar.quartz: 10, MetalBar.iron: 5, MetalBar.gold: 5}) tapper = skill_recipe(Machine.tapper, Skill.foraging, 3, {Material.wood: 40, MetalBar.copper: 2}) worm_bin = skill_recipe(Machine.worm_bin, Skill.fishing, 8, {Material.hardwood: 25, MetalBar.gold: 1, MetalBar.iron: 1, Material.fiber: 50}) @@ -232,7 +232,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) drum_block = cutscene_recipe(Furniture.drum_block, Region.carpenter, NPC.robin, 6, {Material.stone: 10, Ore.copper: 2, Material.fiber: 20}) chest = starter_recipe(Storage.chest, {Material.wood: 50}) -stone_chest = ap_recipe(Storage.stone_chest, {Material.stone: 50}) +stone_chest = special_order_recipe(Storage.stone_chest, SpecialOrder.robins_resource_rush, {Material.stone: 50}) wood_sign = starter_recipe(Sign.wood, {Material.wood: 25}) stone_sign = starter_recipe(Sign.stone, {Material.stone: 25}) @@ -246,8 +246,8 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) transmute_fe = skill_recipe(Craftable.transmute_fe, Skill.mining, 4, {MetalBar.copper: 3}) transmute_au = skill_recipe(Craftable.transmute_au, Skill.mining, 7, {MetalBar.iron: 2}) mini_jukebox = cutscene_recipe(Craftable.mini_jukebox, Region.saloon, NPC.gus, 5, {MetalBar.iron: 2, ArtisanGood.battery_pack: 1}) -mini_obelisk = ap_recipe(Craftable.mini_obelisk, {Material.hardwood: 30, Loot.solar_essence: 20, MetalBar.gold: 3}) -farm_computer = ap_recipe(Craftable.farm_computer, {Artifact.dwarf_gadget: 1, ArtisanGood.battery_pack: 1, MetalBar.quartz: 10}) +mini_obelisk = special_order_recipe(Craftable.mini_obelisk, SpecialOrder.a_curious_substance, {Material.hardwood: 30, Loot.solar_essence: 20, MetalBar.gold: 3}) +farm_computer = special_order_recipe(Craftable.farm_computer, SpecialOrder.aquatic_overpopulation, {Artifact.dwarf_gadget: 1, ArtisanGood.battery_pack: 1, MetalBar.quartz: 10}) hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1}) cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 9, {Material.wood: 15, Material.fiber: 10, Material.coal: 3}) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 0ee00e2856ab..053d56ce28e8 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -268,7 +268,7 @@ id,name,classification,groups,mod_name 283,Ostrich Incubator Recipe,progression,"GINGER_ISLAND", 284,Cute Baby,progression,"BABY", 285,Ugly Baby,progression,"BABY", -286,Deluxe Scarecrow Recipe,progression,"FESTIVAL,RARECROW", +286,Deluxe Scarecrow Recipe,progression,"RARECROW", 287,Treehouse,progression,"GINGER_ISLAND", 288,Coffee Bean,progression,CROPSANITY, 289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index ccf349c6b6ef..5a80b1e28d56 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -459,6 +459,7 @@ def create_seeds(item_factory: StardewItemFactory, options: StardewValleyOptions def create_festival_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + items.append(item_factory("Deluxe Scarecrow Recipe")) if options.festival_locations == FestivalLocations.option_disabled: return From d0b9818000a5459d0c9ed13b5fae1f6a08792626 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 21:34:51 -0500 Subject: [PATCH 164/482] - Got rid of the concept of "Month End" for money # Conflicts: # worlds/stardew_valley/__init__.py --- worlds/stardew_valley/__init__.py | 63 +++--------------- worlds/stardew_valley/items.py | 1 - worlds/stardew_valley/logic/cooking_logic.py | 3 +- worlds/stardew_valley/logic/logic.py | 4 -- worlds/stardew_valley/logic/money_logic.py | 17 +++-- worlds/stardew_valley/logic/time_logic.py | 9 ++- worlds/stardew_valley/stardew_rule.py | 32 ++++++++++ .../strings/ap_names/event_names.py | 1 - worlds/stardew_valley/test/TestRules.py | 64 ++++++++++--------- worlds/stardew_valley/test/__init__.py | 5 ++ 10 files changed, 96 insertions(+), 103 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index f9b2b0e22882..a5171fdfa270 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -1,10 +1,9 @@ import logging -from typing import Dict, Any, Iterable, Optional, Union, Set, List +from typing import Dict, Any, Iterable, Optional, Union, List -from BaseClasses import Region, Entrance, Location, Item, Tutorial, CollectionState, ItemClassification, MultiWorld, Group as ItemLinkGroup +from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld from Options import PerGameCommonOptions from worlds.AutoWorld import World, WebWorld -from worlds.generic.Rules import set_rule from . import rules from .bundles import get_all_bundles, Bundle from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs @@ -18,7 +17,7 @@ from .presets import sv_options_presets from .regions import create_regions from .rules import set_rules -from .stardew_rule import True_, StardewRule +from .stardew_rule import True_, StardewRule, CountPercent from .strings.ap_names.event_names import Event from .strings.goal_names import Goal as GoalName @@ -75,11 +74,10 @@ class StardewValleyWorld(World): web = StardewWebWorld() modified_bundles: Dict[str, Bundle] randomized_entrances: Dict[str, str] - all_progression_items: Set[str] + total_progression_items: int def __init__(self, world: MultiWorld, player: int): super().__init__(world, player) - self.all_progression_items = set() self.filler_item_pool_names = [] def generate_early(self): @@ -121,6 +119,7 @@ def add_location(name: str, code: Optional[int], region: str): self.multiworld.regions.extend(world_regions.values()) def create_items(self): + self.total_progression_items = 0 self.precollect_farm_type() self.precollect_starting_season() items_to_exclude = [excluded_items @@ -142,7 +141,6 @@ def create_items(self): self.multiworld.itempool += created_items self.setup_early_items() - self.setup_month_events() self.setup_construction_events() self.setup_victory() @@ -184,22 +182,12 @@ def precollect_starting_season(self): self.multiworld.push_precollected(starting_season) def setup_early_items(self): - if (self.options.building_progression == - BuildingProgression.option_progressive_early_shipping_bin): + if self.options.building_progression & BuildingProgression.option_progressive_early_shipping_bin: self.multiworld.early_items[self.player]["Shipping Bin"] = 1 if self.options.backpack_progression == BackpackProgression.option_early_progressive: self.multiworld.early_items[self.player]["Progressive Backpack"] = 1 - def setup_month_events(self): - for i in range(0, MAX_MONTHS): - month_end = LocationData(None, "Stardew Valley", f"{Event.month_end} {i + 1}") - if i == 0: - self.create_event_location(month_end, True_(), Event.month_end) - continue - - self.create_event_location(month_end, self.logic.received(Event.month_end, i), Event.month_end) - def setup_construction_events(self): can_construct_buildings = LocationData(None, "Carpenter Shop", Event.can_construct_buildings) self.create_event_location(can_construct_buildings, True_(), Event.can_construct_buildings) @@ -263,11 +251,11 @@ def setup_victory(self): Event.victory) elif self.options.goal == options.Goal.option_allsanity: self.create_event_location(location_table[GoalName.allsanity], - self.logic.has_everything(frozenset(self.all_progression_items)), + CountPercent(self.player, 100), Event.victory) elif self.options.goal == options.Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], - self.logic.has_everything(frozenset(self.all_progression_items)).simplify(), + CountPercent(self.player, 100), Event.victory) self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player) @@ -280,7 +268,7 @@ def create_item(self, item: Union[str, ItemData], override_classification: ItemC override_classification = item.classification if override_classification == ItemClassification.progression: - self.all_progression_items.add(item.name) + self.total_progression_items += 1 return StardewItem(item.name, override_classification, item.code, self.player) def create_event_location(self, location_data: LocationData, rule: StardewRule = None, item: Optional[str] = None): @@ -297,39 +285,6 @@ def create_event_location(self, location_data: LocationData, rule: StardewRule = def set_rules(self): set_rules(self) - self.force_first_month_once_all_early_items_are_found() - - def force_first_month_once_all_early_items_are_found(self): - """ - The Fill algorithm sweeps all event when calculating the early location. This causes an issue where - location only locked behind event are considered early, which they are not really... - - This patches the issue, by adding a dependency to the first month end on all early items, so all the locations - that depends on it will not be considered early. This requires at least one early item to be progression, or - it just won't work... - - We do this for all early items, not just ours, to avoid them getting stuck behind late stardew months and not feeling early at all - """ - - early_items = [] - for player, item_count in self.multiworld.early_items.items(): - for item, count in item_count.items(): - if self.multiworld.worlds[player].create_item(item).advancement: - early_items.append((player, item, count)) - - for item, count in self.multiworld.local_early_items[self.player].items(): - if self.create_item(item).advancement: - early_items.append((self.player, item, count)) - - def first_month_require_all_early_items(state: CollectionState) -> bool: - for player, item, count in early_items: - if not state.has(item, player, count): - return False - - return True - - first_month_end = self.multiworld.get_location("Month End 1", self.player) - set_rule(first_month_end, first_month_require_all_early_items) def generate_basic(self): pass diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 5a80b1e28d56..a333df998f44 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -129,7 +129,6 @@ def load_item_csv(): events = [ ItemData(None, Event.victory, ItemClassification.progression), - ItemData(None, Event.month_end, ItemClassification.progression), ItemData(None, Event.can_construct_buildings, ItemClassification.progression), ] diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 181078faf058..e9f022648807 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -111,8 +111,7 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, FriendshipSource): return self.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, QueenOfSauceSource): - year_rule = self.time.has_year_two if source.year == 2 else self.time.has_year_three - return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) & year_rule + return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) return False_() @cache_self1 diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 401a1cc3f14d..1fab14015292 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -759,10 +759,6 @@ def has_all_stardrops(self) -> StardewRule: return self.received("Stardrop", number_of_stardrops_to_receive) & And(*other_rules) - def has_everything(self, all_progression_items: frozenset[str]) -> StardewRule: - rules = self.received(all_progression_items, len(all_progression_items)) - return rules - def has_prismatic_jelly_reward_access(self) -> StardewRule: if self.options.special_order_locations == SpecialOrderLocations.option_disabled: return self.special_order.can_complete_special_order("Prismatic Jelly") diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 22629a66f681..9255264986b3 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -5,11 +5,9 @@ from .region_logic import RegionLogic from .time_logic import TimeLogic from ..options import StartingMoney -from ..stardew_rule import StardewRule, True_ +from ..stardew_rule import StardewRule, True_, CountPercent from ..strings.currency_names import Currency - -MONEY_PER_MONTH = 15000 -DISPOSABLE_INCOME_DIVISOR = 5 +from ..strings.region_names import Region qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", "25 Qi Gems", "20 Qi Gems", "10 Qi Gems") @@ -34,15 +32,20 @@ def __init__(self, player: int, cached_rules: CachedRules, starting_money_option @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: - if self.starting_money_option == -1: + if amount < 2000: return True_() - return self.time.has_lived_months(amount // MONEY_PER_MONTH) + shipping_bin_rule = self.region.can_reach(Region.shipping) + if amount < 10000: + return shipping_bin_rule + + percent_progression_items_needed = min(100, amount // 10000) + return shipping_bin_rule & CountPercent(self.player, percent_progression_items_needed) @cache_self1 def can_spend(self, amount: int) -> StardewRule: if self.starting_money_option == -1: return True_() - return self.time.has_lived_months(amount // (MONEY_PER_MONTH // DISPOSABLE_INCOME_DIVISOR)) + return self.can_have_earned_total(amount * 5) # Should be cached def can_spend_at(self, region: str, amount: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 18e4e4cb96db..c2d9af1ec7b7 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -3,10 +3,11 @@ from Utils import cache_self1 from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic -from ..stardew_rule import StardewRule +from ..stardew_rule import StardewRule, CountPercent, True_ from ..strings.ap_names.event_names import Event MAX_MONTHS = 12 +MONTH_COEFFICIENT = 100 // MAX_MONTHS class TimeLogic(CachedLogic): @@ -18,8 +19,10 @@ def __init__(self, player: int, cached_rules: CachedRules, received_logic: Recei @cache_self1 def has_lived_months(self, number: int) -> StardewRule: - number = max(0, min(number, MAX_MONTHS)) - return self.received(Event.month_end, number) + if number <= 0: + return True_() + number = min(number, MAX_MONTHS) + return CountPercent(self.player, number * MONTH_COEFFICIENT) @cached_property def has_lived_max_months(self) -> StardewRule: diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index dda0137a1957..9bbd9f3e0698 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -391,3 +391,35 @@ def __hash__(self): def simplify(self) -> StardewRule: return self.other_rules[self.item].simplify() + + +class CountPercent(StardewRule): + player: int + percent: int + + def __init__(self, player: int, percent: int): + + assert percent > 0, "CountPercent rule must be above 0%" + assert percent <= 100, "CountPercent rule can't require more than 100% of items" + + self.player = player + self.percent = percent + + def __call__(self, state: CollectionState) -> bool: + stardew_world = state.multiworld.worlds[self.player] + total_count = stardew_world.total_progression_items + needed_count = (total_count * self.percent) // 100 + total_count = 0 + for item in state.prog_items[self.player]: + item_count = state.prog_items[self.player][item] + total_count += item_count + if total_count >= needed_count: + return True + return False + + + def __repr__(self): + return f"CountPercent {self.percent}" + + def get_difficulty(self): + return self.percent diff --git a/worlds/stardew_valley/strings/ap_names/event_names.py b/worlds/stardew_valley/strings/ap_names/event_names.py index b84b6c2f939c..a5dd773f551f 100644 --- a/worlds/stardew_valley/strings/ap_names/event_names.py +++ b/worlds/stardew_valley/strings/ap_names/event_names.py @@ -1,4 +1,3 @@ class Event: victory = "Victory" - month_end = "Month End" can_construct_buildings = "Can Construct Buildings" diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 51ae535fec4f..94a961a424e2 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -58,6 +58,7 @@ def test_old_master_cannoli(self): 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() self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) @@ -95,6 +96,9 @@ class TestBundlesLogic(SVTestBase): } 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)) @@ -106,34 +110,30 @@ class TestBuildingLogic(SVTestBase): def test_coop_blueprint(self): self.assertFalse(self.world.logic.region.can_reach_location("Coop Blueprint")(self.multiworld.state)) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + 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): - self.assertFalse(self.world.logic.region.can_reach_location("Big Coop Blueprint")(self.multiworld.state), + 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("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Can Construct Buildings"), event=True) - self.assertFalse(self.world.logic.region.can_reach_location("Big Coop Blueprint")(self.multiworld.state), + 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=True) - self.assertTrue(self.world.logic.region.can_reach_location("Big Coop Blueprint")(self.multiworld.state), + 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.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + 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)) @@ -144,21 +144,20 @@ def test_deluxe_coop_blueprint(self): self.assertTrue(self.world.logic.region.can_reach_location("Deluxe Coop Blueprint")(self.multiworld.state)) def test_big_shed_blueprint(self): - self.assertFalse(self.world.logic.region.can_reach_location("Big Shed Blueprint")(self.multiworld.state), + 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("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) self.multiworld.state.collect(self.world.create_item("Can Construct Buildings"), event=True) - self.assertFalse(self.world.logic.region.can_reach_location("Big Shed Blueprint")(self.multiworld.state), + 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(self.world.logic.region.can_reach_location("Big Shed Blueprint")(self.multiworld.state), + self.assertTrue(big_shed_rule(self.multiworld.state), f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}") @@ -366,7 +365,7 @@ def test_can_learn_qos_recipe(self): 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([self.world.create_item("Month End")] * 10) + self.collect_lots_of_money() self.assertFalse(rule(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item("The Queen of Sauce"), event=False) @@ -390,7 +389,7 @@ def test_can_learn_qos_recipe(self): 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([self.world.create_item("Month End")] * 10) + self.collect_lots_of_money() self.assertFalse(rule(self.multiworld.state)) spring = self.world.create_item("Spring") @@ -410,7 +409,7 @@ def test_get_chefsanity_check_recipe(self): self.assertFalse(rule(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item("Spring"), event=False) - self.collect([self.world.create_item("Month End")] * 10) + self.collect_lots_of_money() self.assertFalse(rule(self.multiworld.state)) seeds = self.world.create_item("Radish Seeds") @@ -446,7 +445,7 @@ def test_can_craft_recipe(self): 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([self.world.create_item("Month End")] * 12) + self.collect_lots_of_money() self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False) self.assertFalse(rule(self.multiworld.state)) @@ -458,13 +457,14 @@ def test_can_learn_crafting_recipe(self): rule = self.world.logic.region.can_reach_location(location) self.assertFalse(rule(self.multiworld.state)) - self.multiworld.state.collect(self.world.create_item("Month End"), event=False) + self.collect_lots_of_money() self.assertTrue(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.assertFalse(rule(self.multiworld.state)) @@ -488,6 +488,7 @@ 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.assertFalse(rule(self.multiworld.state)) @@ -516,6 +517,7 @@ def test_can_craft_recipe(self): 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) @@ -537,6 +539,7 @@ 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.assertFalse(rule(self.multiworld.state)) @@ -625,8 +628,7 @@ class TestFriendsanityDatingRules(SVTestBase): } def test_earning_dating_heart_requires_dating(self): - for i in range(12): - self.multiworld.state.collect(self.world.create_item("Month End"), event=True) + self.collect_lots_of_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) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 101c07fb9928..4babbca57615 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -173,6 +173,11 @@ def run_default_tests(self) -> bool: should_run_default_tests = is_not_stardew_test and super().run_default_tests return should_run_default_tests + def collect_lots_of_money(self): + self.multiworld.state.collect(self.world.create_item("Shipping Bin"), event=False) + for i in range(30): + self.multiworld.state.collect(self.world.create_item("Stardrop"), event=False) + pre_generated_worlds = {} From c24ee3c8bb19a31acc284dfa7d99249077959959 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:18:03 -0500 Subject: [PATCH 165/482] Fix SVE friendsanity location requirements. --- worlds/stardew_valley/data/locations.csv | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a6d683bd2e8e..f942914062f0 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2283,10 +2283,10 @@ id,region,name,tags,mod_name 6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded 6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded 6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6181,Forest,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded -6182,Forest,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded -6183,Forest,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded -6184,Forest,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded +6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded +6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded +6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded +6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded 6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded 6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded 6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2315,16 +2315,16 @@ id,region,name,tags,mod_name 6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded 6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded 6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded -6213,Forest,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded -6214,Forest,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded -6215,Forest,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded -6216,Forest,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded -6217,Forest,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded -6218,Forest,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded -6219,Forest,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded -6220,Forest,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded -6221,Forest,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded -6222,Forest,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded +6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded +6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded +6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded +6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded +6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded +6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded +6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded +6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded +6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded +6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded 6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded 6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded 6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded From 30fd01685308c38716e1d4747c61cf5c63cd6454 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sat, 18 Nov 2023 10:48:35 -0600 Subject: [PATCH 166/482] Recipe and Craftsanity Logic # Conflicts: # worlds/stardew_valley/data/locations.csv --- worlds/stardew_valley/data/craftable_data.py | 53 +++++++++++++----- worlds/stardew_valley/data/items.csv | 18 +++++++ worlds/stardew_valley/data/locations.csv | 54 +++++++++++++++---- worlds/stardew_valley/data/recipe_data.py | 5 +- worlds/stardew_valley/logic/logic.py | 6 ++- .../stardew_valley/mods/logic/item_logic.py | 42 +++++++++++++-- worlds/stardew_valley/mods/logic/mod_logic.py | 5 +- .../stardew_valley/strings/craftable_names.py | 38 +++++++++++++ worlds/stardew_valley/strings/food_names.py | 5 ++ .../strings/forageable_names.py | 2 +- worlds/stardew_valley/strings/metal_names.py | 11 ++++ worlds/stardew_valley/strings/seed_names.py | 2 +- 12 files changed, 206 insertions(+), 35 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index d3b20f483399..3ce590945468 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -1,23 +1,26 @@ -from typing import Dict, List +from typing import Dict, List, Optional +from ..mods.mod_data import ModNames from .recipe_source import RecipeSource, StarterSource, QueenOfSauceSource, ShopSource, SkillSource, FriendshipSource, ShopTradeSource, CutsceneSource, \ ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource from ..strings.artisan_good_names import ArtisanGood -from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, Fishing, Ring, Consumable, Edible, Lighting, Storage, Furniture, Sign, Craftable +from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, Fishing, Ring, Consumable, Edible, Lighting, Storage, Furniture, Sign, Craftable, \ + ModEdible, ModCraftable, ModMachine, ModFloor, ModConsumable from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro from ..strings.fish_names import Fish, WaterItem from ..strings.flower_names import Flower -from ..strings.forageable_names import Forageable +from ..strings.food_names import Meal +from ..strings.forageable_names import Forageable, SVEForage from ..strings.ingredient_names import Ingredient from ..strings.machine_names import Machine from ..strings.material_names import Material from ..strings.metal_names import Ore, MetalBar, Fossil, Artifact, Mineral from ..strings.monster_drop_names import Loot -from ..strings.region_names import Region +from ..strings.region_names import Region, SVERegion from ..strings.seed_names import Seed, TreeSeed -from ..strings.skill_names import Skill +from ..strings.skill_names import Skill, ModSkill from ..strings.special_order_names import SpecialOrder from ..strings.villager_names import NPC @@ -26,11 +29,13 @@ class CraftingRecipe: item: str ingredients: Dict[str, int] source: RecipeSource + mod_name: Optional[str] = None - def __init__(self, item: str, ingredients: Dict[str, int], source: RecipeSource): + def __init__(self, item: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None): self.item = item self.ingredients = ingredients self.source = source + self.mod_name = mod_name def __repr__(self): return f"{self.item} (Source: {self.source} |" \ @@ -50,14 +55,14 @@ def cutscene_recipe(name: str, region: str, friend: str, hearts: int, ingredient return create_recipe(name, ingredients, source) -def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int]) -> CraftingRecipe: +def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe: source = SkillSource(skill, level) - return create_recipe(name, ingredients, source) + return create_recipe(name, ingredients, source, mod_name) -def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe: +def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe: source = ShopSource(region, price) - return create_recipe(name, ingredients, source) + return create_recipe(name, ingredients, source, mod_name) def festival_shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe: @@ -97,8 +102,8 @@ def cellar_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe: return create_recipe(name, ingredients, source) -def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) -> CraftingRecipe: - recipe = CraftingRecipe(name, ingredients, source) +def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None) -> CraftingRecipe: + recipe = CraftingRecipe(name, ingredients, source, mod_name) all_crafting_recipes.append(recipe) return recipe @@ -251,5 +256,29 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource) hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1}) cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 9, {Material.wood: 15, Material.fiber: 10, Material.coal: 3}) +magic_elixir = shop_recipe(ModEdible.magic_elixir, Region.adventurer_guild, 3000, {Edible.life_elixir: 1, Forageable.purple_mushroom: 1}, ModNames.magic) +travel_charm = shop_recipe(ModCraftable.travel_core, Region.adventurer_guild, 250, {Loot.solar_essence: 1, Loot.void_essence: 1}, ModNames.magic) +preservation_chamber = skill_recipe(ModMachine.preservation_chamber, ModSkill.archaeology, 2, {MetalBar.copper: 1, Material.wood: 15, ArtisanGood.oak_resin: 30}, + ModNames.archaeology) +preservation_chamber_h = skill_recipe(ModMachine.preservation_chamber_h, ModSkill.archaeology, 7, {MetalBar.copper: 1, Material.hardwood: 15, + ArtisanGood.oak_resin: 30}, ModNames.archaeology) +grinder = skill_recipe(ModMachine.grinder, ModSkill.archaeology, 8, {Artifact.rusty_cog: 10, MetalBar.iron: 5, ArtisanGood.battery_pack: 1}, ModNames.archaeology) +ancient_battery = skill_recipe(ModMachine.ancient_battery, ModSkill.archaeology, 6, {Material.stone: 40, MetalBar.copper: 10, MetalBar.iron: 5}, + ModNames.archaeology) +glass_bazier = skill_recipe(ModCraftable.glass_bazier, ModSkill.archaeology, 1, {Artifact.glass_shards: 10}, ModNames.archaeology) +glass_path = skill_recipe(ModFloor.glass_path, ModSkill.archaeology, 1, {Artifact.glass_shards: 1}, ModNames.archaeology) +glass_fence = skill_recipe(ModCraftable.glass_fence, ModSkill.archaeology, 1, {Artifact.glass_shards: 5}, ModNames.archaeology) +bone_path = skill_recipe(ModFloor.bone_path, ModSkill.archaeology, 3, {Fossil.bone_fragment: 1}, ModNames.archaeology) +water_strainer = skill_recipe(ModCraftable.water_strainer, ModSkill.archaeology, 4, {Material.wood: 40, MetalBar.copper: 4}, ModNames.archaeology) +wooden_display = skill_recipe(ModCraftable.wooden_display, ModSkill.archaeology, 2, {Material.wood: 25}, ModNames.archaeology) +hardwood_display = skill_recipe(ModCraftable.hardwood_display, ModSkill.archaeology, 7, {Material.hardwood: 10}, ModNames.archaeology) +volcano_totem = skill_recipe(ModConsumable.volcano_totem, ModSkill.archaeology, 9, {Material.cinder_shard: 5, Artifact.rare_disc: 1, Artifact.dwarf_gadget: 1}, + ModNames.archaeology) +haste_elixir = shop_recipe(ModEdible.haste_elixir, SVERegion.alesia_shop, 35000, {Loot.void_essence: 35, SVEForage.void_soul: 5, Ingredient.sugar: 1, + Meal.spicy_eel: 1}, ModNames.sve) +hero_elixir = shop_recipe(ModEdible.hero_elixir, SVERegion.issac_shop, 65000, {SVEForage.void_pebble: 3, SVEForage.void_soul: 5, Ingredient.oil: 1, + Loot.slime: 10}, ModNames.sve) +armor_elixir = shop_recipe(ModEdible.armor_elixir, SVERegion.alesia_shop, 50000, {Loot.solar_essence: 30, SVEForage.void_soul: 5, Ingredient.vinegar: 5, + Fossil.bone_fragment: 5}, ModNames.sve) all_crafting_recipes_by_name = {recipe.item: recipe for recipe in all_crafting_recipes} diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 053d56ce28e8..0ccb31c92b1e 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -801,3 +801,21 @@ id,name,classification,groups,mod_name 10513,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10514,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10515,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded +10601,Magic Elixir Recipe,progression,CRAFTSANITY,Magic +10602,Travel Core Recipe,progression,CRAFTSANITY,Magic +10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10606,Glass Bazier Recipe,progression,CRAFTSANITY,Archaeology +10607,Glass Path Recipe,progression,CRAFTSANITY,Archaeology +10608,Glass Fence Recipe,progression,CRAFTSANITY,Archaeology +10609,Bone Path Recipe,progression,CRAFTSANITY,Archaeology +10610,Water Strainer Recipe,progression,CRAFTSANITY,Archaeology +10611,Wooden Display Recipe,progression,CRAFTSANITY,Archaeology +10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology +10613,Warp Totem: Volcano Recipe,progression,CRAFTSANITY,Archaeology +10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology +10615,Hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology +10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology +10617,Ancient Battery Creator Recipe,progression,CRAFTSANITY,Archaeology + diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f942914062f0..87280187cc0e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2385,16 +2385,16 @@ id,region,name,tags,mod_name 6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded 6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded 6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded -6283,Railroad,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6284,Railroad,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6285,Railroad,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6286,Railroad,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6287,Railroad,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6288,Railroad,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6289,Railroad,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6290,Railroad,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6291,Railroad,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6292,Railroad,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded 6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded 6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded 6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2432,6 +2432,40 @@ id,region,name,tags,mod_name 7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator 7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator 7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic +7402,Farm,Craft Travel Core,CRAFTSANITY,Magic +7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded +7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded +7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Farm,Craft Glass Path,CRAFTSANITY,Archaeology +7407,Farm,Craft Bone Path,CRAFTSANITY,Archaeology +7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology +7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology +7410,Farm,Craft Water Strainer,CRAFTSANITY,Archaeology +7411,Farm,Craft Grinder,CRAFTSANITY,Archaeology +7412,Farm,Craft Ancient Battery Creator,CRAFTSANITY,Archaeology +7413,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology +7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology +7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology +7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology +7417,Farm,Craft Warp Totem: Volcano,CRAFTSANITY,Archaeology +7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic +7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic +7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Issac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology +7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology +7458,Farm,Glass Bazier Recipe,CRAFTSANITY,Archaeology +7459,Farm,Glass Fence Recipe,CRAFTSANITY,Archaeology +7460,Farm,Water Strainer Recipe,CRAFTSANITY,Archaeology +7461,Farm,Grinder Recipe,CRAFTSANITY,Archaeology +7462,Farm,Ancient Battery Creator Recipe,CRAFTSANITY,Archaeology +7463,Farm,Preservation Chamber Recipe,CRAFTSANITY,Archaeology +7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology +7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology +7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology +7467,Farm,Warp Totem: Volcano Recipe,CRAFTSANITY,Archaeology 7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 8357b3ec8b65..4bcd669d5a85 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -17,7 +17,6 @@ from ..strings.villager_names import NPC - class CookingRecipe: meal: str ingredients: Dict[str, int] @@ -179,7 +178,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, glazed_butterfish = shop_recipe(SVEMeal.glazed_butterfish, Region.saloon, 4000, {SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, ModNames.sve) mixed_berry_pie = shop_recipe(SVEMeal.mixed_berry_pie, Region.saloon, 3500, {Fruit.strawberry: 6, SVEFruit.salal_berry: 6, Forageable.blackberry: 6, - SVEForage.bearberry: 6, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}, + SVEForage.bearberrys: 6, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}, ModNames.sve) mushroom_berry_rice = shop_recipe(SVEMeal.mushroom_berry_rice, Region.adventurer_guild, 1500, {SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, Ingredient.rice: 1, Ingredient.sugar: 2}, ModNames.sve) @@ -188,4 +187,4 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, void_salmon_sushi = shop_recipe(SVEMeal.void_salmon_sushi, Region.sewer, 5000, {Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, ModNames.sve) -all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} +all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} \ No newline at end of file diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 1fab14015292..107507ff6a70 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -155,19 +155,23 @@ def __post_init__(self): self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, - self.season, self.money, self.relationship, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, + self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in all_fish}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) for recipe in all_cooking_recipes: + if recipe.mod_name is not None and recipe.mod_name not in mods_option: + continue can_cook_rule = self.cooking.can_cook(recipe) if recipe.meal in self.cooking_rules: can_cook_rule = can_cook_rule | self.cooking_rules[recipe.meal] self.cooking_rules[recipe.meal] = can_cook_rule for recipe in all_crafting_recipes: + if recipe.mod_name is not None and recipe.mod_name not in mods_option: + continue can_craft_rule = self.crafting.can_craft(recipe) if recipe.item in self.crafting_rules: can_craft_rule = can_craft_rule | self.crafting_rules[recipe.item] diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 412c8390623b..94ec7895b268 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -5,14 +5,17 @@ from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogic from ...logic.money_logic import MoneyLogic +from ...logic.museum_logic import MuseumLogic from ...logic.region_logic import RegionLogic from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic from ...logic.received_logic import ReceivedLogic from ...logic.tool_logic import ToolLogic +from ...logic.crafting_logic import CraftingLogic from ...options import Mods from ..mod_data import ModNames from ...strings.crop_names import SVEVegetable, SVEFruit +from ...strings.food_names import SVEMeal, SVEBeverage from ...strings.gift_names import SVEGift from ...strings.tool_names import Tool, ToolMaterial from ...strings.forageable_names import SVEForage @@ -33,11 +36,13 @@ class ModItemLogic: region: RegionLogic season: SeasonLogic relationship: RelationshipLogic + museum: MuseumLogic received: ReceivedLogic tool: ToolLogic + crafting: CraftingLogic - def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogic, money: MoneyLogic, region: RegionLogic, - season: SeasonLogic, relationship: RelationshipLogic, tool: ToolLogic): + def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogic, money: MoneyLogic, + region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): self.combat = combat self.crop = crop self.cooking = cooking @@ -47,7 +52,9 @@ def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: Co self.region = region self.season = season self.relationship = relationship + self.museum = museum self.tool = tool + self.crafting = crafting def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() @@ -73,11 +80,36 @@ def _get_sve_item_rules(self): SVESeed.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon, SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon & self.cooking.can_cook(), SVEForage.winter_star_rose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.winter), - SVEForage.bearberry: self.region.can_reach(Region.secret_woods) & self.season.has(Season.winter), - SVEForage.poison_mushroom: self.region.can_reach(Region.secret_woods) & (self.season.has(Season.summer) | self.season.has(Season.fall)), + SVEForage.bearberrys: self.region.can_reach(Region.secret_woods) & self.season.has(Season.winter), + SVEForage.poison_mushroom: self.region.can_reach(Region.secret_woods) & self.season.has_any([Season.summer, Season.fall]), SVEForage.red_baneberry: self.region.can_reach(Region.secret_woods) & self.season.has(Season.summer), SVEForage.ferngill_primrose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.spring), SVEForage.goldenrod: self.region.can_reach(SVERegion.summit) & (self.season.has(Season.summer) | self.season.has(Season.fall)), SVESeed.shrub_seed: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.hoe, ToolMaterial.basic), - SVEFruit.salal_berry: self.crop.can_plant_and_grow_item([Season.spring,Season.summer]) & self.has(SVESeed.shrub_seed), + SVEFruit.salal_berry: self.crop.can_plant_and_grow_item([Season.spring, Season.summer]) & self.has(SVESeed.shrub_seed), + ModEdible.aegis_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 28000), + ModEdible.lightning_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 12000), + ModEdible.barbarian_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 22000), + ModEdible.gravity_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 4000), + SVESeed.ancient_ferns_seed: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.hoe, ToolMaterial.basic), + SVEVegetable.ancient_fiber: self.crop.can_plant_and_grow_item(Season.summer) & self.has(SVESeed.ancient_ferns_seed), + SVEForage.big_conch: self.region.can_reach_any((Region.beach, SVERegion.fable_reef)), + SVEForage.dewdrop_berry: self.region.can_reach(SVERegion.enchanted_grove), + SVEForage.dried_sand_dollar: self.region.can_reach(SVERegion.fable_reef) | (self.region.can_reach(Region.beach) & + self.season.has_any([Season.summer, Season.fall])), + "Galdoran Gem": self.museum.can_complete_museum() & self.relationship.has_hearts(ModNPC.marlon, 8), + SVEForage.golden_ocean_flower: self.region.can_reach(SVERegion.fable_reef), + SVEMeal.grampleton_orange_chicken: self.money.can_spend_at(Region.saloon, 650), + ModEdible.hero_elixir: self.money.can_spend_at(SVERegion.issac_shop, 8000), + SVEForage.lucky_four_leaf_clover: self.region.can_reach_any((Region.secret_woods, SVERegion.forest_west)) & + self.season.has_any([Season.spring, Season.summer]), + SVEForage.mushroom_colony: self.region.can_reach_any((Region.secret_woods, SVERegion.junimo_woods, SVERegion.forest_west)) & + self.season.has(Season.fall), + SVEForage.rusty_blade: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, + SVEForage.smelly_rafflesia: self.region.can_reach(Region.secret_woods), + SVEBeverage.sports_drink: self.money.can_spend_at(Region.hospital, 750), + "Stamina Capsule": self.money.can_spend_at(Region.hospital, 4000), + SVEForage.thistle: self.region.can_reach(SVERegion.summit), + SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, + ModLoot.void_shard: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon } diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 12c236fa9fcb..18e1b29c5d54 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -21,6 +21,7 @@ from ...logic.has_logic import HasLogic from ...logic.mine_logic import MineLogic from ...logic.money_logic import MoneyLogic +from ...logic.museum_logic import MuseumLogic from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogic from ...logic.region_logic import RegionLogic @@ -46,10 +47,10 @@ class ModLogic: sve: SVELogic def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, - action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, building: BuildingLogic, wallet: WalletLogic, + action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, museum: MuseumLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): - self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, tool) + self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, museum, tool, crafting) self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) self.buildings = ModBuildingLogic(player, has, money, mods) diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index bada4c6d8a20..0ba1fba51287 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -137,3 +137,41 @@ class Craftable: farm_computer = "Farm Computer" hopper = "Hopper" cookout_kit = "Cookout Kit" + + +class ModEdible: + magic_elixir = "Magic Elixir" + aegis_elixir = "Aegis Elixir" + armor_elixir = "Armor Elixir" + barbarian_elixir = "Barbarian Elixir" + lightning_elixir = "Lightning Elixir" + gravity_elixir = "Gravity Elixir" + hero_elixir = "Hero Elixir" + haste_elixir = "Haste Elixir" + + +class ModCraftable: + travel_core = "Travel Core" + glass_bazier = "Glass Bazier" + water_strainer = "Water Strainer" + glass_fence = "Glass Fence" + wooden_display = "Wooden Display" + hardwood_display = "Hardwood Display" + + +class ModMachine: + preservation_chamber = "Preservation Chamber" + preservation_chamber_h = "hardwood Preservation Chamber" + grinder = "Grinder" + ancient_battery = "Ancient Battery Creator" + + +class ModFloor: + glass_path = "Glass Path" + bone_path = "Bone Path" + + +class ModConsumable: + volcano_totem = "Warp Totem: Volcano" + + diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index c7b110d19f7a..9294cbebb7d5 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -99,4 +99,9 @@ class SVEMeal: seaweed_salad = "Seaweed Salad" void_delight = "Void Delight" void_salmon_sushi = "Void Salmon Sushi" + grampleton_orange_chicken = "Grampleton Orange Chicken" + + +class SVEBeverage: + sports_drink = "Sports Drink" diff --git a/worlds/stardew_valley/strings/forageable_names.py b/worlds/stardew_valley/strings/forageable_names.py index 9e40e62cb7de..3b4c9f7759ee 100644 --- a/worlds/stardew_valley/strings/forageable_names.py +++ b/worlds/stardew_valley/strings/forageable_names.py @@ -41,7 +41,7 @@ class SVEForage: ferngill_primrose = "Ferngill Primrose" goldenrod = "Goldenrod" winter_star_rose = "Winter Star Rose" - bearberry = "Bearberry" + bearberrys = "Bearberrys" poison_mushroom = "Poison Mushroom" red_baneberry = "Red Baneberry" big_conch = "Big Conch" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 75c08d48d3e1..0555f6cd32f5 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -33,6 +33,16 @@ class Mineral: class Artifact: dwarf_gadget = "Dwarf Gadget" ancient_seed = "Ancient Seed" + glass_shards = "Glass Shards" + rusty_cog = "Rusty Cog" + rare_disc = "Rare Disc" + ancient_doll = "Ancient Doll" + ancient_drum = "Ancient Drum" + ancient_sword = "Ancient Sword" + arrowhead = "Arrowhead" + bone_flute = "Bone Flute" + chewing_stick = "Chewing Stick" + chicken_statue = "Chicken Statue" class Fossil: @@ -46,4 +56,5 @@ class Fossil: mummified_frog = "Mummified Frog" snake_skull = "Snake Skull" snake_vertebrae = "Snake Vertebrae" + amphibian_fossil = "Amphibian Fossil" diff --git a/worlds/stardew_valley/strings/seed_names.py b/worlds/stardew_valley/strings/seed_names.py index 2d5362c2337e..4abb86e679e4 100644 --- a/worlds/stardew_valley/strings/seed_names.py +++ b/worlds/stardew_valley/strings/seed_names.py @@ -29,4 +29,4 @@ class SVESeed: slime_seed = "Slime Seed" void_seed = "Void Seed" shrub_seed = "Shrub Seed" - ancient_fern_seed = "Ancient Fern Seed" + ancient_ferns_seed = "Ancient Ferns Seed" From 5ba48332b125cf5839f7d933e5872ec5a9557a6e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sat, 18 Nov 2023 10:48:44 -0600 Subject: [PATCH 167/482] Shipsanity Logic # Conflicts: # worlds/stardew_valley/data/locations.csv --- worlds/stardew_valley/data/locations.csv | 193 ++++++++++++++++++ worlds/stardew_valley/logic/logic.py | 3 +- worlds/stardew_valley/logic/shipping_logic.py | 8 +- .../stardew_valley/mods/logic/item_logic.py | 39 +++- 4 files changed, 236 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 87280187cc0e..a4aac2570a71 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2529,3 +2529,196 @@ id,region,name,tags,mod_name 7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded 7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded 7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic +8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded +8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded +8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded +8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded +8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded +8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded +8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded +8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded +8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded +8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded +8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded +8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded +8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded +8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded +8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded +8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded +8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded +8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded +8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded +8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded +8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded +8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded +8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded +8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology +8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology +8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology +8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology +8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology +8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology +8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology +8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology +8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology +8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology +8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology +8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology +8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology +8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology +8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology +8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology +8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology +8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology +8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology +8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology +8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology +8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology +8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology +8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology +8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology +8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology +8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology +8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology +8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology +8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology +8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology +8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology +8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology +8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology +8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology +8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology +8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology +8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology +8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology +8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology +8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology +8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology +8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology +8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology +8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology +8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology +8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology +8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology +8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology +8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology +8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology +8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology +8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology +8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology +8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology +8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology +8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology +8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology +8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology +8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology +8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology +8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology +8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology +8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology +8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology +8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology +8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology +8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology +8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology +8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology +8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology +8201,Shipping,Shipsanity: Warp Totem: Volcano,"SHIPSANITY,GINGER_ISLAND",Archaeology +8202,Shipping,Shipsanity: Water Strainer,SHIPSANITY,Archaeology diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 107507ff6a70..f7be4ea4574f 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -124,7 +124,8 @@ def __post_init__(self): mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island self.buildings = BuildingLogic(self.player, self.cached_rules, self.options.building_progression, self.received, self.has, self.region, self.money) - self.shipping = ShippingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.has, self.region, self.buildings) + self.shipping = ShippingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, mods_option, self.has, self.region, + self.buildings) self.relationship = RelationshipLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.cached_rules, self.options.museumsanity, self.received, self.has, self.region, self.action) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 0d09058a5f70..26cee518a65f 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -8,6 +8,7 @@ from ..locations import LocationTags, locations_by_tag from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations +from ..options import Mods from ..stardew_rule import StardewRule, And from ..strings.building_names import Building from ..strings.region_names import Region @@ -16,16 +17,18 @@ class ShippingLogic(CachedLogic): exclude_ginger_island: ExcludeGingerIsland special_orders_option: SpecialOrderLocations + mods: Mods has: HasLogic region: RegionLogic buildings: BuildingLogic def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, - special_orders_option: SpecialOrderLocations, + special_orders_option: SpecialOrderLocations, mods: Mods, has: HasLogic, region: RegionLogic, buildings: BuildingLogic): super().__init__(player, cached_rules) self.exclude_ginger_island = exclude_ginger_island self.special_orders_option = special_orders_option + self.mods = mods self.has = has self.region = region self.buildings = buildings @@ -47,8 +50,9 @@ def can_ship_everything(self) -> StardewRule: all_items_to_ship = [] include_island = self.exclude_ginger_island == ExcludeGingerIsland.option_false include_qi = self.special_orders_option == SpecialOrderLocations.option_board_qi + mod_list = self.mods.value for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ - (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags): + (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags) and location.mod_name in mod_list: all_items_to_ship.append(location.name[len(shipsanity_prefix):]) return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 94ec7895b268..a0fefc200ed6 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -1,5 +1,6 @@ from typing import Dict +from ...data.craftable_data import all_crafting_recipes_by_name from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic from ...logic.crop_logic import CropLogic @@ -14,16 +15,28 @@ from ...logic.crafting_logic import CraftingLogic from ...options import Mods from ..mod_data import ModNames +from ...strings.craftable_names import ModCraftable, ModEdible, ModFloor, ModMachine from ...strings.crop_names import SVEVegetable, SVEFruit from ...strings.food_names import SVEMeal, SVEBeverage from ...strings.gift_names import SVEGift from ...strings.tool_names import Tool, ToolMaterial from ...strings.forageable_names import SVEForage +from ...strings.metal_names import Artifact, Fossil from ...strings.monster_drop_names import ModLoot from ...strings.season_names import Season from ...strings.seed_names import SVESeed from ...strings.region_names import Region, SVERegion -from ...stardew_rule import StardewRule +from ...strings.villager_names import ModNPC +from ...stardew_rule import StardewRule, True_ + +display_types = ["Wooden Display: ", "Hardwood Display: "] +display_items = ["Amphibian Fossil", "Anchor", "Ancient Doll", "Ancient Drum", "Ancient Seed", "Ancient Sword", "Arrowhead", "Bone Flute", "Chewing Stick", + "Chicken Statue", "Chipped Amphora", "Dinosaur Egg", "Dried Starfish", "Dwarf Gadget", "Dwarf Scroll I", "Dwarf Scroll II", "Dwarf Scroll III", + "Dwarf Scroll IV", "Dwarvish Helm", "Elvish Jewelry", "Fossilized Leg", "Fossilized Ribs", "Fossilized Skull", "Fossilized Spine", + "Fossilized Tail", "Glass Shards", "Golden Mask", "Golden Relic", "Mummified Bat", "Mummified Frog", "Nautilus Fossil", "Ornamental Fan", + "Palm Fossil", "Prehistoric Handaxe", "Prehistoric Rib", "Prehistoric Scapula", "Prehistoric Skull", "Prehistoric Tibia", "Prehistoric Tool", + "Prehistoric Vertebra", "Rare Disc", "Rusty Cog", "Rusty Spoon", "Rusty Spur", "Skeletal Hand", "Skeletal Tail", "Snake Skull", "Snake Vertebrae", + "Strange Doll (Green)", "Strange Doll", "Trilobite"] class ModItemLogic: @@ -59,11 +72,12 @@ def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: Co def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() if ModNames.sve in self.mods: - items.update(self._get_sve_item_rules()) - + items.update(self.get_sve_item_rules()) + if ModNames.archaeology in self.mods: + items.update(self.get_archaeology_item_rules()) return items - def _get_sve_item_rules(self): + def get_sve_item_rules(self): return {SVEGift.aged_blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 28000), SVEGift.blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 3000), SVESeed.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon, @@ -113,3 +127,20 @@ def _get_sve_item_rules(self): SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, ModLoot.void_shard: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon } + + def get_archaeology_item_rules(self): + archaeology_item_rules = {} + + for item in display_items: + for display_type in display_types: + display_item = display_type[:-2] + location_name = display_type + item + if "Wooden" in display_item: + archaeology_item_rules[location_name] = (self.crafting.can_craft(all_crafting_recipes_by_name[display_item]) & + self.crafting.can_craft(all_crafting_recipes_by_name[ModMachine.preservation_chamber]) & \ + self.has(item)) + else: + archaeology_item_rules[location_name] = (self.crafting.can_craft(all_crafting_recipes_by_name[display_item]) & + self.crafting.can_craft(all_crafting_recipes_by_name[ModMachine.preservation_chamber_h]) & \ + self.has(item)) + return archaeology_item_rules From e5b04f1c48712895bf19522972b9678a411788f2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 19 Nov 2023 13:37:26 -0500 Subject: [PATCH 168/482] - Improved the shipping logic code a tiny bit # Conflicts: # worlds/stardew_valley/logic/shipping_logic.py --- worlds/stardew_valley/logic/shipping_logic.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 26cee518a65f..296c4e078225 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -48,11 +48,15 @@ def can_ship_items(self) -> StardewRule: def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " all_items_to_ship = [] - include_island = self.exclude_ginger_island == ExcludeGingerIsland.option_false - include_qi = self.special_orders_option == SpecialOrderLocations.option_board_qi + exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_qi = self.special_orders_option != SpecialOrderLocations.option_board_qi mod_list = self.mods.value for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: - if (include_island or LocationTags.GINGER_ISLAND not in location.tags) and \ - (include_qi or LocationTags.REQUIRES_QI_ORDERS not in location.tags) and location.mod_name in mod_list: - all_items_to_ship.append(location.name[len(shipsanity_prefix):]) + if exclude_island and LocationTags.GINGER_ISLAND in location.tags: + continue + if exclude_qi and LocationTags.REQUIRES_QI_ORDERS in location.tags: + continue + if location.mod_name and location.mod_name not in mod_list: + continue + all_items_to_ship.append(location.name[len(shipsanity_prefix):]) return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) From 3ab410c78242411141c362e584f85c15168fc11e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 20 Nov 2023 20:21:36 -0600 Subject: [PATCH 169/482] Consolidating strings and clean up code --- worlds/stardew_valley/data/craftable_data.py | 4 +- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/logic/logic.py | 4 +- .../stardew_valley/mods/logic/item_logic.py | 33 +++---- .../stardew_valley/strings/craftable_names.py | 2 +- worlds/stardew_valley/strings/metal_names.py | 88 ++++++++++++++----- 6 files changed, 83 insertions(+), 50 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 3ce590945468..1f7b21be78a4 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -260,8 +260,8 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, travel_charm = shop_recipe(ModCraftable.travel_core, Region.adventurer_guild, 250, {Loot.solar_essence: 1, Loot.void_essence: 1}, ModNames.magic) preservation_chamber = skill_recipe(ModMachine.preservation_chamber, ModSkill.archaeology, 2, {MetalBar.copper: 1, Material.wood: 15, ArtisanGood.oak_resin: 30}, ModNames.archaeology) -preservation_chamber_h = skill_recipe(ModMachine.preservation_chamber_h, ModSkill.archaeology, 7, {MetalBar.copper: 1, Material.hardwood: 15, - ArtisanGood.oak_resin: 30}, ModNames.archaeology) +preservation_chamber_h = skill_recipe(ModMachine.hardwood_preservation_chamber, ModSkill.archaeology, 7, {MetalBar.copper: 1, Material.hardwood: 15, + ArtisanGood.oak_resin: 30}, ModNames.archaeology) grinder = skill_recipe(ModMachine.grinder, ModSkill.archaeology, 8, {Artifact.rusty_cog: 10, MetalBar.iron: 5, ArtisanGood.battery_pack: 1}, ModNames.archaeology) ancient_battery = skill_recipe(ModMachine.ancient_battery, ModSkill.archaeology, 6, {Material.stone: 40, MetalBar.copper: 10, MetalBar.iron: 5}, ModNames.archaeology) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 0ccb31c92b1e..c7dbf8b25fdd 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -815,7 +815,7 @@ id,name,classification,groups,mod_name 10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology 10613,Warp Totem: Volcano Recipe,progression,CRAFTSANITY,Archaeology 10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology -10615,Hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology +10615,hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology 10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology 10617,Ancient Battery Creator Recipe,progression,CRAFTSANITY,Archaeology diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index f7be4ea4574f..afd4e033a763 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -163,7 +163,7 @@ def __post_init__(self): self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) for recipe in all_cooking_recipes: - if recipe.mod_name is not None and recipe.mod_name not in mods_option: + if recipe.mod_name and recipe.mod_name not in mods_option: continue can_cook_rule = self.cooking.can_cook(recipe) if recipe.meal in self.cooking_rules: @@ -171,7 +171,7 @@ def __post_init__(self): self.cooking_rules[recipe.meal] = can_cook_rule for recipe in all_crafting_recipes: - if recipe.mod_name is not None and recipe.mod_name not in mods_option: + if recipe.mod_name and recipe.mod_name not in mods_option: continue can_craft_rule = self.crafting.can_craft(recipe) if recipe.item in self.crafting_rules: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index a0fefc200ed6..11e6807f70cf 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -15,28 +15,22 @@ from ...logic.crafting_logic import CraftingLogic from ...options import Mods from ..mod_data import ModNames -from ...strings.craftable_names import ModCraftable, ModEdible, ModFloor, ModMachine +from ...strings.craftable_names import ModCraftable, ModEdible, ModMachine from ...strings.crop_names import SVEVegetable, SVEFruit from ...strings.food_names import SVEMeal, SVEBeverage from ...strings.gift_names import SVEGift from ...strings.tool_names import Tool, ToolMaterial from ...strings.forageable_names import SVEForage -from ...strings.metal_names import Artifact, Fossil +from ...strings.metal_names import all_fossils, all_artifacts from ...strings.monster_drop_names import ModLoot from ...strings.season_names import Season from ...strings.seed_names import SVESeed from ...strings.region_names import Region, SVERegion from ...strings.villager_names import ModNPC -from ...stardew_rule import StardewRule, True_ +from ...stardew_rule import StardewRule -display_types = ["Wooden Display: ", "Hardwood Display: "] -display_items = ["Amphibian Fossil", "Anchor", "Ancient Doll", "Ancient Drum", "Ancient Seed", "Ancient Sword", "Arrowhead", "Bone Flute", "Chewing Stick", - "Chicken Statue", "Chipped Amphora", "Dinosaur Egg", "Dried Starfish", "Dwarf Gadget", "Dwarf Scroll I", "Dwarf Scroll II", "Dwarf Scroll III", - "Dwarf Scroll IV", "Dwarvish Helm", "Elvish Jewelry", "Fossilized Leg", "Fossilized Ribs", "Fossilized Skull", "Fossilized Spine", - "Fossilized Tail", "Glass Shards", "Golden Mask", "Golden Relic", "Mummified Bat", "Mummified Frog", "Nautilus Fossil", "Ornamental Fan", - "Palm Fossil", "Prehistoric Handaxe", "Prehistoric Rib", "Prehistoric Scapula", "Prehistoric Skull", "Prehistoric Tibia", "Prehistoric Tool", - "Prehistoric Vertebra", "Rare Disc", "Rusty Cog", "Rusty Spoon", "Rusty Spur", "Skeletal Hand", "Skeletal Tail", "Snake Skull", "Snake Vertebrae", - "Strange Doll (Green)", "Strange Doll", "Trilobite"] +display_types = [ModCraftable.wooden_display, ModCraftable.hardwood_display] +display_items = all_artifacts + all_fossils class ModItemLogic: @@ -130,17 +124,14 @@ def get_sve_item_rules(self): def get_archaeology_item_rules(self): archaeology_item_rules = {} - + preservation_chamber_rule = self.has(ModMachine.preservation_chamber) + hardwood_preservation_chamber_rule = self.has(ModMachine.hardwood_preservation_chamber) for item in display_items: for display_type in display_types: - display_item = display_type[:-2] - location_name = display_type + item - if "Wooden" in display_item: - archaeology_item_rules[location_name] = (self.crafting.can_craft(all_crafting_recipes_by_name[display_item]) & - self.crafting.can_craft(all_crafting_recipes_by_name[ModMachine.preservation_chamber]) & \ - self.has(item)) + location_name = display_type + ": " + item + chamber_rule = self.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.has(item) + if "Wooden" in display_type: + archaeology_item_rules[location_name] = chamber_rule & preservation_chamber_rule else: - archaeology_item_rules[location_name] = (self.crafting.can_craft(all_crafting_recipes_by_name[display_item]) & - self.crafting.can_craft(all_crafting_recipes_by_name[ModMachine.preservation_chamber_h]) & \ - self.has(item)) + archaeology_item_rules[location_name] = chamber_rule & hardwood_preservation_chamber_rule return archaeology_item_rules diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index 0ba1fba51287..055deccc4d8e 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -161,7 +161,7 @@ class ModCraftable: class ModMachine: preservation_chamber = "Preservation Chamber" - preservation_chamber_h = "hardwood Preservation Chamber" + hardwood_preservation_chamber = "hardwood Preservation Chamber" grinder = "Grinder" ancient_battery = "Ancient Battery Creator" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 0555f6cd32f5..60f3008cfc74 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -1,3 +1,17 @@ +all_fossils = [] +all_artifacts = [] + + +def fossil(name: str): + all_fossils.append(name) + return name + + +def artifact(name: str): + all_artifacts.append(name) + return name + + class Ore: copper = "Copper Ore" iron = "Iron Ore" @@ -31,30 +45,58 @@ class Mineral: class Artifact: - dwarf_gadget = "Dwarf Gadget" - ancient_seed = "Ancient Seed" - glass_shards = "Glass Shards" - rusty_cog = "Rusty Cog" - rare_disc = "Rare Disc" - ancient_doll = "Ancient Doll" - ancient_drum = "Ancient Drum" - ancient_sword = "Ancient Sword" - arrowhead = "Arrowhead" - bone_flute = "Bone Flute" - chewing_stick = "Chewing Stick" - chicken_statue = "Chicken Statue" + dwarf_gadget = artifact("Dwarf Gadget") + ancient_seed = artifact("Ancient Seed") + glass_shards = artifact("Glass Shards") + rusty_cog = artifact("Rusty Cog") + rare_disc = artifact("Rare Disc") + ancient_doll = artifact("Ancient Doll") + ancient_drum = artifact("Ancient Drum") + ancient_sword = artifact("Ancient Sword") + arrowhead = artifact("Arrowhead") + bone_flute = artifact("Bone Flute") + chewing_stick = artifact("Chewing Stick") + chicken_statue = artifact("Chicken Statue") + anchor = artifact("Anchor") + chipped_amphora = artifact("Chipped Amphora") + dwarf_scroll_i = artifact("Dwarf Scroll I") + dwarf_scroll_ii = artifact("Dwarf Scroll II") + dwarf_scroll_iii = artifact("Dwarf Scroll III") + dwarf_scroll_iv = artifact("Dwarf Scroll IV") + dwarvish_helm = artifact("Dwarvish Helm") + elvish_jewelry = artifact("Elvish Jewelry") + golden_mask = artifact("Golden Mask") + golden_relic = artifact("Golden Relic") + ornamental_fan = artifact("Ornamental Fan") + prehistoric_hammer = artifact("Prehistoric Handaxe") + prehistoric_tool = artifact("Prehistoric Tool") + rusty_spoon = artifact("Rusty Spoon") + rusty_spur = artifact("Rusty Spur") + strange_doll_green = artifact("Strange Doll (Green)") + strange_doll = artifact("Strange Doll") class Fossil: bone_fragment = "Bone Fragment" - fossilized_leg = "Fossilized Leg" - fossilized_ribs = "Fossilized Ribs" - fossilized_skull = "Fossilized Skull" - fossilized_spine = "Fossilized Spine" - fossilized_tail = "Fossilized Tail" - mummified_bat = "Mummified Bat" - mummified_frog = "Mummified Frog" - snake_skull = "Snake Skull" - snake_vertebrae = "Snake Vertebrae" - amphibian_fossil = "Amphibian Fossil" - + fossilized_leg = fossil("Fossilized Leg") + fossilized_ribs = fossil("Fossilized Ribs") + fossilized_skull = fossil("Fossilized Skull") + fossilized_spine = fossil("Fossilized Spine") + fossilized_tail = fossil("Fossilized Tail") + mummified_bat = fossil("Mummified Bat") + mummified_frog = fossil("Mummified Frog") + snake_skull = fossil("Snake Skull") + snake_vertebrae = fossil("Snake Vertebrae") + amphibian_fossil = fossil("Amphibian Fossil") + dinosaur_egg = fossil("Dinosaur Egg") + dried_starfish = fossil("Dried Starfish") + nautilus_fossil = fossil("Nautilus Fossil") + palm_fossil = fossil("Palm Fossil") + prehistoric_rib = fossil("Prehistoric Rib") + prehistoric_scapula = fossil("Prehistoric Scapula") + prehistoric_skull = fossil("Prehistoric Skull") + prehistoric_tibia = fossil("Prehistoric Tibia") + prehistoric_hand = fossil("Skeletal Hand") + skeletal_tail = fossil("Skeletal Tail") + trilobite = fossil("Trilobite") + prehistoric_vertebra = fossil("Prehistoric Vertebra") From 2ecdf91a87a70140436408d34a068e9df096e219 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 20 Nov 2023 20:23:46 -0600 Subject: [PATCH 170/482] Remove default value --- worlds/stardew_valley/data/craftable_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 1f7b21be78a4..5c836c7f7bd0 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -29,7 +29,7 @@ class CraftingRecipe: item: str ingredients: Dict[str, int] source: RecipeSource - mod_name: Optional[str] = None + mod_name: Optional[str] def __init__(self, item: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None): self.item = item From f742b7574219c722d94b96bbf4d75f770cd5f67f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 22:24:06 -0500 Subject: [PATCH 171/482] - rename a variable, fix a syntax, etc --- worlds/stardew_valley/mods/logic/item_logic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 11e6807f70cf..29b525a3c663 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -128,10 +128,10 @@ def get_archaeology_item_rules(self): hardwood_preservation_chamber_rule = self.has(ModMachine.hardwood_preservation_chamber) for item in display_items: for display_type in display_types: - location_name = display_type + ": " + item - chamber_rule = self.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.has(item) + location_name = f"{display_type}: {item}" + display_item_rule = self.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.has(item) if "Wooden" in display_type: - archaeology_item_rules[location_name] = chamber_rule & preservation_chamber_rule + archaeology_item_rules[location_name] = display_item_rule & preservation_chamber_rule else: - archaeology_item_rules[location_name] = chamber_rule & hardwood_preservation_chamber_rule + archaeology_item_rules[location_name] = display_item_rule & hardwood_preservation_chamber_rule return archaeology_item_rules From d0fa74410ade9f4472f95dccf8c6487840cf9c1c Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:41:03 -0500 Subject: [PATCH 172/482] - Fix conflicts in relationship logic --- .../logic/relationship_logic.py | 20 ++++--------------- worlds/stardew_valley/rules.py | 5 ++--- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index cb6e2b36dde0..23309f5818cc 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -153,22 +153,8 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: previous_heart = hearts - self.heart_size_option previous_heart_rule = self.has_hearts(npc, previous_heart) - # if npc == NPC.wizard and ModNames.magic in self.options.mods: - # earn_rule = self.can_meet(npc) & self.time.has_lived_months(hearts) - if npc in all_villagers_by_name: - if not self.npc_is_in_current_slot(npc): - return previous_heart_rule - villager = all_villagers_by_name[npc] - rule_if_birthday = self.season.has(villager.birthday) & self.time.has_lived_months(hearts // 2) - rule_if_not_birthday = self.time.has_lived_months(hearts) - earn_rule = self.can_meet(npc) & (rule_if_birthday | rule_if_not_birthday) - if villager.bachelor: - if hearts > 8: - earn_rule = earn_rule & self.can_date(npc) - if hearts > 10: - earn_rule = earn_rule & self.can_marry(npc) - else: - earn_rule = self.time.has_lived_months(min(hearts // 2, 8)) + if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): + return previous_heart_rule rules = [previous_heart_rule, self.can_meet(npc)] villager = all_villagers_by_name[npc] @@ -180,6 +166,8 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: if hearts > 10: rules.append(self.can_marry(npc)) + return And(*rules) + @cache_self1 def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 565ea5ab95be..1e675eecfa77 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -134,9 +134,8 @@ def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): And(*(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), - And(logic.region.can_reach_location(bundle.name) - for bundle - in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]))) + And(*(logic.region.can_reach_location(bundle.name) + for bundle in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), And(*(logic.region.can_reach_location(bundle.name) for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]))) From fd70435aa26b141f0e23efc2739aabb52bc8772e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 20 Nov 2023 23:43:35 -0500 Subject: [PATCH 173/482] - Fix cropsanity rename --- worlds/stardew_valley/test/TestRules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 94a961a424e2..b25cab6188e1 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -375,7 +375,7 @@ def test_can_learn_qos_recipe(self): class TestRecipeReceiveLogic(SVTestBase): options = { BuildingProgression.internal_name: BuildingProgression.option_progressive, - options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + 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, From 9867eb039d07f784ae75ed39aa8893a37c6a2184 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 00:41:49 -0500 Subject: [PATCH 174/482] - Fixed a few tests failing on the new money logic --- worlds/stardew_valley/test/TestRules.py | 12 ++++++------ worlds/stardew_valley/test/__init__.py | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index b25cab6188e1..e950266d4d04 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -430,7 +430,7 @@ def test_get_chefsanity_check_recipe(self): class TestCraftsanityLogic(SVTestBase): options = { BuildingProgression.internal_name: BuildingProgression.option_progressive, - options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + options.Cropsanity.internal_name: options.Cropsanity.option_enabled, Craftsanity.internal_name: Craftsanity.option_all, ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, } @@ -445,7 +445,7 @@ def test_can_craft_recipe(self): 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_lots_of_money() + self.collect_all_the_money() self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False) self.assertFalse(rule(self.multiworld.state)) @@ -478,7 +478,7 @@ def test_can_craft_festival_recipe(self): class TestCraftsanityWithFestivalsLogic(SVTestBase): options = { BuildingProgression.internal_name: BuildingProgression.option_progressive, - options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + 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, @@ -503,7 +503,7 @@ class TestNoCraftsanityLogic(SVTestBase): options = { BuildingProgression.internal_name: BuildingProgression.option_progressive, SeasonRandomization.internal_name: SeasonRandomization.option_progressive, - options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + 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, @@ -529,7 +529,7 @@ def test_can_craft_festival_recipe(self): class TestNoCraftsanityWithFestivalsLogic(SVTestBase): options = { BuildingProgression.internal_name: BuildingProgression.option_progressive, - options.Cropsanity.internal_name: options.Cropsanity.option_shuffled, + 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, @@ -628,7 +628,7 @@ class TestFriendsanityDatingRules(SVTestBase): } def test_earning_dating_heart_requires_dating(self): - self.collect_lots_of_money() + 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) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 4babbca57615..344845bf2700 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -175,7 +175,12 @@ def run_default_tests(self) -> bool: def collect_lots_of_money(self): self.multiworld.state.collect(self.world.create_item("Shipping Bin"), event=False) - for i in range(30): + for i in range(100): + self.multiworld.state.collect(self.world.create_item("Stardrop"), event=False) + + def collect_all_the_money(self): + self.multiworld.state.collect(self.world.create_item("Shipping Bin"), event=False) + for i in range(1000): self.multiworld.state.collect(self.world.create_item("Stardrop"), event=False) From 1bc17ddf657f296d3824079f83ceedcc0a4a8fc1 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 13 Nov 2023 23:40:04 -0500 Subject: [PATCH 175/482] - slight improvement to performance of And and Or # Conflicts: # generate.prof # worlds/stardew_valley/logic/cached_logic.py # worlds/stardew_valley/logic/fishing_logic.py # worlds/stardew_valley/logic/logic.py # worlds/stardew_valley/logic/mine_logic.py # worlds/stardew_valley/logic/monster_logic.py # worlds/stardew_valley/logic/region_logic.py # worlds/stardew_valley/logic/relationship_logic.py # worlds/stardew_valley/logic/season_logic.py # worlds/stardew_valley/logic/shipping_logic.py # worlds/stardew_valley/rules.py # worlds/stardew_valley/stardew_rule.py --- worlds/stardew_valley/logic/action_logic.py | 2 +- worlds/stardew_valley/logic/cached_logic.py | 2 +- worlds/stardew_valley/logic/combat_logic.py | 8 +-- worlds/stardew_valley/logic/cooking_logic.py | 8 +-- worlds/stardew_valley/logic/crafting_logic.py | 9 +-- worlds/stardew_valley/logic/fishing_logic.py | 3 +- worlds/stardew_valley/logic/has_logic.py | 4 +- worlds/stardew_valley/logic/logic.py | 26 +++---- worlds/stardew_valley/logic/mine_logic.py | 4 +- worlds/stardew_valley/logic/monster_logic.py | 4 +- worlds/stardew_valley/logic/museum_logic.py | 4 +- worlds/stardew_valley/logic/received_logic.py | 4 +- worlds/stardew_valley/logic/region_logic.py | 4 +- .../logic/relationship_logic.py | 15 ++--- worlds/stardew_valley/logic/season_logic.py | 4 +- worlds/stardew_valley/logic/shipping_logic.py | 2 +- worlds/stardew_valley/logic/skill_logic.py | 2 +- .../mods/logic/deepwoods_logic.py | 2 +- worlds/stardew_valley/mods/logic/sve_logic.py | 2 +- worlds/stardew_valley/rules.py | 8 +-- worlds/stardew_valley/stardew_rule.py | 67 ++++--------------- worlds/stardew_valley/test/__init__.py | 1 + .../performance/TestOptionsPerformance.py | 66 ------------------ 23 files changed, 68 insertions(+), 183 deletions(-) delete mode 100644 worlds/stardew_valley/test/performance/TestOptionsPerformance.py diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 2b48dda10aac..2b2921b324c5 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -38,5 +38,5 @@ def can_open_geode(self, geode: str) -> StardewRule: blacksmith_access = self.region.can_reach(Region.blacksmith) geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] if geode == Generic.any: - return blacksmith_access & Or([self.has(geode_type) for geode_type in geodes]) + return blacksmith_access & Or(*(self.has(geode_type) for geode_type in geodes)) return blacksmith_access & self.has(geode) diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py index df0f8a8bcb13..aa963d2ce67b 100644 --- a/worlds/stardew_valley/logic/cached_logic.py +++ b/worlds/stardew_valley/logic/cached_logic.py @@ -61,7 +61,7 @@ def get_cache_key(self, method: Callable, *parameters) -> Hashable: def cache_rule(func): @functools.wraps(func) - def wrapper(self, *args, **kwargs): + def wrapper(self, *args): key = self.get_cache_key(func, *args, **kwargs) return self.cached_rules.try_get_rule(key, func, self, *args, **kwargs) return wrapper diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index a9f764a08815..000e9e322d5b 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -47,16 +47,16 @@ def has_any_weapon(self) -> StardewRule: @cached_property def has_decent_weapon(self) -> StardewRule: - return Or(self.received(weapon, 2) for weapon in valid_weapons) + return Or(*(self.received(weapon, 2) for weapon in valid_weapons)) @cached_property def has_good_weapon(self) -> StardewRule: - return Or(self.received(weapon, 3) for weapon in valid_weapons) + return Or(*(self.received(weapon, 3) for weapon in valid_weapons)) @cached_property def has_great_weapon(self) -> StardewRule: - return Or(self.received(weapon, 4) for weapon in valid_weapons) + return Or(*(self.received(weapon, 4) for weapon in valid_weapons)) @cached_property def has_galaxy_weapon(self) -> StardewRule: - return Or(self.received(weapon, 5) for weapon in valid_weapons) + return Or(*(self.received(weapon, 5) for weapon in valid_weapons)) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index e9f022648807..91424ef3e162 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -71,10 +71,8 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: return cook_rule recipe_rule = self.knows_recipe(recipe.source, recipe.meal) - ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) - number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) - time_rule = self.time.has_lived_months(number_ingredients) - return cook_rule & recipe_rule & ingredients_rule & time_rule + ingredients_rule = And(*(self.has(ingredient) for ingredient in recipe.ingredients)) + return cook_rule & recipe_rule & ingredients_rule # Should be cached def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: @@ -130,4 +128,4 @@ def can_cook_everything(self) -> StardewRule: continue all_recipes_names.append(location.name[len(cooksanity_prefix):]) all_recipes = [all_cooking_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] - return And([self.can_cook(recipe) for recipe in all_recipes]) + return And(*(self.can_cook(recipe) for recipe in all_recipes)) diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 76258b760d6e..a02c3e87b251 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -59,15 +59,12 @@ def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: C @cache_self1 def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: - craft_rule = True_() if recipe is None: - return craft_rule + return True_() learn_rule = self.knows_recipe(recipe) - ingredients_rule = And([self.has(ingredient) for ingredient in recipe.ingredients]) - number_ingredients = sum(recipe.ingredients[ingredient] for ingredient in recipe.ingredients) // 10 - time_rule = self.time.has_lived_months(number_ingredients) - return craft_rule & learn_rule & ingredients_rule & time_rule + ingredients_rule = And(*(self.has(ingredient) for ingredient in recipe.ingredients)) + return learn_rule & ingredients_rule @cache_self1 def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index a47bfcccff40..0efe8f4caf45 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -72,5 +72,4 @@ def can_start_extended_family_quest(self) -> StardewRule: return False_() if self.special_order_locations != SpecialOrderLocations.option_board_qi: return False_() - return self.region.can_reach(Region.qi_walnut_room) & And( - *(self.can_catch_fish(fish) for fish in legendary_fish)) + return self.region.can_reach(Region.qi_walnut_room) & And(*(self.can_catch_fish(fish) for fish in legendary_fish)) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 27e9902802ae..743e0432964a 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -26,9 +26,9 @@ def has(self, items: Union[str, Tuple[str]], count: Optional[int] = None) -> Sta return True_() if count is None or count == len(items): - return And(self.has(item) for item in items) + return And(*(self.has(item) for item in items)) if count == 1: - return Or(self.has(item) for item in items) + return Or(*(self.has(item) for item in items)) return Count(count, (self.has(item) for item in items)) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index afd4e033a763..0104251c3cdb 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -301,7 +301,7 @@ def __post_init__(self): Fertilizer.deluxe: False_(), Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150)), Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), - Fish.any: Or([self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)]), + Fish.any: Or(*(self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value))), Fish.crab: self.skill.can_crab_pot_at(Region.beach), Fish.crayfish: self.skill.can_crab_pot_at(Region.town), Fish.lobster: self.skill.can_crab_pot_at(Region.beach), @@ -542,7 +542,7 @@ def can_catch_every_fish(self) -> StardewRule: if exclude_extended_family and fish in extended_family: continue rules.append(self.fishing.can_catch_fish(fish)) - return And(rules) + return And(*rules) def can_smelt(self, item: str) -> StardewRule: return self.has(Machine.furnace) & self.has(item) @@ -595,7 +595,7 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: continue rules.append(self.monster.can_kill_any(all_monsters_by_category[category])) - return And(rules) + return And(*rules) def can_win_egg_hunt(self) -> StardewRule: number_of_movement_buffs = self.options.movement_buff_number @@ -614,9 +614,9 @@ def can_succeed_luau_soup(self) -> StardewRule: Forageable.cactus_fruit, Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, Vegetable.hops, Vegetable.wheat] keg_rules = [self.artisan.can_keg(kegable) for kegable in eligible_kegables] - aged_rule = self.has(Machine.cask) & Or(keg_rules) + aged_rule = self.has(Machine.cask) & Or(*keg_rules) # There are a few other valid items but I don't feel like coding them all - return Or(fish_rule) | Or(aged_rule) + return Or(*fish_rule) | aged_rule def can_succeed_grange_display(self) -> StardewRule: if self.options.festival_locations != FestivalLocations.option_hard: @@ -629,10 +629,10 @@ def can_succeed_grange_display(self) -> StardewRule: mineral_rule = self.action.can_open_geode(Generic.any) # More than half the minerals are good enough good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, Fruit.pomegranate, Fruit.strawberry, Fruit.melon, Fruit.rhubarb, Fruit.pineapple, Fruit.ancient_fruit, Fruit.starfruit, ] - fruit_rule = Or([self.has(fruit) for fruit in good_fruits]) + fruit_rule = Or(*(self.has(fruit) for fruit in good_fruits)) good_vegetables = [Vegetable.amaranth, Vegetable.artichoke, Vegetable.beet, Vegetable.cauliflower, Forageable.fiddlehead_fern, Vegetable.kale, Vegetable.radish, Vegetable.taro_root, Vegetable.yam, Vegetable.red_cabbage, Vegetable.pumpkin] - vegetable_rule = Or([self.has(vegetable) for vegetable in good_vegetables]) + vegetable_rule = Or(*(self.has(vegetable) for vegetable in good_vegetables)) return animal_rule & artisan_rule & cooking_rule & fish_rule & \ forage_rule & fruit_rule & mineral_rule & vegetable_rule @@ -684,11 +684,11 @@ def has_any_animal(self) -> StardewRule: return self.has_any_coop_animal() | self.has_any_barn_animal() def has_any_coop_animal(self) -> StardewRule: - coop_rule = Or([self.has_animal(coop_animal) for coop_animal in coop_animals]) + coop_rule = Or(*(self.has_animal(coop_animal) for coop_animal in coop_animals)) return coop_rule def has_any_barn_animal(self) -> StardewRule: - barn_rule = Or([self.has_animal(barn_animal) for barn_animal in barn_animals]) + barn_rule = Or(*(self.has_animal(barn_animal) for barn_animal in barn_animals)) return barn_rule def has_island_trader(self) -> StardewRule: @@ -713,8 +713,8 @@ def has_walnut(self, number: int) -> StardewRule: self.region.can_reach(Region.volcano_secret_beach), self.region.can_reach(Region.volcano_floor_5), self.region.can_reach(Region.volcano_floor_10)] - reach_volcano = Or(reach_volcano_regions) - reach_all_volcano = And(reach_volcano_regions) + reach_volcano = Or(*reach_volcano_regions) + reach_all_volcano = And(*reach_volcano_regions) reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano] reach_caves = And(self.region.can_reach(Region.qi_walnut_room), self.region.can_reach(Region.dig_site), self.region.can_reach(Region.gourmand_frog_cave), @@ -729,7 +729,7 @@ def has_walnut(self, number: int) -> StardewRule: if number <= 15: return Count(3, reach_walnut_regions) if number <= 20: - return And(reach_walnut_regions) + return And(*reach_walnut_regions) if number <= 50: return reach_entire_island gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz) @@ -773,7 +773,7 @@ def has_all_rarecrows(self) -> StardewRule: rules = [] for rarecrow_number in range(1, 9): rules.append(self.received(f"Rarecrow #{rarecrow_number}")) - return And(rules) + return And(*rules) def has_abandoned_jojamart(self) -> StardewRule: return self.received(CommunityUpgrade.movie_theater, 1) diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 5b4d82cb0bbd..89a34779827d 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -81,7 +81,7 @@ def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: skill_tier = min(10, max(0, tier * 2)) rules.append(self.skill.has_level(Skill.combat, skill_tier)) rules.append(self.skill.has_level(Skill.mining, skill_tier)) - return And(rules) + return And(*rules) @cache_self1 def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: @@ -103,4 +103,4 @@ def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule skill_tier = min(10, max(0, tier * 2 + 6)) rules.extend({self.skill.has_level(Skill.combat, skill_tier), self.skill.has_level(Skill.mining, skill_tier)}) - return And(rules) + return And(*rules) diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 07c640b9868a..0d9db208d10b 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -39,9 +39,9 @@ def can_kill_max(self, monster: StardewMonster) -> StardewRule: # Should be cached def can_kill_any(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] - return Or(rules) + return Or(*rules) # Should be cached def can_kill_all(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.can_kill(monster, amount_tier) for monster in monsters] - return And(rules) + return And(*rules) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index d4e98771c95b..16a7bf5e91e7 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -40,7 +40,7 @@ def can_donate_museum_artifacts(self, number: int) -> StardewRule: @cache_self1 def can_find_museum_item(self, item: MuseumItem) -> StardewRule: region_rule = self.region.can_reach_all_except_one(item.locations) - geodes_rule = And([self.action.can_open_geode(geode) for geode in item.geodes]) + geodes_rule = And(*(self.action.can_open_geode(geode) for geode in item.geodes)) # monster_rule = self.can_farm_monster(item.monsters) # extra_rule = True_() pan_rule = False_() @@ -77,7 +77,7 @@ def can_complete_museum(self) -> StardewRule: for donation in all_museum_items: rules.append(self.can_find_museum_item(donation)) - return And(rules) & self.region.can_reach(Region.museum) + return And(*rules) & self.region.can_reach(Region.museum) def can_donate(self, item: str) -> StardewRule: return self.has(item) & self.region.can_reach(Region.museum) diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index f7d70c793756..9bb952c98991 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -24,9 +24,9 @@ def received(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = 1) return Received(items, self.player, count) if count is None: - return And(self.received(item) for item in items) + return And(*(self.received(item) for item in items)) if count == 1: - return Or(self.received(item) for item in items) + return Or(*(self.received(item) for item in items)) return TotalReceived(count, items, self.player) diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index be7a9ec0bc3b..72d6710a2066 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -16,11 +16,11 @@ def can_reach(self, region_name: str) -> StardewRule: @cache_self1 def can_reach_any(self, region_names: Tuple[str, ...]) -> StardewRule: - return Or(self.can_reach(spot) for spot in region_names) + return Or(*(self.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all(self, region_names: Tuple[str, ...]) -> StardewRule: - return And(self.can_reach(spot) for spot in region_names) + return And(*(self.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 23309f5818cc..6f693ed5fc07 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -1,17 +1,16 @@ import math -from typing import Iterable, Union +from typing import Union from Utils import cache_self1 from .building_logic import BuildingLogic -from .cached_logic import CachedLogic, cache_rule, profile_rule +from .cached_logic import CachedLogic, cache_rule from .gift_logic import GiftLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic from .time_logic import TimeLogic -from .. import options -from ..data.villagers_data import all_villagers_by_name, get_villagers_for_mods, Villager +from ..data.villagers_data import all_villagers_by_name, Villager from ..options import Friendsanity, FriendsanityHeartSize, Mods from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic @@ -71,7 +70,7 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule: return True_() baby_rules = [self.can_get_married(), self.buildings.has_house(2), self.has_hearts(Generic.bachelor, 12), self.has_children(number_children - 1)] - return And(baby_rules) + return And(*baby_rules) # Should be cached def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: @@ -87,14 +86,14 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: continue if npc == Generic.any or all_villagers_by_name[name].bachelor: possible_friends.append(self.has_hearts(name, hearts)) - return Or(possible_friends) + return Or(*possible_friends) if npc == Generic.all: mandatory_friends = [] for name in all_villagers_by_name: if not self.npc_is_in_current_slot(name): continue mandatory_friends.append(self.has_hearts(name, hearts)) - return And(mandatory_friends) + return And(*mandatory_friends) if npc.isnumeric(): possible_friends = [] for name in all_villagers_by_name: @@ -133,7 +132,7 @@ def can_meet(self, npc: str) -> StardewRule: elif npc == ModNPC.lance: rules.append(self.region.can_reach(Region.volcano_floor_10)) - return And(rules) + return And(*rules) def can_give_loved_gifts_to_everyone(self) -> StardewRule: rules = [] diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 3d7c287e65c5..4516df34123c 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -38,7 +38,7 @@ def has(self, season: str) -> StardewRule: def has_any(self, seasons: Iterable[str]): if not seasons: return True_() - return Or([self.has(season) for season in seasons]) + return Or(*(self.has(season) for season in seasons)) def has_any_not_winter(self): return self.has_any([Season.spring, Season.summer, Season.fall]) @@ -46,4 +46,4 @@ def has_any_not_winter(self): def has_all(self, seasons: Iterable[str]): if not seasons: return True_() - return And([self.has(season) for season in seasons]) + return And(*(self.has(season) for season in seasons)) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 296c4e078225..9e757a22310e 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -59,4 +59,4 @@ def can_ship_everything(self) -> StardewRule: if location.mod_name and location.mod_name not in mod_list: continue all_items_to_ship.append(location.name[len(shipsanity_prefix):]) - return self.buildings.has_building(Building.shipping_bin) & And([self.has(item) for item in all_items_to_ship]) + return self.buildings.has_building(Building.shipping_bin) & And(*(self.has(item) for item in all_items_to_ship)) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 7c6197a47222..79db857a9d34 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -127,7 +127,7 @@ def can_get_farming_xp(self) -> StardewRule: crop_rules = [] for crop in all_crops: crop_rules.append(self.crop.can_grow(crop)) - return Or(crop_rules) + return Or(*crop_rules) @cached_property def can_get_foraging_xp(self) -> StardewRule: diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index 264c28069b3c..19ed65b00adf 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -49,7 +49,7 @@ def can_reach_woods_depth(self, depth: int) -> StardewRule: if self.skill_option == SkillProgression.option_progressive: combat_tier = min(10, max(0, tier + 5)) rules.append(self.skill.has_level(Skill.combat, combat_tier)) - return And(rules) + return And(*rules) def has_woods_rune_to_depth(self, floor: int) -> StardewRule: if self.elevator_option == ElevatorProgression.option_vanilla: diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 88da42519b25..797a71e3b692 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -74,5 +74,5 @@ def initialize_rules(self): def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", "Nexus: Outpost Runes"] - return Or([self.received(rune) for rune in rune_list]) + return Or(*(self.received(rune) for rune in rune_list)) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 1e675eecfa77..4d653d5d500e 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -579,13 +579,13 @@ def set_museum_milestone_rule(logic: StardewLogic, multiworld: MultiWorld, museu elif milestone_name.endswith(artifacts_suffix): rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_museum_artifacts, logic.museum.can_find_museum_artifacts) elif milestone_name == "Dwarf Scrolls": - rule = And([logic.museum.can_find_museum_item(item) for item in dwarf_scrolls]) & logic.received(metal_detector, 4) + rule = And(*(logic.museum.can_find_museum_item(item) for item in dwarf_scrolls)) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Front": - rule = And([logic.museum.can_find_museum_item(item) for item in skeleton_front]) & logic.received(metal_detector, 4) + rule = And(*(logic.museum.can_find_museum_item(item) for item in skeleton_front)) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Middle": - rule = And([logic.museum.can_find_museum_item(item) for item in skeleton_middle]) & logic.received(metal_detector, 4) + rule = And(*(logic.museum.can_find_museum_item(item) for item in skeleton_middle)) & logic.received(metal_detector, 4) elif milestone_name == "Skeleton Back": - rule = And([logic.museum.can_find_museum_item(item) for item in skeleton_back]) & logic.received(metal_detector, 4) + rule = And(*(logic.museum.can_find_museum_item(item) for item in skeleton_back)) & logic.received(metal_detector, 4) elif milestone_name == "Ancient Seed": rule = logic.museum.can_find_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4) if rule is None: diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 9bbd9f3e0698..10da27a443ff 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Iterable, Dict, List, Union, FrozenSet, Set +from typing import Iterable, Dict, List, Union, FrozenSet from BaseClasses import CollectionState, ItemClassification from .items import item_table @@ -21,7 +21,7 @@ def __or__(self, other) -> StardewRule: def __and__(self, other) -> StardewRule: if type(other) is And: - return And(other.rules.union({self})) + return And(*other.rules.union({self})) return And(self, other) @@ -90,29 +90,9 @@ class Or(StardewRule): rules: FrozenSet[StardewRule] _simplified: bool - def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): - rules_list: Set[StardewRule] - - if isinstance(rule, Iterable): - rules_list = {*rule} - else: - rules_list = {rule} - - if rules is not None: - rules_list.update(rules) - - assert rules_list, "Can't create a Or conditions without rules" - - if any(type(rule) is Or for rule in rules_list): - new_rules: Set[StardewRule] = set() - for rule in rules_list: - if type(rule) is Or: - new_rules.update(rule.rules) - else: - new_rules.add(rule) - rules_list = new_rules - - self.rules = frozenset(rules_list) + def __init__(self, *rules: StardewRule): + self.rules = frozenset(rules) + assert self.rules, "Can't create a Or conditions without rules" self._simplified = False def __call__(self, state: CollectionState) -> bool: @@ -128,9 +108,9 @@ def __or__(self, other): if other is false_: return self if type(other) is Or: - return Or(self.rules.union(other.rules)) + return Or(*self.rules.union(other.rules)) - return Or(self.rules.union({other})) + return Or(*self.rules.union({other})) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -165,33 +145,10 @@ class And(StardewRule): rules: FrozenSet[StardewRule] _simplified: bool - def __init__(self, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): - rules_list: Set[StardewRule] - - if isinstance(rule, Iterable): - rules_list = {*rule} - else: - rules_list = {rule} - - if rules is not None: - rules_list.update(rules) - - if not rules_list: - rules_list.add(true_) - elif any(type(rule) is And for rule in rules_list): - new_rules: Set[StardewRule] = set() - for rule in rules_list: - if type(rule) is And: - new_rules.update(rule.rules) - else: - new_rules.add(rule) - rules_list = new_rules - - self.rules = frozenset(rules_list) + def __init__(self, *rules: StardewRule): + self.rules = frozenset(rules) self._simplified = False - self.rules = frozenset(rules_list) - def __call__(self, state: CollectionState) -> bool: self.simplify() result = all(rule(state) for rule in self.rules) @@ -206,9 +163,9 @@ def __and__(self, other): if other is false_: return other if type(other) is And: - return And(self.rules.union(other.rules)) + return And(*self.rules.union(other.rules)) - return And(self.rules.union({other})) + return And(*self.rules.union({other})) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -379,7 +336,7 @@ def __call__(self, state: CollectionState) -> bool: return self.other_rules[self.item](state) def __repr__(self): - if not self.item in self.other_rules: + if self.item not in self.other_rules: return f"Has {self.item} -> {MISSING_ITEM}" return f"Has {self.item} -> {repr(self.other_rules[self.item])}" diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 344845bf2700..38231b585b91 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -155,6 +155,7 @@ def setUp(self) -> None: performance_tests_key = "performance" if performance_tests_key in os.environ: self.skip_performance_tests = not bool(os.environ[performance_tests_key]) + self.skip_performance_tests = False class SVTestBase(WorldTestBase, SVTestCase): diff --git a/worlds/stardew_valley/test/performance/TestOptionsPerformance.py b/worlds/stardew_valley/test/performance/TestOptionsPerformance.py deleted file mode 100644 index 9175b24aa9d2..000000000000 --- a/worlds/stardew_valley/test/performance/TestOptionsPerformance.py +++ /dev/null @@ -1,66 +0,0 @@ -import time - -from BaseClasses import get_seed -from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, \ - allsanity_options_with_mods, setup_multiworld, default_options - -number_generations = 5 - - -def performance_test_multiworld(tester, options, option_text): - number_players = len(options) - total_time = 0 - all_times = {} - for i in range(number_generations): - seed = get_seed() - time_before = time.time() - multiworld = setup_multiworld(options, seed) - time_after = time.time() - elapsed_time = time_after - time_before - total_time += elapsed_time - all_times[i] = elapsed_time - size = size_name(number_players) - average_time = total_time / number_generations - # Remove outliers - num_outliers = 0 - for world in all_times: - if all_times[world] > average_time * 4: - num_outliers += 1 - total_time -= all_times[world] - average_time = total_time / (number_generations - num_outliers) - print(f"{option_text}:") - print(f"\tGenerated {(number_generations - num_outliers)} {size} multiworlds in {total_time} seconds") - print(f"\tAverage time per world: {average_time} seconds") - return average_time - - -def size_name(number_players): - if number_players == 1: - return "solo" - elif number_players == 2: - return "duo" - elif number_players == 3: - return "trio" - return f"{number_players}-player" - - -class TestIndividualAllsanityOptions(SVTestCase): - - def test_solo(self): - if self.skip_performance_tests: - return - times = dict() - allsanity_options = allsanity_options_without_mods() - for option1 in allsanity_options: - for option2 in allsanity_options: - if option1 == option2: - continue - options_text = f"{option1}: {allsanity_options[option1]}, {option2}: {allsanity_options[option2]}" - with self.subTest(options_text): - multiworld_options = dict(minimal_locations_maximal_items()) - multiworld_options[option1] = allsanity_options[option1] - multiworld_options[option2] = allsanity_options[option2] - times[options_text] = performance_test_multiworld(self, [multiworld_options], options_text) - sorted_times = sorted(times, key=lambda x: times[x], reverse=True) - for options in sorted_times: - print(f"{options}: {times[options]}") From ef8f0018e9664807e3a065076999507cd0144a4f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 12:00:30 -0500 Subject: [PATCH 176/482] - Remove skip performance test override again - Initialize total progression items even if create_items is never called --- worlds/stardew_valley/__init__.py | 1 + worlds/stardew_valley/test/__init__.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index a5171fdfa270..ae058cd6c2e6 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -79,6 +79,7 @@ class StardewValleyWorld(World): def __init__(self, world: MultiWorld, player: int): super().__init__(world, player) self.filler_item_pool_names = [] + self.total_progression_items = 0 def generate_early(self): self.force_change_options_if_incompatible() diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 38231b585b91..344845bf2700 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -155,7 +155,6 @@ def setUp(self) -> None: performance_tests_key = "performance" if performance_tests_key in os.environ: self.skip_performance_tests = not bool(os.environ[performance_tests_key]) - self.skip_performance_tests = False class SVTestBase(WorldTestBase, SVTestCase): From 5d64cc8dcdc314d26314ab33dcaadb2fe218860b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 12:36:08 -0500 Subject: [PATCH 177/482] - Undid some changes in base classes because alttp can't handle them --- BaseClasses.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 080b28bef44b..b35b53b7904f 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -650,17 +650,16 @@ def __init__(self, parent: MultiWorld): self.collect(item, True) def update_reachable_regions(self, player: int): - new_connection: bool = True self.stale[player] = False - reachable_regions = self.reachable_regions[player] - blocked_connections = self.blocked_connections[player] + rrp = self.reachable_regions[player] + bc = self.blocked_connections[player] queue = deque(self.blocked_connections[player]) - start = self.multiworld.get_region("Menu", player) + start = self.multiworld.get_region('Menu', player) # init on first call - this can't be done on construction since the regions don't exist yet - if start not in reachable_regions: - reachable_regions.add(start) - blocked_connections.update(start.exits) + if start not in rrp: + rrp.add(start) + bc.update(start.exits) queue.extend(start.exits) # run BFS on all connections, and keep track of those blocked by missing items From f494c4aecfcab516470a91203f50246c020b577b Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 12:36:25 -0500 Subject: [PATCH 178/482] - Improved buildings logic and houses --- worlds/stardew_valley/logic/building_logic.py | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 762b57fbf53e..5e761318d447 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -40,24 +40,24 @@ def __init__(self, player: int, cached_rules: CachedRules, building_option: Buil def initialize_rules(self): self.building_rules.update({ # @formatter:off - Building.barn: self.money.can_spend_at(Region.carpenter, 6000) & self.has((Material.wood, Material.stone)), - Building.big_barn: self.money.can_spend_at(Region.carpenter, 12000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.barn), - Building.deluxe_barn: self.money.can_spend_at(Region.carpenter, 25000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_barn), - Building.coop: self.money.can_spend_at(Region.carpenter, 4000) & self.has((Material.wood, Material.stone)), - Building.big_coop: self.money.can_spend_at(Region.carpenter, 10000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.coop), - Building.deluxe_coop: self.money.can_spend_at(Region.carpenter, 20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_coop), - Building.fish_pond: self.money.can_spend_at(Region.carpenter, 5000) & self.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), - Building.mill: self.money.can_spend_at(Region.carpenter, 2500) & self.has((Material.stone, Material.wood, ArtisanGood.cloth)), - Building.shed: self.money.can_spend_at(Region.carpenter, 15000) & self.has(Material.wood), - Building.big_shed: self.money.can_spend_at(Region.carpenter, 20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.shed), - Building.silo: self.money.can_spend_at(Region.carpenter, 100) & self.has((Material.stone, Material.clay, MetalBar.copper)), - Building.slime_hutch: self.money.can_spend_at(Region.carpenter, 10000) & self.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), - Building.stable: self.money.can_spend_at(Region.carpenter, 10000) & self.has((Material.hardwood, MetalBar.iron)), - Building.well: self.money.can_spend_at(Region.carpenter, 1000) & self.has(Material.stone), - Building.shipping_bin: self.money.can_spend_at(Region.carpenter, 250) & self.has(Material.wood), - Building.kitchen: self.money.can_spend_at(Region.carpenter, 10000) & self.has(Material.wood) & self.has_house(0), - Building.kids_room: self.money.can_spend_at(Region.carpenter, 50000) & self.has(Material.hardwood) & self.has_house(1), - Building.cellar: self.money.can_spend_at(Region.carpenter, 100000) & self.has_house(2), + Building.barn: self.money.can_spend(6000) & self.has((Material.wood, Material.stone)), + Building.big_barn: self.money.can_spend(12000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.barn), + Building.deluxe_barn: self.money.can_spend(25000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_barn), + Building.coop: self.money.can_spend(4000) & self.has((Material.wood, Material.stone)), + Building.big_coop: self.money.can_spend(10000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.coop), + Building.deluxe_coop: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_coop), + Building.fish_pond: self.money.can_spend(5000) & self.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), + Building.mill: self.money.can_spend(2500) & self.has((Material.stone, Material.wood, ArtisanGood.cloth)), + Building.shed: self.money.can_spend(15000) & self.has(Material.wood), + Building.big_shed: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.shed), + Building.silo: self.money.can_spend(100) & self.has((Material.stone, Material.clay, MetalBar.copper)), + Building.slime_hutch: self.money.can_spend(10000) & self.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), + Building.stable: self.money.can_spend(10000) & self.has((Material.hardwood, MetalBar.iron)), + Building.well: self.money.can_spend(1000) & self.has(Material.stone), + Building.shipping_bin: self.money.can_spend(250) & self.has(Material.wood), + Building.kitchen: self.money.can_spend(10000) & self.has(Material.wood) & self.has_house(0), + Building.kids_room: self.money.can_spend(50000) & self.has(Material.hardwood) & self.has_house(1), + Building.cellar: self.money.can_spend(100000) & self.has_house(2), # @formatter:on }) @@ -89,14 +89,15 @@ def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level > 3: return False_() + carpenter_rule = self.received(Event.can_construct_buildings) if self.building_option & BuildingProgression.option_progressive: - return self.received(f"Progressive House", upgrade_level) & self.region.can_reach(Region.carpenter) + return carpenter_rule & self.received(f"Progressive House", upgrade_level) if upgrade_level == 1: - return Has(Building.kitchen, self.building_rules) + return carpenter_rule & Has(Building.kitchen, self.building_rules) if upgrade_level == 2: - return Has(Building.kids_room, self.building_rules) + return carpenter_rule & Has(Building.kids_room, self.building_rules) # if upgrade_level == 3: - return Has(Building.cellar, self.building_rules) + return carpenter_rule & Has(Building.cellar, self.building_rules) From 87a32b8ea17494ff9443e3d6bf868ca0ed9363d0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 12:36:39 -0500 Subject: [PATCH 179/482] - Updated check counts --- worlds/stardew_valley/test/TestGeneration.py | 16 ++++++++++++++-- worlds/stardew_valley/test/__init__.py | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 9190640aa35e..d55e3a4a2445 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -3,7 +3,7 @@ from BaseClasses import ItemClassification, MultiWorld, Item from . import setup_solo_multiworld, SVTestBase, get_minsanity_options, allsanity_options_without_mods, \ - allsanity_options_with_mods, minimal_locations_maximal_items, SVTestCase + allsanity_options_with_mods, minimal_locations_maximal_items, SVTestCase, default_options from .. import locations, items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name from ..items import Group, item_table @@ -359,6 +359,18 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tExpected: {expected_locations}" f"\n\t\tActual: {number_locations}") + def test_default_settings_has_exactly_locations(self): + expected_locations = 420 + multiworld = setup_solo_multiworld(default_options()) + real_locations = get_real_locations(self, multiworld) + number_locations = len(real_locations) + print(f"Stardew Valley - Default options locations: {number_locations}") + if number_locations != expected_locations: + print(f"\tNew locations detected!" + f"\n\tPlease update test_default_settings_has_exactly_locations" + f"\n\t\tExpected: {expected_locations}" + f"\n\t\tActual: {number_locations}") + def test_allsanity_without_mods_has_at_least_locations(self): expected_locations = 1952 allsanity_options = allsanity_options_without_mods() @@ -374,7 +386,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2425 + expected_locations = 2652 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 344845bf2700..36a70fdac2b8 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -64,7 +64,7 @@ def minimal_locations_maximal_items(): BundleRandomization.internal_name: BundleRandomization.option_vanilla, BundlePrice.internal_name: BundlePrice.option_very_cheap, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, - Cropsanity.internal_name: Cropsanity.option_enabled, + Cropsanity.internal_name: Cropsanity.option_disabled, BackpackProgression.internal_name: BackpackProgression.option_vanilla, ToolProgression.internal_name: ToolProgression.option_vanilla, SkillProgression.internal_name: SkillProgression.option_vanilla, From 91b2ac6b75288cd8223319fae7d980637806e9f9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 22:59:43 -0500 Subject: [PATCH 180/482] - Made the railroad boulder into an AP item --- worlds/stardew_valley/data/items.csv | 1 + worlds/stardew_valley/items.py | 1 + worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/test/TestLogic.py | 3 ++- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index c7dbf8b25fdd..aa5365d09e41 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -444,6 +444,7 @@ id,name,classification,groups,mod_name 466,Wilderness Farm,progression,"FARM_TYPE", 467,Four Corners Farm,progression,"FARM_TYPE", 468,Beach Farm,progression,"FARM_TYPE", +469,Railroad Boulder Removed,progression,, 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, 4003,Frozen,trap,TRAP, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index a333df998f44..4b2362f85132 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -192,6 +192,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_skills(item_factory, options, items) create_wizard_buildings(item_factory, options, items) create_carpenter_buildings(item_factory, options, items) + items.append(item_factory("Railroad Boulder Removed")) items.append(item_factory("Beach Bridge")) items.append(item_factory("Dark Talisman")) create_tv_channels(item_factory, items) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 0104251c3cdb..504f0827703f 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -159,7 +159,7 @@ def __post_init__(self): self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) - self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in all_fish}) + self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) for recipe in all_cooking_recipes: diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 4d653d5d500e..e696613971a9 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -235,7 +235,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S set_adventure_guild_entrance_rules(logic, multiworld, player, world_options) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), - logic.time.has_lived_months(2)) + logic.received("Railroad Boulder Removed")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 701d9600b3a5..9497a6ded48b 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -77,7 +77,8 @@ def test_given_fish_rule_then_can_be_resolved(self): with self.subTest(msg=fish): rule = logic.fish_rules[fish] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve fish rule for {fish} {rule}") + rule_result = rule(multi_world.state) + self.assertTrue(rule == False_() or rule_result, f"Could not resolve fish rule for {fish} {rule}") def test_given_museum_rule_then_can_be_resolved(self): for donation in logic.museum_rules.keys(): From b7c9c0ed70c7645613122438d67c612943c3e933 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 23:29:15 -0500 Subject: [PATCH 181/482] - Add Dark Talisman quest event --- worlds/stardew_valley/__init__.py | 5 +++++ worlds/stardew_valley/items.py | 1 + worlds/stardew_valley/rules.py | 5 ++--- worlds/stardew_valley/strings/ap_names/event_names.py | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index ae058cd6c2e6..b452d85c5a5b 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -143,6 +143,7 @@ def create_items(self): self.setup_early_items() self.setup_construction_events() + self.setup_quest_events() self.setup_victory() def precollect_farm_type(self): @@ -193,6 +194,10 @@ def setup_construction_events(self): can_construct_buildings = LocationData(None, "Carpenter Shop", Event.can_construct_buildings) self.create_event_location(can_construct_buildings, True_(), Event.can_construct_buildings) + def setup_quest_events(self): + start_dark_talisman_quest = LocationData(None, "Railroad", Event.start_dark_talisman_quest) + self.create_event_location(start_dark_talisman_quest, self.logic.wallet.has_rusty_key, Event.start_dark_talisman_quest) + def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 4b2362f85132..b31f53be7728 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -130,6 +130,7 @@ def load_item_csv(): events = [ ItemData(None, Event.victory, ItemClassification.progression), ItemData(None, Event.can_construct_buildings, ItemClassification.progression), + ItemData(None, Event.start_dark_talisman_quest, ItemClassification.progression), ] all_items: List[ItemData] = load_item_csv() + events diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index e696613971a9..48323ca704aa 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -4,7 +4,7 @@ from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules from .strings.craftable_names import Bomb -from . import locations +from . import locations, Event from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals, \ @@ -241,8 +241,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), - ((logic.wallet.has_rusty_key & logic.region.can_reach(Region.railroad) & - logic.relationship.can_meet(NPC.krobus) | logic.mod.magic.can_blink()))) + (logic.received(Event.start_dark_talisman_quest) & logic.relationship.can_meet(NPC.krobus)) | logic.mod.magic.can_blink()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), logic.received("Club Card")) diff --git a/worlds/stardew_valley/strings/ap_names/event_names.py b/worlds/stardew_valley/strings/ap_names/event_names.py index a5dd773f551f..2d18ba5bee11 100644 --- a/worlds/stardew_valley/strings/ap_names/event_names.py +++ b/worlds/stardew_valley/strings/ap_names/event_names.py @@ -1,3 +1,4 @@ class Event: victory = "Victory" can_construct_buildings = "Can Construct Buildings" + start_dark_talisman_quest = "Start Dark Talisman Quest" From 777cd8cf436d80cf5b0f3d62d3fdab6d65b6c70f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 23:37:42 -0500 Subject: [PATCH 182/482] - Fixed circular dependency --- worlds/stardew_valley/rules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 48323ca704aa..bdcd0d3a29b9 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -4,7 +4,7 @@ from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules from .strings.craftable_names import Bomb -from . import locations, Event +from . import locations from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals, \ @@ -18,6 +18,7 @@ from .options import ToolProgression, BuildingProgression, ExcludeGingerIsland, SpecialOrderLocations, Museumsanity, BackpackProgression, Shipsanity, \ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And +from .strings.ap_names.event_names import Event from .strings.ap_names.transport_names import Transportation from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building From 0ffa9f8b12d7d5e9724d6898c93298db68720366 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 17:48:14 -0500 Subject: [PATCH 183/482] delete dead code --- worlds/stardew_valley/__init__.py | 1 - worlds/stardew_valley/logic/ability_logic.py | 7 +- worlds/stardew_valley/logic/artisan_logic.py | 3 - worlds/stardew_valley/logic/cached_logic.py | 106 +----------------- worlds/stardew_valley/logic/farming_logic.py | 6 +- worlds/stardew_valley/logic/pet_logic.py | 5 +- .../logic/relationship_logic.py | 2 +- 7 files changed, 8 insertions(+), 122 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index b452d85c5a5b..c533d9162ed7 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -9,7 +9,6 @@ from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData from .logic.bundle_logic import BundleLogic -from .logic.cached_logic import function_total_times, function_call_numbers from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \ diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index e2403a126148..ac5a2d1241b7 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -1,12 +1,11 @@ -from .cached_logic import profile_rule from .mine_logic import MineLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .skill_logic import SkillLogic from .tool_logic import ToolLogic -from ..options import NumberOfMovementBuffs, NumberOfLuckBuffs from ..mods.logic.magic_logic import MagicLogic from ..mods.logic.skills_logic import ModSkillLogic +from ..options import NumberOfMovementBuffs, NumberOfLuckBuffs from ..stardew_rule import StardewRule from ..strings.ap_names.buff_names import Buff from ..strings.region_names import Region @@ -26,8 +25,8 @@ class AbilityLogic: magic: MagicLogic mod_skill: ModSkillLogic - def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogic, region: RegionLogic, tool: ToolLogic, - skill: SkillLogic, mine: MineLogic): + def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogic, + region: RegionLogic, tool: ToolLogic, skill: SkillLogic, mine: MineLogic): self.player = player self.movement_buff_option = movement_buff_option self.luck_buff_option = luck_buff_option diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 32821990a020..e7e63ba21263 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -1,6 +1,3 @@ -from typing import Union - -from .cached_logic import profile_rule from .has_logic import HasLogic from .time_logic import TimeLogic from ..stardew_rule import StardewRule diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py index aa963d2ce67b..eca87c06be42 100644 --- a/worlds/stardew_valley/logic/cached_logic.py +++ b/worlds/stardew_valley/logic/cached_logic.py @@ -1,14 +1,7 @@ -import functools -import random -import time -from typing import Dict, Callable, Hashable, Iterable +from typing import Dict, Hashable from ..stardew_rule import StardewRule -rule_calls = 0 -rule_creations = 0 -time_creating_rules = 0 - class CachedRules: cached_rules: Dict[Hashable, StardewRule] @@ -16,33 +9,6 @@ class CachedRules: def __init__(self): self.cached_rules = dict() - def try_get_rule(self, key: str, create_rule, *args, **kwargs) -> StardewRule: - if key not in self.cached_rules: - self.cached_rules[key] = create_rule(*args, **kwargs) - return self.cached_rules[key] - - def try_get_rule_without_cache(self, key: Hashable, create_rule: Callable[[], StardewRule]) -> StardewRule: - return create_rule() - - def try_get_rule_with_stats(self, key: Hashable, create_rule: Callable[[], StardewRule]) -> StardewRule: - global rule_calls, rule_creations, time_creating_rules - rule_calls += 1 - if key not in self.cached_rules: - rule_creations += 1 - time_before = time.time() - self.cached_rules[key] = create_rule() - time_after = time.time() - time_creating_rules += (time_after - time_before) - if rule_calls % 100000 == 0: - cached_calls = rule_calls - rule_creations - percent_cached_calls = round((cached_calls / rule_calls) * 100) - percent_real_calls = 100 - percent_cached_calls - time_saved = (time_creating_rules / percent_real_calls) * 100 - print( - f"Rule Creations/Calls: {rule_creations}/{rule_calls} ({cached_calls} cached calls [{percent_cached_calls}%] saving {time_saved}s" - f" for a total of {time_creating_rules}s creating rules)") - return self.cached_rules[key] - class CachedLogic: player: int @@ -52,73 +18,3 @@ def __init__(self, player: int, cached_rules: CachedRules): self.player = player self.cached_rules = cached_rules self.name = type(self).__name__ - - def get_cache_key(self, method: Callable, *parameters) -> Hashable: - assert not any(isinstance(p, Iterable) for p in parameters) - return self.name, method.__name__, str(parameters) - # return f"{type(self).__name__} {method.__name__} {' '.join(map(str, parameters))}" - - -def cache_rule(func): - @functools.wraps(func) - def wrapper(self, *args): - key = self.get_cache_key(func, *args, **kwargs) - return self.cached_rules.try_get_rule(key, func, self, *args, **kwargs) - return wrapper - - -time_getting_keys = 0 -time_getting_rules = 0 - - -def cache_rule_with_profiling(func): - @functools.wraps(func) - def wrapper(self, *args, **kwargs): - global time_getting_keys, time_getting_rules - time_before_key = time.time() - key = self.get_cache_key(func, *args) - time_between = time.time() - rule = self.cached_rules.try_get_rule(key, lambda: func(self, *args, **kwargs)) - time_after_rule = time.time() - time_getting_keys += (time_between - time_before_key) - time_getting_rules += (time_after_rule - time_between) - if random.random() < 0.0001: - print(f"Time Getting Keys: {time_getting_keys} seconds") - print(f"Time Getting Rules: {time_getting_rules} seconds") - return rule - - return wrapper - - -function_call_numbers = dict() -function_total_times = dict() - - -def profile_rule(func): - @functools.wraps(func) - def wrapper(self, *args, **kwargs): - key = f"{self.__class__.__name__} {func.__name__}" - key_params = f"{self.__class__.__name__} {func.__name__} {args}" - - if key not in function_call_numbers: - function_call_numbers[key] = 0 - if key_params not in function_call_numbers: - function_call_numbers[key_params] = 0 - if key not in function_total_times: - function_total_times[key] = 0 - if key_params not in function_total_times: - function_total_times[key_params] = 0 - - time_before = time.time() - result = func(self, *args, **kwargs) - time_after = time.time() - time_used = time_after - time_before - - function_call_numbers[key] += 1 - function_call_numbers[key_params] += 1 - function_total_times[key] += time_used - function_total_times[key_params] += time_used - - return result - - return wrapper diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 114b49902754..83078a31682c 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -1,7 +1,6 @@ -from .cached_logic import profile_rule from .has_logic import HasLogic -from ..stardew_rule import StardewRule, True_ from .skill_logic import SkillLogic +from ..stardew_rule import StardewRule, True_ from ..strings.fertilizer_names import Fertilizer @@ -33,9 +32,8 @@ def can_grow_crop_quality(self, quality: int) -> StardewRule: self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) if quality == 2: return self.skill.has_farming_level(10) | ( - self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( + self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( self.has_fertilizer(3) & self.skill.has_farming_level(2)) if quality >= 3: return self.has_fertilizer(3) & self.skill.has_farming_level(4) - diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index bb2a1b17b741..413dbe07827d 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -1,13 +1,11 @@ import math - from typing import Union -from .cached_logic import CachedLogic, CachedRules, profile_rule +from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic from .tool_logic import ToolLogic -from .. import options from ..data.villagers_data import Villager from ..options import Friendsanity, FriendsanityHeartSize from ..stardew_rule import StardewRule, True_ @@ -61,4 +59,3 @@ def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): return f"{npc} <3" return self.heart(npc.name) - diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 6f693ed5fc07..bdf6e87bffd7 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -3,7 +3,7 @@ from Utils import cache_self1 from .building_logic import BuildingLogic -from .cached_logic import CachedLogic, cache_rule +from .cached_logic import CachedLogic from .gift_logic import GiftLogic from .has_logic import HasLogic, CachedRules from .received_logic import ReceivedLogic From 207c11e651304b3d46414f36794a03fb2f01dce2 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 18:12:56 -0500 Subject: [PATCH 184/482] delete dead code --- worlds/stardew_valley/logic/action_logic.py | 10 ++-- worlds/stardew_valley/logic/building_logic.py | 10 ++-- worlds/stardew_valley/logic/bundle_logic.py | 8 ++- worlds/stardew_valley/logic/cached_logic.py | 20 ------- worlds/stardew_valley/logic/combat_logic.py | 7 ++- worlds/stardew_valley/logic/cooking_logic.py | 13 ++--- worlds/stardew_valley/logic/crafting_logic.py | 14 ++--- worlds/stardew_valley/logic/crop_logic.py | 11 ++-- worlds/stardew_valley/logic/fishing_logic.py | 10 ++-- worlds/stardew_valley/logic/gift_logic.py | 12 ++--- worlds/stardew_valley/logic/has_logic.py | 7 ++- worlds/stardew_valley/logic/logic.py | 53 +++++++++---------- worlds/stardew_valley/logic/mine_logic.py | 13 ++--- worlds/stardew_valley/logic/money_logic.py | 11 ++-- worlds/stardew_valley/logic/monster_logic.py | 8 ++- worlds/stardew_valley/logic/museum_logic.py | 11 ++-- worlds/stardew_valley/logic/pet_logic.py | 7 ++- worlds/stardew_valley/logic/received_logic.py | 7 ++- worlds/stardew_valley/logic/region_logic.py | 7 ++- .../logic/relationship_logic.py | 9 ++-- worlds/stardew_valley/logic/season_logic.py | 8 ++- worlds/stardew_valley/logic/shipping_logic.py | 10 ++-- worlds/stardew_valley/logic/skill_logic.py | 13 ++--- worlds/stardew_valley/logic/time_logic.py | 7 ++- worlds/stardew_valley/logic/tool_logic.py | 12 ++--- 25 files changed, 116 insertions(+), 182 deletions(-) delete mode 100644 worlds/stardew_valley/logic/cached_logic.py diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 2b2921b324c5..4ffc8ebed187 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,6 +1,5 @@ from Utils import cache_self1 -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..stardew_rule import StardewRule, True_, Or @@ -9,14 +8,13 @@ from ..strings.region_names import Region -class ActionLogic(CachedLogic): +class ActionLogic: received: ReceivedLogic has: HasLogic region: RegionLogic - def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, has: HasLogic, - region: RegionLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic): + self.player = player self.received = received self.has = has self.region = region diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 5e761318d447..7d04c45002b3 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,8 +1,7 @@ from typing import Dict from Utils import cache_self1 -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -17,7 +16,7 @@ from ..strings.region_names import Region -class BuildingLogic(CachedLogic): +class BuildingLogic: player: int building_option: BuildingProgression received: ReceivedLogic @@ -26,9 +25,8 @@ class BuildingLogic(CachedLogic): money: MoneyLogic building_rules: Dict[str, StardewRule] - def __init__(self, player: int, cached_rules: CachedRules, building_option: BuildingProgression, - received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + self.player = player self.player = player self.building_option = building_option self.received = received diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index ad4c4a9e0cdc..74d98cedc6f7 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,7 +1,6 @@ from functools import cached_property from typing import Tuple -from .cached_logic import CachedLogic, CachedRules from .farming_logic import FarmingLogic from .has_logic import HasLogic from .money_logic import MoneyLogic @@ -11,15 +10,14 @@ from ..strings.region_names import Region -class BundleLogic(CachedLogic): +class BundleLogic: has: HasLogic region: RegionLogic money: MoneyLogic farming: FarmingLogic - def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic, region: RegionLogic, money: MoneyLogic, - farming: FarmingLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, has: HasLogic, region: RegionLogic, money: MoneyLogic, farming: FarmingLogic): + self.player = player self.has = has self.region = region self.money = money diff --git a/worlds/stardew_valley/logic/cached_logic.py b/worlds/stardew_valley/logic/cached_logic.py deleted file mode 100644 index eca87c06be42..000000000000 --- a/worlds/stardew_valley/logic/cached_logic.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Dict, Hashable - -from ..stardew_rule import StardewRule - - -class CachedRules: - cached_rules: Dict[Hashable, StardewRule] - - def __init__(self): - self.cached_rules = dict() - - -class CachedLogic: - player: int - cached_rules: CachedRules - - def __init__(self, player: int, cached_rules: CachedRules): - self.player = player - self.cached_rules = cached_rules - self.name = type(self).__name__ diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 000e9e322d5b..e053d1c62d37 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,7 +1,6 @@ from functools import cached_property from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from ..mods.logic.magic_logic import MagicLogic @@ -12,13 +11,13 @@ valid_weapons = (APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger) -class CombatLogic(CachedLogic): +class CombatLogic: received: ReceivedLogic region: RegionLogic magic: MagicLogic - def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, region: RegionLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, received: ReceivedLogic, region: RegionLogic): + self.player = player self.region = region self.received = received diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 91424ef3e162..3a98170506f8 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -3,8 +3,7 @@ from Utils import cache_self1 from .action_logic import ActionLogic from .building_logic import BuildingLogic -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -25,7 +24,7 @@ from ..strings.tv_channel_names import Channel -class CookingLogic(CachedLogic): +class CookingLogic: chefsanity_option: Chefsanity exclude_ginger_island: ExcludeGingerIsland mods: Mods @@ -40,12 +39,10 @@ class CookingLogic(CachedLogic): relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, cached_rules: CachedRules, chefsanity_option: Chefsanity, - exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogic, - has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, - action: ActionLogic, buildings: BuildingLogic, + def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogic, + has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): - super().__init__(player, cached_rules) + self.player = player self.chefsanity_option = chefsanity_option self.exclude_ginger_island = exclude_ginger_island self.mods = mods diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index a02c3e87b251..a9c28ca6f507 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,7 +1,6 @@ from functools import cached_property from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic @@ -21,7 +20,7 @@ from ..strings.region_names import Region -class CraftingLogic(CachedLogic): +class CraftingLogic: craftsanity_option: Craftsanity exclude_ginger_island: ExcludeGingerIsland mods: Mods @@ -36,13 +35,10 @@ class CraftingLogic(CachedLogic): skill: SkillLogic special_orders: SpecialOrderLogic - def __init__(self, player: int, cached_rules: CachedRules, craftsanity_option: Craftsanity, - exclude_ginger_island: ExcludeGingerIsland, mods: Mods, festivals_option: FestivalLocations, - special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, - region: RegionLogic, time: TimeLogic, - money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, - special_orders: SpecialOrderLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, craftsanity_option: Craftsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, + festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): + self.player = player self.craftsanity_option = craftsanity_option self.exclude_ginger_island = exclude_ginger_island self.mods = mods diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index c9ab8802a233..fc6588538a2b 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,8 +1,7 @@ from typing import Union, Iterable from Utils import cache_self1 -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -19,7 +18,7 @@ from ..strings.tool_names import Tool -class CropLogic(CachedLogic): +class CropLogic: player: int cropsanity_option: Cropsanity exclude_ginger_island_option: ExcludeGingerIsland @@ -31,9 +30,9 @@ class CropLogic(CachedLogic): money: MoneyLogic tool: ToolLogic - def __init__(self, player: int, cached_rules: CachedRules, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, region: RegionLogic, - traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, + region: RegionLogic, traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): + self.player = player self.cropsanity_option = cropsanity_option self.exclude_ginger_island_option = exclude_ginger_island_option self.received = received diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 0efe8f4caf45..8af498783c5d 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,5 +1,4 @@ from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic @@ -15,7 +14,7 @@ from ..strings.skill_names import Skill -class FishingLogic(CachedLogic): +class FishingLogic: exclude_ginger_island: ExcludeGingerIsland special_order_locations: SpecialOrderLocations received: ReceivedLogic @@ -24,10 +23,9 @@ class FishingLogic(CachedLogic): tool: ToolLogic skill: SkillLogic - def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, - special_order_locations: SpecialOrderLocations, - received: ReceivedLogic, region: RegionLogic, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, received: ReceivedLogic, + region: RegionLogic, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): + self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_order_locations = special_order_locations self.received = received diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 7ac88086be23..3f3c0ed3e6c5 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,20 +1,18 @@ from functools import cached_property -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct from ..strings.gift_names import Gift -class GiftLogic(CachedLogic): +class GiftLogic: has: HasLogic - def __init__(self, player: int, cached_rules: CachedRules, has: HasLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, has: HasLogic): + self.player = player self.has = has @cached_property def has_any_universal_love(self) -> StardewRule: - return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has( - AnimalProduct.rabbit_foot) + return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 743e0432964a..80ff3cac77fe 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,14 +1,13 @@ from typing import Dict, Union, Optional, Tuple -from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, True_, And, Or, Has, Count -class HasLogic(CachedLogic): +class HasLogic: item_rules: Dict[str, StardewRule] - def __init__(self, player: int, cached_rules: CachedRules, item_rules: Dict[str, StardewRule]): - super().__init__(player, cached_rules) + def __init__(self, player: int, item_rules: Dict[str, StardewRule]): + self.player = player self.item_rules = item_rules def __call__(self, *args, **kwargs) -> StardewRule: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 504f0827703f..5fd3910a2c9c 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -16,7 +16,7 @@ from .crop_logic import CropLogic from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic -from .gift_logic import GiftLogic, CachedRules +from .gift_logic import GiftLogic from .has_logic import HasLogic from .mine_logic import MineLogic from .money_logic import MoneyLogic @@ -44,8 +44,7 @@ from ..data.recipe_data import all_cooking_recipes from ..mods.logic.mod_logic import ModLogic from ..mods.mod_data import ModNames -from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions, Fishsanity, Museumsanity, Friendsanity -from ..regions import vanilla_regions +from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions, Fishsanity, Friendsanity from ..stardew_rule import False_, Or, True_, Count, And, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals from ..strings.animal_product_names import AnimalProduct @@ -103,18 +102,17 @@ class StardewLogic: festival_rules: Dict[str, StardewRule] = field(default_factory=dict) def __post_init__(self): - self.cached_rules = CachedRules() - self.received = ReceivedLogic(self.player, self.cached_rules) - self.has = HasLogic(self.player, self.cached_rules, self.item_rules) - self.region = RegionLogic(self.player, self.cached_rules) + self.received = ReceivedLogic(self.player) + self.has = HasLogic(self.player, self.item_rules) + self.region = RegionLogic(self.player) self.traveling_merchant = TravelingMerchantLogic(self.player, self.received) - self.time = TimeLogic(self.player, self.cached_rules, self.received) - self.season = SeasonLogic(self.player, self.cached_rules, self.options.season_randomization, self.received, self.time) - self.money = MoneyLogic(self.player, self.cached_rules, self.options.starting_money, self.received, self.has, self.region, self.time) - self.action = ActionLogic(self.player, self.cached_rules, self.received, self.has, self.region) + self.time = TimeLogic(self.player, self.received) + self.season = SeasonLogic(self.player, self.options.season_randomization, self.received, self.time) + self.money = MoneyLogic(self.player, self.options.starting_money, self.received, self.has, self.region, self.time) + self.action = ActionLogic(self.player, self.received, self.has, self.region) self.arcade = ArcadeLogic(self.player, self.options.arcade_machine_locations, self.received, self.region) self.artisan = ArtisanLogic(self.player, self.has, self.time) - self.gifts = GiftLogic(self.player, self.cached_rules, self.has) + self.gifts = GiftLogic(self.player, self.has) tool_option = self.options.tool_progression skill_option = self.options.skill_progression elevator_option = self.options.elevator_progression @@ -123,28 +121,29 @@ def __post_init__(self): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.buildings = BuildingLogic(self.player, self.cached_rules, self.options.building_progression, self.received, self.has, self.region, self.money) - self.shipping = ShippingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, mods_option, self.has, self.region, + self.buildings = BuildingLogic(self.player, self.options.building_progression, self.received, self.has, self.region, self.money) + self.shipping = ShippingLogic(self.player, exclude_ginger_island, special_order_locations, mods_option, self.has, self.region, self.buildings) - self.relationship = RelationshipLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, + self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) - self.museum = MuseumLogic(self.player, self.cached_rules, self.options.museumsanity, self.received, self.has, self.region, self.action) + self.museum = MuseumLogic(self.player, self.options.museumsanity, self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) - self.combat = CombatLogic(self.player, self.cached_rules, self.received, self.region) - self.monster = MonsterLogic(self.player, self.cached_rules, self.region, self.time, self.combat) - self.tool = ToolLogic(self.player, self.cached_rules, tool_option, self.received, self.has, self.region, self.season, self.money) - self.pet = PetLogic(self.player, self.cached_rules, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) - self.crop = CropLogic(self.player, self.cached_rules, self.options.cropsanity, exclude_ginger_island, self.received, self.has, self.region, self.traveling_merchant, + self.combat = CombatLogic(self.player, self.received, self.region) + self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) + self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) + self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) + self.crop = CropLogic(self.player, self.options.cropsanity, exclude_ginger_island, self.received, self.has, self.region, + self.traveling_merchant, self.season, self.money, self.tool) - self.skill = SkillLogic(self.player, self.cached_rules, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, + self.skill = SkillLogic(self.player, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, self.combat, self.crop) self.farming = FarmingLogic(self.player, self.has, self.skill) - self.bundle = BundleLogic(self.player, self.cached_rules, self.has, self.region, self.money, self.farming) - self.fishing = FishingLogic(self.player, self.cached_rules, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, + self.bundle = BundleLogic(self.player, self.has, self.region, self.money, self.farming) + self.fishing = FishingLogic(self.player, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, self.tool, self.skill) - self.mine = MineLogic(self.player, self.cached_rules, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, + self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.cached_rules, self.options.chefsanity, exclude_ginger_island, mods_option, self.received, self.has, + self.cooking = CookingLogic(self.player, self.options.chefsanity, exclude_ginger_island, mods_option, self.received, self.has, self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) @@ -152,7 +151,7 @@ def __post_init__(self): self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, self.time, self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, self.wallet, mods_option) - self.crafting = CraftingLogic(self.player, self.cached_rules, self.options.craftsanity, exclude_ginger_island, mods_option, + self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 89a34779827d..b96cfb83d019 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,6 +1,5 @@ from Utils import cache_self1 -from .cached_logic import CachedLogic -from .combat_logic import CombatLogic, CachedRules +from .combat_logic import CombatLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .skill_logic import SkillLogic @@ -15,7 +14,7 @@ from ..strings.tool_names import Tool, ToolMaterial -class MineLogic(CachedLogic): +class MineLogic: tool_option: ToolProgression skill_option: SkillProgression elevator_option: ElevatorProgression @@ -26,11 +25,9 @@ class MineLogic(CachedLogic): skill: SkillLogic mod_elevator: ModElevatorLogic - def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, - skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, - region: RegionLogic, - combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, + region: RegionLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): + self.player = player self.tool_option = tool_option self.skill_option = skill_option self.elevator_option = elevator_option diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 9255264986b3..4de343cb5d76 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,6 +1,5 @@ from Utils import cache_self1 -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic @@ -13,17 +12,15 @@ "25 Qi Gems", "20 Qi Gems", "10 Qi Gems") -class MoneyLogic(CachedLogic): +class MoneyLogic: starting_money_option: StartingMoney received: ReceivedLogic has: HasLogic region: RegionLogic time: TimeLogic - def __init__(self, player: int, cached_rules: CachedRules, starting_money_option: StartingMoney, - received: ReceivedLogic, - has: HasLogic, region: RegionLogic, time: TimeLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, starting_money_option: StartingMoney, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): + self.player = player self.starting_money_option = starting_money_option self.received = received self.has = has diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 0d9db208d10b..4c7459770161 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,7 +1,6 @@ from typing import Iterable, Union, Hashable from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from .combat_logic import CombatLogic from .region_logic import RegionLogic from .time_logic import TimeLogic, MAX_MONTHS @@ -9,14 +8,13 @@ from ..stardew_rule import StardewRule, Or, And -class MonsterLogic(CachedLogic): +class MonsterLogic: region: RegionLogic time: TimeLogic combat: CombatLogic - def __init__(self, player: int, cached_rules: CachedRules, region: RegionLogic, time: TimeLogic, - combat: CombatLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, region: RegionLogic, time: TimeLogic, combat: CombatLogic): + self.player = player self.region = region self.time = time self.combat = combat diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 16a7bf5e91e7..18384e4f3b7c 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -2,8 +2,7 @@ from Utils import cache_self1 from .action_logic import ActionLogic -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .. import options @@ -13,7 +12,7 @@ from ..strings.region_names import Region -class MuseumLogic(CachedLogic): +class MuseumLogic: player: int museum_option: Museumsanity received = ReceivedLogic @@ -21,10 +20,8 @@ class MuseumLogic(CachedLogic): region: RegionLogic action: ActionLogic - def __init__(self, player: int, cached_rules: CachedRules, museum_option: Museumsanity, received: ReceivedLogic, - has: HasLogic, - region: RegionLogic, action: ActionLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic): + self.player = player self.museum_option = museum_option self.received = received self.has = has diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 413dbe07827d..4c7ede2c02df 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -1,7 +1,6 @@ import math from typing import Union -from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .time_logic import TimeLogic @@ -13,7 +12,7 @@ from ..strings.villager_names import NPC -class PetLogic(CachedLogic): +class PetLogic: friendsanity_option: Friendsanity heart_size_option: FriendsanityHeartSize received: ReceivedLogic @@ -21,9 +20,9 @@ class PetLogic(CachedLogic): time: TimeLogic tool: ToolLogic - def __init__(self, player: int, cached_rules: CachedRules, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, + def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, region: RegionLogic, time: TimeLogic, tool: ToolLogic): - super().__init__(player, cached_rules) + self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option self.received = received_logic diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 9bb952c98991..bee387c4ae9f 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,13 +1,12 @@ from typing import Union, Optional, Tuple -from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived -class ReceivedLogic(CachedLogic): +class ReceivedLogic: - def __init__(self, player: int, cached_rules: CachedRules): - super().__init__(player, cached_rules) + def __init__(self, player: int): + self.player = player def __call__(self, *args, **kwargs) -> StardewRule: count = 1 diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 72d6710a2066..215c819c0142 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,14 +1,13 @@ from typing import Tuple from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from ..stardew_rule import StardewRule, And, Or, Reach, Count -class RegionLogic(CachedLogic): +class RegionLogic: - def __init__(self, player: int, cached_rules: CachedRules): - super().__init__(player, cached_rules) + def __init__(self, player: int): + self.player = player @cache_self1 def can_reach(self, region_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index bdf6e87bffd7..a329d48a879f 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -3,9 +3,8 @@ from Utils import cache_self1 from .building_logic import BuildingLogic -from .cached_logic import CachedLogic from .gift_logic import GiftLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic @@ -21,7 +20,7 @@ possible_kids = ("Cute Baby", "Ugly Baby") -class RelationshipLogic(CachedLogic): +class RelationshipLogic: friendsanity_option: Friendsanity heart_size_option: FriendsanityHeartSize received: ReceivedLogic @@ -33,11 +32,11 @@ class RelationshipLogic(CachedLogic): buildings: BuildingLogic mods_option: Mods - def __init__(self, player: int, cached_rules: CachedRules, friendsanity_option: Friendsanity, + def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): - super().__init__(player, cached_rules) + self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option self.received = received_logic diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 4516df34123c..19046fd8776a 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,7 +1,6 @@ from typing import Iterable from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from .time_logic import TimeLogic from ..options import SeasonRandomization @@ -10,14 +9,13 @@ from ..strings.season_names import Season -class SeasonLogic(CachedLogic): +class SeasonLogic: season_option: SeasonRandomization received: ReceivedLogic time: TimeLogic - def __init__(self, player: int, cached_rules: CachedRules, season_option: SeasonRandomization, - received_logic: ReceivedLogic, time: TimeLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, season_option: SeasonRandomization, received_logic: ReceivedLogic, time: TimeLogic): + self.player = player self.season_option = season_option self.received = received_logic self.time = time diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 9e757a22310e..5fa24bdbcf3b 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -2,7 +2,6 @@ from Utils import cache_self1 from .building_logic import BuildingLogic -from .cached_logic import CachedLogic, CachedRules from .has_logic import HasLogic from .region_logic import RegionLogic from ..locations import LocationTags, locations_by_tag @@ -14,7 +13,7 @@ from ..strings.region_names import Region -class ShippingLogic(CachedLogic): +class ShippingLogic: exclude_ginger_island: ExcludeGingerIsland special_orders_option: SpecialOrderLocations mods: Mods @@ -22,10 +21,9 @@ class ShippingLogic(CachedLogic): region: RegionLogic buildings: BuildingLogic - def __init__(self, player: int, cached_rules: CachedRules, exclude_ginger_island: ExcludeGingerIsland, - special_orders_option: SpecialOrderLocations, mods: Mods, - has: HasLogic, region: RegionLogic, buildings: BuildingLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations,mods: Mods, has: HasLogic, + region: RegionLogic, buildings: BuildingLogic): + self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_orders_option = special_orders_option self.mods = mods diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 79db857a9d34..ef7d5d2c2043 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -3,10 +3,9 @@ from Utils import cache_self1 from worlds.stardew_valley.strings.craftable_names import Fishing -from .cached_logic import CachedLogic from .combat_logic import CombatLogic from .crop_logic import CropLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic from .season_logic import SeasonLogic @@ -18,7 +17,6 @@ from ..mods.logic.mod_skills_levels import get_mod_skill_levels from ..options import SkillProgression, Mods from ..stardew_rule import StardewRule, True_, Or -from ..strings.generic_names import Generic from ..strings.machine_names import Machine from ..strings.performance_names import Performance from ..strings.region_names import Region @@ -28,7 +26,7 @@ fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west) -class SkillLogic(CachedLogic): +class SkillLogic: skill_option: SkillProgression received: ReceivedLogic has: HasLogic @@ -41,10 +39,9 @@ class SkillLogic(CachedLogic): magic: MagicLogic mods: Mods - def __init__(self, player: int, cached_rules: CachedRules, skill_option: SkillProgression, received: ReceivedLogic, - has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, - tool: ToolLogic, combat: CombatLogic, crop: CropLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, + time: TimeLogic, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): + self.player = player self.skill_option = skill_option self.received = received self.has = has diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index c2d9af1ec7b7..1fa014f77381 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,7 +1,6 @@ from functools import cached_property from Utils import cache_self1 -from .cached_logic import CachedLogic, CachedRules from .received_logic import ReceivedLogic from ..stardew_rule import StardewRule, CountPercent, True_ from ..strings.ap_names.event_names import Event @@ -10,11 +9,11 @@ MONTH_COEFFICIENT = 100 // MAX_MONTHS -class TimeLogic(CachedLogic): +class TimeLogic: received: ReceivedLogic - def __init__(self, player: int, cached_rules: CachedRules, received_logic: ReceivedLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, received_logic: ReceivedLogic): + self.player = player self.received = received_logic @cache_self1 diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 77108a53b244..f7a7883d6d04 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,6 +1,5 @@ from Utils import cache_self1 -from .cached_logic import CachedLogic -from .has_logic import HasLogic, CachedRules +from .has_logic import HasLogic from .money_logic import MoneyLogic from .received_logic import ReceivedLogic from .region_logic import RegionLogic @@ -28,7 +27,7 @@ } -class ToolLogic(CachedLogic): +class ToolLogic: tool_option = ToolProgression received: ReceivedLogic has: HasLogic @@ -37,10 +36,9 @@ class ToolLogic(CachedLogic): money: MoneyLogic magic: MagicLogic - def __init__(self, player: int, cached_rules: CachedRules, tool_option: ToolProgression, received: ReceivedLogic, - has: HasLogic, region: RegionLogic, - season: SeasonLogic, money: MoneyLogic): - super().__init__(player, cached_rules) + def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, + money: MoneyLogic): + self.player = player self.tool_option = tool_option self.received = received self.has = has From cca376f4804ba9a48d3bea8b4461f2cd31b3558e Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 19:02:37 -0500 Subject: [PATCH 185/482] introduce first mixin --- worlds/stardew_valley/logic/ability_logic.py | 12 +++--- worlds/stardew_valley/logic/action_logic.py | 14 +++---- worlds/stardew_valley/logic/arcade_logic.py | 10 ++--- worlds/stardew_valley/logic/artisan_logic.py | 6 +-- worlds/stardew_valley/logic/base_logic.py | 32 +++++++++++++++ worlds/stardew_valley/logic/building_logic.py | 15 +++---- worlds/stardew_valley/logic/bundle_logic.py | 10 ++--- worlds/stardew_valley/logic/combat_logic.py | 10 ++--- worlds/stardew_valley/logic/cooking_logic.py | 17 ++++---- worlds/stardew_valley/logic/crafting_logic.py | 15 +++---- worlds/stardew_valley/logic/crop_logic.py | 17 ++++---- worlds/stardew_valley/logic/farming_logic.py | 6 +-- worlds/stardew_valley/logic/fishing_logic.py | 12 +++--- worlds/stardew_valley/logic/gift_logic.py | 6 +-- worlds/stardew_valley/logic/has_logic.py | 13 +++---- worlds/stardew_valley/logic/logic.py | 39 ++++++++----------- worlds/stardew_valley/logic/mine_logic.py | 13 ++++--- worlds/stardew_valley/logic/money_logic.py | 15 +++---- worlds/stardew_valley/logic/monster_logic.py | 6 +-- worlds/stardew_valley/logic/museum_logic.py | 15 +++---- worlds/stardew_valley/logic/pet_logic.py | 10 ++--- worlds/stardew_valley/logic/quest_logic.py | 15 +++---- worlds/stardew_valley/logic/received_logic.py | 7 ++-- worlds/stardew_valley/logic/region_logic.py | 7 ++-- .../logic/relationship_logic.py | 14 +++---- worlds/stardew_valley/logic/season_logic.py | 6 +-- worlds/stardew_valley/logic/shipping_logic.py | 12 +++--- worlds/stardew_valley/logic/skill_logic.py | 15 +++---- .../logic/special_order_logic.py | 15 +++---- worlds/stardew_valley/logic/time_logic.py | 6 +-- worlds/stardew_valley/logic/tool_logic.py | 15 +++---- .../logic/traveling_merchant_logic.py | 6 +-- worlds/stardew_valley/logic/wallet_logic.py | 6 +-- .../mods/logic/buildings_logic.py | 18 ++++----- .../mods/logic/deepwoods_logic.py | 15 +++---- .../mods/logic/elevator_logic.py | 8 ++-- .../stardew_valley/mods/logic/item_logic.py | 30 +++++++------- .../stardew_valley/mods/logic/magic_logic.py | 16 ++++---- worlds/stardew_valley/mods/logic/mod_logic.py | 26 +++++++------ .../stardew_valley/mods/logic/quests_logic.py | 30 +++++++------- .../stardew_valley/mods/logic/skills_logic.py | 23 +++++------ .../mods/logic/special_orders_logic.py | 25 ++++++------ worlds/stardew_valley/mods/logic/sve_logic.py | 19 ++++----- 43 files changed, 335 insertions(+), 292 deletions(-) create mode 100644 worlds/stardew_valley/logic/base_logic.py diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index ac5a2d1241b7..21c1dfee6987 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -1,6 +1,6 @@ from .mine_logic import MineLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .skill_logic import SkillLogic from .tool_logic import ToolLogic from ..mods.logic.magic_logic import MagicLogic @@ -17,16 +17,16 @@ class AbilityLogic: player: int movement_buff_option: NumberOfMovementBuffs luck_buff_option: NumberOfLuckBuffs - received: ReceivedLogic - region: RegionLogic + received: ReceivedLogicMixin + region: RegionLogicMixin tool: ToolLogic skill: SkillLogic mine: MineLogic magic: MagicLogic mod_skill: ModSkillLogic - def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogic, - region: RegionLogic, tool: ToolLogic, skill: SkillLogic, mine: MineLogic): + def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogicMixin, + region: RegionLogicMixin, tool: ToolLogic, skill: SkillLogic, mine: MineLogic): self.player = player self.movement_buff_option = movement_buff_option self.luck_buff_option = luck_buff_option diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 4ffc8ebed187..e70e7fa1a5f6 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,7 +1,7 @@ from Utils import cache_self1 -from .has_logic import HasLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .has_logic import HasLogicMixin +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from ..stardew_rule import StardewRule, True_, Or from ..strings.generic_names import Generic from ..strings.geode_names import Geode @@ -9,11 +9,11 @@ class ActionLogic: - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin - def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic): + def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin): self.player = player self.received = received self.has = has diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index 8298c2cff691..eae7ce67be17 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,5 +1,5 @@ -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .. import options from ..options import ArcadeMachineLocations from ..stardew_rule import StardewRule, True_ @@ -9,10 +9,10 @@ class ArcadeLogic: player: int arcade_option: ArcadeMachineLocations - received = ReceivedLogic - region: RegionLogic + received = ReceivedLogicMixin + region: RegionLogicMixin - def __init__(self, player: int, arcade_option: ArcadeMachineLocations, received: ReceivedLogic, region: RegionLogic): + def __init__(self, player: int, arcade_option: ArcadeMachineLocations, received: ReceivedLogicMixin, region: RegionLogicMixin): self.player = player self.arcade_option = arcade_option self.received = received diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index e7e63ba21263..6d98637a1c42 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -1,4 +1,4 @@ -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .time_logic import TimeLogic from ..stardew_rule import StardewRule from ..strings.crop_names import all_vegetables, all_fruits, Vegetable, Fruit @@ -8,10 +8,10 @@ class ArtisanLogic: player: int - has: HasLogic + has: HasLogicMixin time: TimeLogic - def __init__(self, player: int, has: HasLogic, time: TimeLogic): + def __init__(self, player: int, has: HasLogicMixin, time: TimeLogic): self.player = player self.has = has self.time = time diff --git a/worlds/stardew_valley/logic/base_logic.py b/worlds/stardew_valley/logic/base_logic.py new file mode 100644 index 000000000000..2d315ba963a7 --- /dev/null +++ b/worlds/stardew_valley/logic/base_logic.py @@ -0,0 +1,32 @@ +from dataclasses import dataclass, field +from typing import Dict + +from ..options import StardewValleyOptions +from ..stardew_rule import StardewRule + + +@dataclass(frozen=False) +class LogicRegistry: + player: int + options: StardewValleyOptions + + item_rules: Dict[str, StardewRule] = field(default_factory=dict) + sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) + tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) + seed_rules: Dict[str, StardewRule] = field(default_factory=dict) + cooking_rules: Dict[str, StardewRule] = field(default_factory=dict) + crafting_rules: Dict[str, StardewRule] = field(default_factory=dict) + crop_rules: Dict[str, StardewRule] = field(default_factory=dict) + fish_rules: Dict[str, StardewRule] = field(default_factory=dict) + museum_rules: Dict[str, StardewRule] = field(default_factory=dict) + festival_rules: Dict[str, StardewRule] = field(default_factory=dict) + quest_rules: Dict[str, StardewRule] = field(default_factory=dict) + + +class BaseLogic: + player: int + registry: LogicRegistry + + def __init__(self, player: int, registry: LogicRegistry): + self.player = player + self.registry = registry diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 7d04c45002b3..aba4cdb66099 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,10 +1,10 @@ from typing import Dict from Utils import cache_self1 -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from ..options import BuildingProgression from ..stardew_rule import StardewRule, True_, False_, Has from ..strings.ap_names.event_names import Event @@ -19,13 +19,14 @@ class BuildingLogic: player: int building_option: BuildingProgression - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin money: MoneyLogic building_rules: Dict[str, StardewRule] - def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, money: MoneyLogic): + def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, + money: MoneyLogic): self.player = player self.player = player self.building_option = building_option diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 74d98cedc6f7..45ae765e3e8b 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -2,21 +2,21 @@ from typing import Tuple from .farming_logic import FarmingLogic -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .money_logic import MoneyLogic -from .region_logic import RegionLogic +from .region_logic import RegionLogicMixin from ..data.bundle_data import BundleItem from ..stardew_rule import StardewRule from ..strings.region_names import Region class BundleLogic: - has: HasLogic - region: RegionLogic + has: HasLogicMixin + region: RegionLogicMixin money: MoneyLogic farming: FarmingLogic - def __init__(self, player: int, has: HasLogic, region: RegionLogic, money: MoneyLogic, farming: FarmingLogic): + def __init__(self, player: int, has: HasLogicMixin, region: RegionLogicMixin, money: MoneyLogic, farming: FarmingLogic): self.player = player self.has = has self.region = region diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index e053d1c62d37..7575c3a2a945 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,8 +1,8 @@ from functools import cached_property from Utils import cache_self1 -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from ..mods.logic.magic_logic import MagicLogic from ..stardew_rule import StardewRule, Or, False_ from ..strings.ap_names.ap_weapon_names import APWeapon @@ -12,11 +12,11 @@ class CombatLogic: - received: ReceivedLogic - region: RegionLogic + received: ReceivedLogicMixin + region: RegionLogicMixin magic: MagicLogic - def __init__(self, player: int, received: ReceivedLogic, region: RegionLogic): + def __init__(self, player: int, received: ReceivedLogicMixin, region: RegionLogicMixin): self.player = player self.region = region self.received = received diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 3a98170506f8..1e5e50d77658 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -3,10 +3,10 @@ from Utils import cache_self1 from .action_logic import ActionLogic from .building_logic import BuildingLogic -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic from .skill_logic import SkillLogic @@ -28,9 +28,9 @@ class CookingLogic: chefsanity_option: Chefsanity exclude_ginger_island: ExcludeGingerIsland mods: Mods - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin season: SeasonLogic time: TimeLogic money: MoneyLogic @@ -39,8 +39,9 @@ class CookingLogic: relationship: RelationshipLogic skill: SkillLogic - def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogic, - has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, buildings: BuildingLogic, + def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogicMixin, + has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, + buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player self.chefsanity_option = chefsanity_option diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index a9c28ca6f507..c2185e8055f3 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,10 +1,10 @@ from functools import cached_property from Utils import cache_self1 -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .skill_logic import SkillLogic from .special_order_logic import SpecialOrderLogic @@ -26,9 +26,9 @@ class CraftingLogic: mods: Mods festivals_option: FestivalLocations special_orders_option: SpecialOrderLocations - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin time: TimeLogic money: MoneyLogic relationship: RelationshipLogic @@ -36,7 +36,8 @@ class CraftingLogic: special_orders: SpecialOrderLogic def __init__(self, player: int, craftsanity_option: Craftsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, - festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogic, has: HasLogic, region: RegionLogic, + festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogicMixin, has: HasLogicMixin, + region: RegionLogicMixin, time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): self.player = player self.craftsanity_option = craftsanity_option diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index fc6588538a2b..383ec7f4c99b 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,10 +1,10 @@ from typing import Union, Iterable from Utils import cache_self1 -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .season_logic import SeasonLogic from .tool_logic import ToolLogic from .traveling_merchant_logic import TravelingMerchantLogic @@ -22,16 +22,17 @@ class CropLogic: player: int cropsanity_option: Cropsanity exclude_ginger_island_option: ExcludeGingerIsland - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin traveling_merchant: TravelingMerchantLogic season: SeasonLogic money: MoneyLogic tool: ToolLogic - def __init__(self, player: int, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogic, has: HasLogic, - region: RegionLogic, traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): + def __init__(self, player: int, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogicMixin, + has: HasLogicMixin, + region: RegionLogicMixin, traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): self.player = player self.cropsanity_option = cropsanity_option self.exclude_ginger_island_option = exclude_ginger_island_option diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 83078a31682c..cf20021d50af 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -1,4 +1,4 @@ -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .skill_logic import SkillLogic from ..stardew_rule import StardewRule, True_ from ..strings.fertilizer_names import Fertilizer @@ -6,10 +6,10 @@ class FarmingLogic: player: int - has: HasLogic + has: HasLogicMixin skill: SkillLogic - def __init__(self, player: int, has: HasLogic, skill: SkillLogic): + def __init__(self, player: int, has: HasLogicMixin, skill: SkillLogic): self.player = player self.has = has self.skill = skill diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 8af498783c5d..b42e9e2107e5 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,6 +1,6 @@ from Utils import cache_self1 -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .tool_logic import ToolLogic @@ -17,14 +17,14 @@ class FishingLogic: exclude_ginger_island: ExcludeGingerIsland special_order_locations: SpecialOrderLocations - received: ReceivedLogic - region: RegionLogic + received: ReceivedLogicMixin + region: RegionLogicMixin season: SeasonLogic tool: ToolLogic skill: SkillLogic - def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, received: ReceivedLogic, - region: RegionLogic, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): + def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, received: ReceivedLogicMixin, + region: RegionLogicMixin, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_order_locations = special_order_locations diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 3f3c0ed3e6c5..9b351fd9e9da 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,15 +1,15 @@ from functools import cached_property -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct from ..strings.gift_names import Gift class GiftLogic: - has: HasLogic + has: HasLogicMixin - def __init__(self, player: int, has: HasLogic): + def __init__(self, player: int, has: HasLogicMixin): self.player = player self.has = has diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 80ff3cac77fe..5d82c0f4acb9 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,14 +1,13 @@ -from typing import Dict, Union, Optional, Tuple +from typing import Union, Optional, Tuple +from .base_logic import BaseLogic, LogicRegistry from ..stardew_rule import StardewRule, True_, And, Or, Has, Count -class HasLogic: - item_rules: Dict[str, StardewRule] +class HasLogicMixin(BaseLogic): - def __init__(self, player: int, item_rules: Dict[str, StardewRule]): - self.player = player - self.item_rules = item_rules + def __init__(self, player: int, registry: LogicRegistry): + super().__init__(player, registry) def __call__(self, *args, **kwargs) -> StardewRule: count = None @@ -19,7 +18,7 @@ def __call__(self, *args, **kwargs) -> StardewRule: # Should be cached def has(self, items: Union[str, Tuple[str]], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): - return Has(items, self.item_rules) + return Has(items, self.registry.item_rules) if len(items) == 0: return True_() diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 5fd3910a2c9c..9ed776a3fd62 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -1,13 +1,13 @@ from __future__ import annotations -from dataclasses import field, dataclass -from typing import Dict +from dataclasses import dataclass from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from .ability_logic import AbilityLogic from .action_logic import ActionLogic from .arcade_logic import ArcadeLogic from .artisan_logic import ArtisanLogic +from .base_logic import LogicRegistry, BaseLogic from .building_logic import BuildingLogic from .bundle_logic import BundleLogic from .combat_logic import CombatLogic @@ -17,15 +17,15 @@ from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic from .gift_logic import GiftLogic -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .mine_logic import MineLogic from .money_logic import MoneyLogic from .monster_logic import MonsterLogic from .museum_logic import MuseumLogic from .pet_logic import PetLogic from .quest_logic import QuestLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic from .shipping_logic import ShippingLogic @@ -44,7 +44,7 @@ from ..data.recipe_data import all_cooking_recipes from ..mods.logic.mod_logic import ModLogic from ..mods.mod_data import ModNames -from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions, Fishsanity, Friendsanity +from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity from ..stardew_rule import False_, Or, True_, Count, And, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals from ..strings.animal_product_names import AnimalProduct @@ -85,26 +85,18 @@ fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] +# FIXME this should not extend LogicRegistry, but it's a step in the migration. @dataclass(frozen=False, repr=False) -class StardewLogic: +class StardewLogic(BaseLogic, LogicRegistry): player: int - options: StardewValleyOptions - - item_rules: Dict[str, StardewRule] = field(default_factory=dict) - sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) - tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) - seed_rules: Dict[str, StardewRule] = field(default_factory=dict) - cooking_rules: Dict[str, StardewRule] = field(default_factory=dict) - crafting_rules: Dict[str, StardewRule] = field(default_factory=dict) - crop_rules: Dict[str, StardewRule] = field(default_factory=dict) - fish_rules: Dict[str, StardewRule] = field(default_factory=dict) - museum_rules: Dict[str, StardewRule] = field(default_factory=dict) - festival_rules: Dict[str, StardewRule] = field(default_factory=dict) def __post_init__(self): - self.received = ReceivedLogic(self.player) - self.has = HasLogic(self.player, self.item_rules) - self.region = RegionLogic(self.player) + # FIXME this is awful + self.registry = self + + self.received = ReceivedLogicMixin(self.player, self.registry) + self.has = HasLogicMixin(self.player, self.registry) + self.region = RegionLogicMixin(self.player, self.registry) self.traveling_merchant = TravelingMerchantLogic(self.player, self.received) self.time = TimeLogic(self.player, self.received) self.season = SeasonLogic(self.player, self.options.season_randomization, self.received, self.time) @@ -154,7 +146,8 @@ def __post_init__(self): self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, + self.mod = ModLogic(self.player, self.registry, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, + self.artisan, self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index b96cfb83d019..3b1b6b9e30e2 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,7 +1,7 @@ from Utils import cache_self1 from .combat_logic import CombatLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .skill_logic import SkillLogic from .tool_logic import ToolLogic from .. import options @@ -18,15 +18,16 @@ class MineLogic: tool_option: ToolProgression skill_option: SkillProgression elevator_option: ElevatorProgression - received: ReceivedLogic - region: RegionLogic + received: ReceivedLogicMixin + region: RegionLogicMixin combat: CombatLogic tool: ToolLogic skill: SkillLogic mod_elevator: ModElevatorLogic - def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, - region: RegionLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): + def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, + received: ReceivedLogicMixin, + region: RegionLogicMixin, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): self.player = player self.tool_option = tool_option self.skill_option = skill_option diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 4de343cb5d76..8a7bce79fe70 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,7 +1,7 @@ from Utils import cache_self1 -from .has_logic import HasLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .has_logic import HasLogicMixin +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .time_logic import TimeLogic from ..options import StartingMoney from ..stardew_rule import StardewRule, True_, CountPercent @@ -14,12 +14,13 @@ class MoneyLogic: starting_money_option: StartingMoney - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin time: TimeLogic - def __init__(self, player: int, starting_money_option: StartingMoney, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic): + def __init__(self, player: int, starting_money_option: StartingMoney, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, + time: TimeLogic): self.player = player self.starting_money_option = starting_money_option self.received = received diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 4c7459770161..3aeb0bf4c02b 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -2,18 +2,18 @@ from Utils import cache_self1 from .combat_logic import CombatLogic -from .region_logic import RegionLogic +from .region_logic import RegionLogicMixin from .time_logic import TimeLogic, MAX_MONTHS from ..data.monster_data import StardewMonster, all_monsters_by_name from ..stardew_rule import StardewRule, Or, And class MonsterLogic: - region: RegionLogic + region: RegionLogicMixin time: TimeLogic combat: CombatLogic - def __init__(self, player: int, region: RegionLogic, time: TimeLogic, combat: CombatLogic): + def __init__(self, player: int, region: RegionLogicMixin, time: TimeLogic, combat: CombatLogic): self.player = player self.region = region self.time = time diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 18384e4f3b7c..1ff9b56bad87 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -2,9 +2,9 @@ from Utils import cache_self1 from .action_logic import ActionLogic -from .has_logic import HasLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .has_logic import HasLogicMixin +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals from ..options import Museumsanity @@ -15,12 +15,13 @@ class MuseumLogic: player: int museum_option: Museumsanity - received = ReceivedLogic - has: HasLogic - region: RegionLogic + received = ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin action: ActionLogic - def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic): + def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, + action: ActionLogic): self.player = player self.museum_option = museum_option self.received = received diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 4c7ede2c02df..0aff9d9ec7a4 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -1,8 +1,8 @@ import math from typing import Union -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .time_logic import TimeLogic from .tool_logic import ToolLogic from ..data.villagers_data import Villager @@ -15,13 +15,13 @@ class PetLogic: friendsanity_option: Friendsanity heart_size_option: FriendsanityHeartSize - received: ReceivedLogic - region: RegionLogic + received: ReceivedLogicMixin + region: RegionLogicMixin time: TimeLogic tool: ToolLogic def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, - received_logic: ReceivedLogic, region: RegionLogic, time: TimeLogic, tool: ToolLogic): + received_logic: ReceivedLogicMixin, region: RegionLogicMixin, time: TimeLogic, tool: ToolLogic): self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 88a63f6cfbb8..17013d433d13 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -5,11 +5,11 @@ from .combat_logic import CombatLogic from .cooking_logic import CookingLogic from .fishing_logic import FishingLogic -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .mine_logic import MineLogic from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic from .skill_logic import SkillLogic @@ -39,10 +39,10 @@ class QuestLogic: player: int - received: ReceivedLogic - has: HasLogic + received: ReceivedLogicMixin + has: HasLogicMixin mine: MineLogic - region: RegionLogic + region: RegionLogicMixin relationship: RelationshipLogic tool: ToolLogic fishing: FishingLogic @@ -55,7 +55,8 @@ class QuestLogic: wallet: WalletLogic quest_rules: Dict[str, StardewRule] - def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogic, has: HasLogic, mine: MineLogic, region: RegionLogic, action: ActionLogic, + def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogicMixin, has: HasLogicMixin, mine: MineLogic, region: RegionLogicMixin, + action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, time: TimeLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): self.player = player diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index bee387c4ae9f..f481281bc90f 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,12 +1,13 @@ from typing import Union, Optional, Tuple +from .base_logic import BaseLogic, LogicRegistry from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived -class ReceivedLogic: +class ReceivedLogicMixin(BaseLogic): - def __init__(self, player: int): - self.player = player + def __init__(self, player: int, registry: LogicRegistry): + super().__init__(player, registry) def __call__(self, *args, **kwargs) -> StardewRule: count = 1 diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 215c819c0142..c6411efa3cb1 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,13 +1,14 @@ from typing import Tuple from Utils import cache_self1 +from .base_logic import BaseLogic, LogicRegistry from ..stardew_rule import StardewRule, And, Or, Reach, Count -class RegionLogic: +class RegionLogicMixin(BaseLogic): - def __init__(self, player: int): - self.player = player + def __init__(self, player: int, registry: LogicRegistry): + super().__init__(player, registry) @cache_self1 def can_reach(self, region_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index a329d48a879f..8b8abba5abd7 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -4,9 +4,9 @@ from Utils import cache_self1 from .building_logic import BuildingLogic from .gift_logic import GiftLogic -from .has_logic import HasLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .has_logic import HasLogicMixin +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .season_logic import SeasonLogic from .time_logic import TimeLogic from ..data.villagers_data import all_villagers_by_name, Villager @@ -23,9 +23,9 @@ class RelationshipLogic: friendsanity_option: Friendsanity heart_size_option: FriendsanityHeartSize - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin time: TimeLogic season: SeasonLogic gifts: GiftLogic @@ -34,7 +34,7 @@ class RelationshipLogic: def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, - received_logic: ReceivedLogic, has: HasLogic, region: RegionLogic, + received_logic: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): self.player = player self.friendsanity_option = friendsanity_option diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 19046fd8776a..6295a95177ff 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,7 +1,7 @@ from typing import Iterable from Utils import cache_self1 -from .received_logic import ReceivedLogic +from .received_logic import ReceivedLogicMixin from .time_logic import TimeLogic from ..options import SeasonRandomization from ..stardew_rule import StardewRule, True_, And, Or @@ -11,10 +11,10 @@ class SeasonLogic: season_option: SeasonRandomization - received: ReceivedLogic + received: ReceivedLogicMixin time: TimeLogic - def __init__(self, player: int, season_option: SeasonRandomization, received_logic: ReceivedLogic, time: TimeLogic): + def __init__(self, player: int, season_option: SeasonRandomization, received_logic: ReceivedLogicMixin, time: TimeLogic): self.player = player self.season_option = season_option self.received = received_logic diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 5fa24bdbcf3b..1318ed206d72 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -2,8 +2,8 @@ from Utils import cache_self1 from .building_logic import BuildingLogic -from .has_logic import HasLogic -from .region_logic import RegionLogic +from .has_logic import HasLogicMixin +from .region_logic import RegionLogicMixin from ..locations import LocationTags, locations_by_tag from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations @@ -17,12 +17,12 @@ class ShippingLogic: exclude_ginger_island: ExcludeGingerIsland special_orders_option: SpecialOrderLocations mods: Mods - has: HasLogic - region: RegionLogic + has: HasLogicMixin + region: RegionLogicMixin buildings: BuildingLogic - def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations,mods: Mods, has: HasLogic, - region: RegionLogic, buildings: BuildingLogic): + def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations,mods: Mods, has: HasLogicMixin, + region: RegionLogicMixin, buildings: BuildingLogic): self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_orders_option = special_orders_option diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index ef7d5d2c2043..7e949c8b1154 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -5,9 +5,9 @@ from worlds.stardew_valley.strings.craftable_names import Fishing from .combat_logic import CombatLogic from .crop_logic import CropLogic -from .has_logic import HasLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .has_logic import HasLogicMixin +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .season_logic import SeasonLogic from .time_logic import TimeLogic from .tool_logic import ToolLogic @@ -28,9 +28,9 @@ class SkillLogic: skill_option: SkillProgression - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin season: SeasonLogic time: TimeLogic tool: ToolLogic @@ -39,7 +39,8 @@ class SkillLogic: magic: MagicLogic mods: Mods - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, + season: SeasonLogic, time: TimeLogic, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): self.player = player self.skill_option = skill_option diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 82429231d4c3..77f51e355017 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -4,11 +4,11 @@ from .arcade_logic import ArcadeLogic from .artisan_logic import ArtisanLogic from .cooking_logic import CookingLogic -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .mine_logic import MineLogic from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogic from .shipping_logic import ShippingLogic @@ -36,9 +36,9 @@ class SpecialOrderLogic: player: int - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin season: SeasonLogic time: TimeLogic money: MoneyLogic @@ -53,7 +53,8 @@ class SpecialOrderLogic: ability: AbilityLogic special_order_rules: Dict[str, StardewRule] - def __init__(self, player: int, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, + def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogic, time: TimeLogic, + money: MoneyLogic, shipping: ShippingLogic, arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, tool: ToolLogic, skill: SkillLogic, mine: MineLogic, cooking: CookingLogic, ability: AbilityLogic): self.player = player diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 1fa014f77381..f241bb93682b 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,7 +1,7 @@ from functools import cached_property from Utils import cache_self1 -from .received_logic import ReceivedLogic +from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule, CountPercent, True_ from ..strings.ap_names.event_names import Event @@ -10,9 +10,9 @@ class TimeLogic: - received: ReceivedLogic + received: ReceivedLogicMixin - def __init__(self, player: int, received_logic: ReceivedLogic): + def __init__(self, player: int, received_logic: ReceivedLogicMixin): self.player = player self.received = received_logic diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index f7a7883d6d04..8ef2b403a8a6 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,8 +1,8 @@ from Utils import cache_self1 -from .has_logic import HasLogic +from .has_logic import HasLogicMixin from .money_logic import MoneyLogic -from .received_logic import ReceivedLogic -from .region_logic import RegionLogic +from .received_logic import ReceivedLogicMixin +from .region_logic import RegionLogicMixin from .season_logic import SeasonLogic from ..mods.logic.magic_logic import MagicLogic from ..options import ToolProgression @@ -29,14 +29,15 @@ class ToolLogic: tool_option = ToolProgression - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin season: SeasonLogic money: MoneyLogic magic: MagicLogic - def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, season: SeasonLogic, + def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, + season: SeasonLogic, money: MoneyLogic): self.player = player self.tool_option = tool_option diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index 4b8bf0583c12..c047c2caf15d 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,13 +1,13 @@ -from .received_logic import ReceivedLogic +from .received_logic import ReceivedLogicMixin from ..stardew_rule import True_ from ..strings.calendar_names import Weekday class TravelingMerchantLogic: player: int - received: ReceivedLogic + received: ReceivedLogicMixin - def __init__(self, player: int, received_logic: ReceivedLogic): + def __init__(self, player: int, received_logic: ReceivedLogicMixin): self.player = player self.received = received_logic diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index 97d7c9d27afb..fe936b081eee 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,17 +1,17 @@ from functools import cached_property from .museum_logic import MuseumLogic +from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule -from .received_logic import ReceivedLogic from ..strings.wallet_item_names import Wallet class WalletLogic: player: int - received = ReceivedLogic + received = ReceivedLogicMixin museum: MuseumLogic - def __init__(self, player: int, received: ReceivedLogic, museum: MuseumLogic): + def __init__(self, player: int, received: ReceivedLogicMixin, museum: MuseumLogic): self.player = player self.received = received self.museum = museum diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 45d4dcb1d11f..2c59c2a45da3 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -1,31 +1,31 @@ from typing import Dict -from ...stardew_rule import StardewRule -from ...logic.has_logic import HasLogic +from ..mod_data import ModNames +from ...logic.base_logic import LogicRegistry +from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogic from ...options import Mods +from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ArtisanGood from ...strings.building_names import ModBuilding -from ..mod_data import ModNames from ...strings.metal_names import MetalBar from ...strings.region_names import Region -class ModBuildingLogic: +class ModBuildingLogic(HasLogicMixin): player: int - has: HasLogic money: MoneyLogic mods_option: Mods - def __init__(self, player: int, has: HasLogic, money: MoneyLogic, mods_option: Mods): - self.player = player - self.has = has + def __init__(self, player: int, registry: LogicRegistry, money: MoneyLogic, mods_option: Mods): + super().__init__(player, registry) self.money = money self.mods_option = mods_option def get_modded_building_rules(self) -> Dict[str, StardewRule]: buildings = dict() if ModNames.tractor in self.mods_option: - tractor_rule = self.money.can_spend_at(Region.carpenter, 150000) & self.has(MetalBar.iron) & self.has(MetalBar.iridium) & self.has(ArtisanGood.battery_pack) + tractor_rule = self.money.can_spend_at(Region.carpenter, 150000) & self.has(MetalBar.iron) & self.has(MetalBar.iridium) & self.has( + ArtisanGood.battery_pack) buildings.update({ModBuilding.tractor_garage: tractor_rule}) return buildings diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index 19ed65b00adf..e65b5573322e 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -1,30 +1,31 @@ from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic -from ...logic.has_logic import HasLogic -from ...logic.received_logic import ReceivedLogic +from ...logic.has_logic import HasLogicMixin +from ...logic.received_logic import ReceivedLogicMixin from ...logic.skill_logic import SkillLogic from ...logic.tool_logic import ToolLogic from ...options import SkillProgression, ElevatorProgression +from ...stardew_rule import StardewRule, True_, And +from ...strings.ap_names.transport_names import ModTransportation from ...strings.craftable_names import Bomb from ...strings.performance_names import Performance from ...strings.skill_names import Skill from ...strings.tool_names import Tool, ToolMaterial -from ...strings.ap_names.transport_names import ModTransportation -from ...stardew_rule import StardewRule, True_, And class DeepWoodsLogic: player: int skill_option: SkillProgression elevator_option: ElevatorProgression - received: ReceivedLogic - has: HasLogic + received: ReceivedLogicMixin + has: HasLogicMixin combat: CombatLogic tool: ToolLogic skill: SkillLogic cooking: CookingLogic - def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogic, has: HasLogic, combat: CombatLogic, tool: ToolLogic, + def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogicMixin, has: HasLogicMixin, + combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, cooking: CookingLogic): self.player = player self.skill_option = skill_option diff --git a/worlds/stardew_valley/mods/logic/elevator_logic.py b/worlds/stardew_valley/mods/logic/elevator_logic.py index 8c4fc448b412..4abf17687c2f 100644 --- a/worlds/stardew_valley/mods/logic/elevator_logic.py +++ b/worlds/stardew_valley/mods/logic/elevator_logic.py @@ -1,16 +1,16 @@ -from ...logic.received_logic import ReceivedLogic +from ...logic.received_logic import ReceivedLogicMixin +from ...mods.mod_data import ModNames from ...options import ElevatorProgression, Mods from ...stardew_rule import StardewRule, True_ -from ...mods.mod_data import ModNames class ModElevatorLogic: player: int elevator_option: ElevatorProgression mods: Mods - received: ReceivedLogic + received: ReceivedLogicMixin - def __init__(self, player: int, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic): + def __init__(self, player: int, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogicMixin): self.player = player self.elevator_option = elevator_option self.mods = mods diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 29b525a3c663..f25f7569b3fb 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -1,33 +1,33 @@ from typing import Dict +from ..mod_data import ModNames from ...data.craftable_data import all_crafting_recipes_by_name from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic +from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic -from ...logic.has_logic import HasLogic +from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogic from ...logic.museum_logic import MuseumLogic -from ...logic.region_logic import RegionLogic +from ...logic.received_logic import ReceivedLogicMixin +from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic -from ...logic.received_logic import ReceivedLogic from ...logic.tool_logic import ToolLogic -from ...logic.crafting_logic import CraftingLogic from ...options import Mods -from ..mod_data import ModNames +from ...stardew_rule import StardewRule from ...strings.craftable_names import ModCraftable, ModEdible, ModMachine from ...strings.crop_names import SVEVegetable, SVEFruit from ...strings.food_names import SVEMeal, SVEBeverage -from ...strings.gift_names import SVEGift -from ...strings.tool_names import Tool, ToolMaterial from ...strings.forageable_names import SVEForage +from ...strings.gift_names import SVEGift from ...strings.metal_names import all_fossils, all_artifacts from ...strings.monster_drop_names import ModLoot +from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed -from ...strings.region_names import Region, SVERegion +from ...strings.tool_names import Tool, ToolMaterial from ...strings.villager_names import ModNPC -from ...stardew_rule import StardewRule display_types = [ModCraftable.wooden_display, ModCraftable.hardwood_display] display_items = all_artifacts + all_fossils @@ -38,18 +38,18 @@ class ModItemLogic: combat: CombatLogic crop: CropLogic cooking: CookingLogic - has: HasLogic + has: HasLogicMixin money: MoneyLogic - region: RegionLogic + region: RegionLogicMixin season: SeasonLogic relationship: RelationshipLogic museum: MuseumLogic - received: ReceivedLogic + received: ReceivedLogicMixin tool: ToolLogic crafting: CraftingLogic - def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogic, money: MoneyLogic, - region: RegionLogic, season: SeasonLogic, relationship: RelationshipLogic, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): + def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogicMixin, money: MoneyLogic, + region: RegionLogicMixin, season: SeasonLogic, relationship: RelationshipLogic, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): self.combat = combat self.crop = crop self.cooking = cooking @@ -79,7 +79,7 @@ def get_sve_item_rules(self): SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(SVESeed.stalk_seed), SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(SVESeed.fungus_seed), SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon & - self.tool.has_tool(Tool.axe,ToolMaterial.iron), + self.tool.has_tool(Tool.axe, ToolMaterial.iron), SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(SVESeed.slime_seed), SVESeed.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon, SVESeed.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon, diff --git a/worlds/stardew_valley/mods/logic/magic_logic.py b/worlds/stardew_valley/mods/logic/magic_logic.py index 255e1337cff0..3e7e08c239e7 100644 --- a/worlds/stardew_valley/mods/logic/magic_logic.py +++ b/worlds/stardew_valley/mods/logic/magic_logic.py @@ -1,20 +1,20 @@ -from ...logic.received_logic import ReceivedLogic -from ...logic.region_logic import RegionLogic +from ...logic.received_logic import ReceivedLogicMixin +from ...logic.region_logic import RegionLogicMixin +from ...mods.mod_data import ModNames from ...options import Mods +from ...stardew_rule import Count, StardewRule, False_ +from ...strings.ap_names.skill_level_names import ModSkillLevel from ...strings.region_names import MagicRegion -from ...mods.mod_data import ModNames from ...strings.spells import MagicSpell -from ...strings.ap_names.skill_level_names import ModSkillLevel -from ...stardew_rule import Count, StardewRule, False_ class MagicLogic: player: int mods: Mods - received: ReceivedLogic - region: RegionLogic + received: ReceivedLogicMixin + region: RegionLogicMixin - def __init__(self, player: int, mods: Mods, received: ReceivedLogic, region: RegionLogic): + def __init__(self, player: int, mods: Mods, received: ReceivedLogicMixin, region: RegionLogicMixin): self.player = player self.mods = mods self.received = received diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 18e1b29c5d54..f8bff41d6cdd 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -1,5 +1,3 @@ -from typing import List, Iterable - from .buildings_logic import ModBuildingLogic from .deepwoods_logic import DeepWoodsLogic from .elevator_logic import ModElevatorLogic @@ -12,19 +10,20 @@ from ...logic.ability_logic import AbilityLogic from ...logic.action_logic import ActionLogic from ...logic.artisan_logic import ArtisanLogic +from ...logic.base_logic import LogicRegistry, BaseLogic from ...logic.building_logic import BuildingLogic from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic from ...logic.fishing_logic import FishingLogic -from ...logic.has_logic import HasLogic +from ...logic.has_logic import HasLogicMixin from ...logic.mine_logic import MineLogic from ...logic.money_logic import MoneyLogic from ...logic.museum_logic import MuseumLogic from ...logic.quest_logic import QuestLogic -from ...logic.received_logic import ReceivedLogic -from ...logic.region_logic import RegionLogic +from ...logic.received_logic import ReceivedLogicMixin +from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic from ...logic.skill_logic import SkillLogic @@ -34,10 +33,10 @@ from ...options import SkillProgression, ElevatorProgression, Mods -class ModLogic: +class ModLogic(BaseLogic): items: ModItemLogic quests: ModQuestLogic - region: RegionLogic + region: RegionLogicMixin magic: MagicLogic buildings: ModBuildingLogic special_orders: ModSpecialOrderLogic @@ -46,19 +45,24 @@ class ModLogic: skill: ModSkillLogic sve: SVELogic - def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, - action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, museum: MuseumLogic, building: BuildingLogic, wallet: WalletLogic, + def __init__(self, player: int, registry: LogicRegistry, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, + received: ReceivedLogicMixin, + has: HasLogicMixin, region: RegionLogicMixin, + action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, museum: MuseumLogic, building: BuildingLogic, + wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): + super().__init__(player, registry) self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, museum, tool, crafting) self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) - self.buildings = ModBuildingLogic(player, has, money, mods) + self.buildings = ModBuildingLogic(player, registry, money, mods) self.special_orders = ModSpecialOrderLogic(player, action, artisan, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) self.skill = ModSkillLogic(player, skill_option, received, has, region, action, relationship, building, tool, fishing, cooking, self.magic, mods) - self.sve = SVELogic(player, skill_option, received, has, quest, region, action, relationship, building, tool, fishing, cooking, money, combat, season, time) + self.sve = SVELogic(player, skill_option, received, has, quest, region, action, relationship, building, tool, fishing, cooking, money, combat, season, + time) combat.set_magic(self.magic) tool.set_magic(self.magic) ability.set_magic(self.magic, self.skill) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index fd815e04b990..098c24418ce3 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -1,39 +1,39 @@ from typing import Dict -from ...logic.has_logic import HasLogic -from ...logic.region_logic import RegionLogic +from ..mod_data import ModNames +from ...logic.has_logic import HasLogicMixin +from ...logic.received_logic import ReceivedLogicMixin +from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic -from ...logic.received_logic import ReceivedLogic from ...logic.time_logic import TimeLogic from ...options import Mods -from ...strings.quest_names import ModQuest -from ..mod_data import ModNames +from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ArtisanGood from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable from ...strings.food_names import Meal, Beverage from ...strings.forageable_names import SVEForage -from ...strings.monster_drop_names import Loot -from ...strings.villager_names import ModNPC -from ...strings.season_names import Season -from ...strings.region_names import Region, SVERegion from ...strings.material_names import Material from ...strings.metal_names import Ore, MetalBar +from ...strings.monster_drop_names import Loot +from ...strings.quest_names import ModQuest +from ...strings.region_names import Region, SVERegion +from ...strings.season_names import Season +from ...strings.villager_names import ModNPC from ...strings.wallet_item_names import Wallet -from ...stardew_rule import StardewRule class ModQuestLogic: mods: Mods - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin time: TimeLogic season: SeasonLogic relationship: RelationshipLogic - def __init__(self, mods: Mods, received: ReceivedLogic, has: HasLogic, region: RegionLogic, time: TimeLogic, season: SeasonLogic, - relationship: RelationshipLogic,): + def __init__(self, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, time: TimeLogic, season: SeasonLogic, + relationship: RelationshipLogic, ): self.mods = mods self.received = received self.has = has diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 252c52d5b16f..eaa4d0548c1e 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -1,32 +1,32 @@ from .magic_logic import MagicLogic +from ...data.villagers_data import all_villagers from ...logic.action_logic import ActionLogic from ...logic.building_logic import BuildingLogic from ...logic.cooking_logic import CookingLogic from ...logic.fishing_logic import FishingLogic -from ...logic.has_logic import HasLogic -from ...logic.received_logic import ReceivedLogic -from ...logic.region_logic import RegionLogic +from ...logic.has_logic import HasLogicMixin +from ...logic.received_logic import ReceivedLogicMixin +from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic from ...logic.tool_logic import ToolLogic +from ...mods.mod_data import ModNames from ...options import SkillProgression, Mods +from ...stardew_rule import Count, StardewRule, False_, True_ from ...strings.building_names import Building from ...strings.geode_names import Geode +from ...strings.machine_names import Machine from ...strings.region_names import Region from ...strings.skill_names import ModSkill from ...strings.spells import MagicSpell -from ...strings.machine_names import Machine from ...strings.tool_names import Tool, ToolMaterial -from ...mods.mod_data import ModNames -from ...data.villagers_data import all_villagers -from ...stardew_rule import Count, StardewRule, False_, True_ class ModSkillLogic: player: int skill_option: SkillProgression - received: ReceivedLogic - has: HasLogic - region: RegionLogic + received: ReceivedLogicMixin + has: HasLogicMixin + region: RegionLogicMixin action: ActionLogic relationship: RelationshipLogic building: BuildingLogic @@ -36,7 +36,8 @@ class ModSkillLogic: magic: MagicLogic mods_option: Mods - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, region: RegionLogic, action: ActionLogic, + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, + action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, magic: MagicLogic, mods_option: Mods): self.player = player diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index caa3e3e068db..a58d422c1b70 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -1,30 +1,26 @@ -from typing import Iterable - +from ..mod_data import ModNames from ...logic.action_logic import ActionLogic from ...logic.artisan_logic import ArtisanLogic from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic -from ...logic.has_logic import HasLogic -from ...logic.region_logic import RegionLogic +from ...logic.has_logic import HasLogicMixin +from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic from ...logic.wallet_logic import WalletLogic from ...options import Mods from ...strings.artisan_good_names import ArtisanGood from ...strings.craftable_names import Consumable, Edible, Bomb +from ...strings.crop_names import Fruit from ...strings.fertilizer_names import Fertilizer -from ...strings.flower_names import Flower from ...strings.food_names import Meal -from ...strings.crop_names import Fruit from ...strings.geode_names import Geode -from ...strings.machine_names import Machine from ...strings.material_names import Material from ...strings.metal_names import MetalBar from ...strings.monster_drop_names import Loot from ...strings.region_names import Region, SVERegion from ...strings.special_order_names import SpecialOrder, ModSpecialOrder from ...strings.villager_names import ModNPC -from ..mod_data import ModNames class ModSpecialOrderLogic: @@ -33,14 +29,15 @@ class ModSpecialOrderLogic: artisan: ArtisanLogic crafting: CraftingLogic crop: CropLogic - has: HasLogic - region: RegionLogic + has: HasLogicMixin + region: RegionLogicMixin relationship: RelationshipLogic season: SeasonLogic wallet: WalletLogic mods_option: Mods - def __init__(self, player: int, action: ActionLogic, artisan: ArtisanLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogic, region: RegionLogic, relationship: RelationshipLogic, + def __init__(self, player: int, action: ActionLogic, artisan: ArtisanLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, + region: RegionLogicMixin, relationship: RelationshipLogic, season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): self.player = player self.action = action @@ -72,9 +69,11 @@ def get_modded_special_orders_rules(self, vanilla_rules): ModSpecialOrder.a_mysterious_venture: self.has(Bomb.cherry_bomb) & self.has(Bomb.bomb) & self.has(Bomb.mega_bomb) & self.region.can_reach(Region.adventurer_guild), ModSpecialOrder.an_elegant_reception: self.artisan.can_keg(Fruit.starfruit) & self.has(ArtisanGood.cheese) & - self.has(ArtisanGood.goat_cheese) & self.season.has_any_not_winter() & self.region.can_reach(SVERegion.jenkins_cellar), + self.has(ArtisanGood.goat_cheese) & self.season.has_any_not_winter() & self.region.can_reach( + SVERegion.jenkins_cellar), ModSpecialOrder.fairy_garden: self.has(Consumable.fairy_dust) & - self.region.can_reach(Region.island_south) & (self.action.can_open_geode(Geode.frozen) | self.action.can_open_geode(Geode.omni)) & + self.region.can_reach(Region.island_south) & ( + self.action.can_open_geode(Geode.frozen) | self.action.can_open_geode(Geode.omni)) & self.region.can_reach(SVERegion.blue_moon_vineyard), ModSpecialOrder.homemade_fertilizer: self.has(Fertilizer.quality) & self.region.can_reach(SVERegion.susans_house) }) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 797a71e3b692..86aea748be20 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -1,30 +1,30 @@ from typing import Dict +from ..mod_regions import SVERegion from ...logic.action_logic import ActionLogic from ...logic.building_logic import BuildingLogic from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic from ...logic.fishing_logic import FishingLogic -from ...logic.has_logic import HasLogic +from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogic from ...logic.quest_logic import QuestLogic -from ...logic.received_logic import ReceivedLogic -from ...logic.region_logic import RegionLogic +from ...logic.received_logic import ReceivedLogicMixin +from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic from ...logic.season_logic import SeasonLogic from ...logic.time_logic import TimeLogic from ...logic.tool_logic import ToolLogic -from ..mod_regions import SVERegion from ...options import SkillProgression from ...stardew_rule import StardewRule, Or class SVELogic: player: int - received: ReceivedLogic - has: HasLogic + received: ReceivedLogicMixin + has: HasLogicMixin quest: QuestLogic - region: RegionLogic + region: RegionLogicMixin relationship: RelationshipLogic time: TimeLogic tool: ToolLogic @@ -35,7 +35,9 @@ class SVELogic: season: SeasonLogic sve_location_rules: Dict[str, StardewRule] - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogic, has: HasLogic, quest: QuestLogic, region: RegionLogic, action: ActionLogic, + def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, quest: QuestLogic, + region: RegionLogicMixin, + action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, time: TimeLogic): self.player = player @@ -75,4 +77,3 @@ def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", "Nexus: Outpost Runes"] return Or(*(self.received(rune) for rune in rune_list)) - From 4fb4f999b47f075e1b0f5f9611ab28fc7fc3c9c9 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 19:22:38 -0500 Subject: [PATCH 186/482] more mixin --- worlds/stardew_valley/logic/artisan_logic.py | 6 +++--- worlds/stardew_valley/logic/building_logic.py | 6 +++--- worlds/stardew_valley/logic/bundle_logic.py | 6 +++--- worlds/stardew_valley/logic/cooking_logic.py | 14 ++++++------- worlds/stardew_valley/logic/crafting_logic.py | 10 ++++----- worlds/stardew_valley/logic/crop_logic.py | 14 ++++++------- worlds/stardew_valley/logic/fishing_logic.py | 6 +++--- worlds/stardew_valley/logic/logic.py | 19 +++++++++-------- worlds/stardew_valley/logic/money_logic.py | 21 +++++++------------ worlds/stardew_valley/logic/monster_logic.py | 6 +++--- worlds/stardew_valley/logic/pet_logic.py | 6 +++--- worlds/stardew_valley/logic/quest_logic.py | 14 ++++++------- worlds/stardew_valley/logic/region_logic.py | 1 + .../logic/relationship_logic.py | 10 ++++----- worlds/stardew_valley/logic/season_logic.py | 19 ++++++++--------- worlds/stardew_valley/logic/skill_logic.py | 12 +++++------ .../logic/special_order_logic.py | 16 +++++++------- worlds/stardew_valley/logic/time_logic.py | 11 +++++----- worlds/stardew_valley/logic/tool_logic.py | 12 +++++------ .../logic/traveling_merchant_logic.py | 10 ++++----- .../mods/logic/buildings_logic.py | 6 +++--- .../stardew_valley/mods/logic/item_logic.py | 13 ++++++------ worlds/stardew_valley/mods/logic/mod_logic.py | 11 +++++----- .../stardew_valley/mods/logic/quests_logic.py | 10 ++++----- .../mods/logic/special_orders_logic.py | 6 +++--- worlds/stardew_valley/mods/logic/sve_logic.py | 14 ++++++------- worlds/stardew_valley/strings/season_names.py | 2 +- 27 files changed, 137 insertions(+), 144 deletions(-) diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 6d98637a1c42..ecde1eb63543 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -1,5 +1,5 @@ from .has_logic import HasLogicMixin -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from ..stardew_rule import StardewRule from ..strings.crop_names import all_vegetables, all_fruits, Vegetable, Fruit from ..strings.generic_names import Generic @@ -9,9 +9,9 @@ class ArtisanLogic: player: int has: HasLogicMixin - time: TimeLogic + time: TimeLogicMixin - def __init__(self, player: int, has: HasLogicMixin, time: TimeLogic): + def __init__(self, player: int, has: HasLogicMixin, time: TimeLogicMixin): self.player = player self.has = has self.time = time diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index aba4cdb66099..e983f93c3fe2 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -2,7 +2,7 @@ from Utils import cache_self1 from .has_logic import HasLogicMixin -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from ..options import BuildingProgression @@ -22,11 +22,11 @@ class BuildingLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - money: MoneyLogic + money: MoneyLogicMixin building_rules: Dict[str, StardewRule] def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - money: MoneyLogic): + money: MoneyLogicMixin): self.player = player self.player = player self.building_option = building_option diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 45ae765e3e8b..826256573e1d 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -3,7 +3,7 @@ from .farming_logic import FarmingLogic from .has_logic import HasLogicMixin -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .region_logic import RegionLogicMixin from ..data.bundle_data import BundleItem from ..stardew_rule import StardewRule @@ -13,10 +13,10 @@ class BundleLogic: has: HasLogicMixin region: RegionLogicMixin - money: MoneyLogic + money: MoneyLogicMixin farming: FarmingLogic - def __init__(self, player: int, has: HasLogicMixin, region: RegionLogicMixin, money: MoneyLogic, farming: FarmingLogic): + def __init__(self, player: int, has: HasLogicMixin, region: RegionLogicMixin, money: MoneyLogicMixin, farming: FarmingLogic): self.player = player self.has = has self.region = region diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 1e5e50d77658..2c0a6e2b1945 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -4,13 +4,13 @@ from .action_logic import ActionLogic from .building_logic import BuildingLogic from .has_logic import HasLogicMixin -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogic -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \ QueenOfSauceSource, CookingRecipe, \ all_cooking_recipes_by_name @@ -31,16 +31,16 @@ class CookingLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - season: SeasonLogic - time: TimeLogic - money: MoneyLogic + season: SeasonLogicMixin + time: TimeLogicMixin + money: MoneyLogicMixin action: ActionLogic buildings: BuildingLogic relationship: RelationshipLogic skill: SkillLogic def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogicMixin, - has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogic, time: TimeLogic, money: MoneyLogic, action: ActionLogic, + has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, action: ActionLogic, buildings: BuildingLogic, relationship: RelationshipLogic, skill: SkillLogic): self.player = player diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index c2185e8055f3..8d7ca63ddf1a 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -2,13 +2,13 @@ from Utils import cache_self1 from .has_logic import HasLogicMixin -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .skill_logic import SkillLogic from .special_order_logic import SpecialOrderLogic -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from .. import options from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name from ..data.recipe_data import StarterSource, ShopSource, SkillSource, FriendshipSource @@ -29,8 +29,8 @@ class CraftingLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - time: TimeLogic - money: MoneyLogic + time: TimeLogicMixin + money: MoneyLogicMixin relationship: RelationshipLogic skill: SkillLogic special_orders: SpecialOrderLogic @@ -38,7 +38,7 @@ class CraftingLogic: def __init__(self, player: int, craftsanity_option: Craftsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - time: TimeLogic, money: MoneyLogic, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): + time: TimeLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): self.player = player self.craftsanity_option = craftsanity_option self.exclude_ginger_island = exclude_ginger_island diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 383ec7f4c99b..c97fea4c3b88 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -2,12 +2,12 @@ from Utils import cache_self1 from .has_logic import HasLogicMixin -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from .tool_logic import ToolLogic -from .traveling_merchant_logic import TravelingMerchantLogic +from .traveling_merchant_logic import TravelingMerchantLogicMixin from ..data import CropItem, SeedItem from ..options import Cropsanity, ExcludeGingerIsland from ..stardew_rule import StardewRule, True_, False_ @@ -25,14 +25,14 @@ class CropLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - traveling_merchant: TravelingMerchantLogic - season: SeasonLogic - money: MoneyLogic + traveling_merchant: TravelingMerchantLogicMixin + season: SeasonLogicMixin + money: MoneyLogicMixin tool: ToolLogic def __init__(self, player: int, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogicMixin, has: HasLogicMixin, - region: RegionLogicMixin, traveling_merchant: TravelingMerchantLogic, season: SeasonLogic, money: MoneyLogic, tool: ToolLogic): + region: RegionLogicMixin, traveling_merchant: TravelingMerchantLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, tool: ToolLogic): self.player = player self.cropsanity_option = cropsanity_option self.exclude_ginger_island_option = exclude_ginger_island_option diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index b42e9e2107e5..8ee7791906c3 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,7 +1,7 @@ from Utils import cache_self1 from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogic from .tool_logic import ToolLogic from ..data import FishItem @@ -19,12 +19,12 @@ class FishingLogic: special_order_locations: SpecialOrderLocations received: ReceivedLogicMixin region: RegionLogicMixin - season: SeasonLogic + season: SeasonLogicMixin tool: ToolLogic skill: SkillLogic def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, received: ReceivedLogicMixin, - region: RegionLogicMixin, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): + region: RegionLogicMixin, season: SeasonLogicMixin, tool: ToolLogic, skill: SkillLogic): self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_order_locations = special_order_locations diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9ed776a3fd62..3e77f1e27795 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -19,7 +19,7 @@ from .gift_logic import GiftLogic from .has_logic import HasLogicMixin from .mine_logic import MineLogic -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .monster_logic import MonsterLogic from .museum_logic import MuseumLogic from .pet_logic import PetLogic @@ -27,13 +27,13 @@ from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogic from .skill_logic import SkillLogic from .special_order_logic import SpecialOrderLogic -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic -from .traveling_merchant_logic import TravelingMerchantLogic +from .traveling_merchant_logic import TravelingMerchantLogicMixin from .wallet_logic import WalletLogic from ..data import all_fish, all_purchasable_seeds, all_crops from ..data.craftable_data import all_crafting_recipes @@ -97,10 +97,10 @@ def __post_init__(self): self.received = ReceivedLogicMixin(self.player, self.registry) self.has = HasLogicMixin(self.player, self.registry) self.region = RegionLogicMixin(self.player, self.registry) - self.traveling_merchant = TravelingMerchantLogic(self.player, self.received) - self.time = TimeLogic(self.player, self.received) - self.season = SeasonLogic(self.player, self.options.season_randomization, self.received, self.time) - self.money = MoneyLogic(self.player, self.options.starting_money, self.received, self.has, self.region, self.time) + self.traveling_merchant = TravelingMerchantLogicMixin(self.player, self.registry) + self.time = TimeLogicMixin(self.player, self.registry) + self.season = SeasonLogicMixin(self.player, self.registry, self.options.season_randomization) + self.money = MoneyLogicMixin(self.player, self.registry, self.options.starting_money) self.action = ActionLogic(self.player, self.received, self.has, self.region) self.arcade = ArcadeLogic(self.player, self.options.arcade_machine_locations, self.received, self.region) self.artisan = ArtisanLogic(self.player, self.has, self.time) @@ -148,7 +148,8 @@ def __post_init__(self): self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, self.registry, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, - self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, + self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, + self.fishing, self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 8a7bce79fe70..ea604b1c28bc 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,8 +1,9 @@ from Utils import cache_self1 +from .base_logic import LogicRegistry from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from ..options import StartingMoney from ..stardew_rule import StardewRule, True_, CountPercent from ..strings.currency_names import Currency @@ -12,21 +13,13 @@ "25 Qi Gems", "20 Qi Gems", "10 Qi Gems") -class MoneyLogic: +class MoneyLogicMixin(TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): starting_money_option: StartingMoney - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - time: TimeLogic - - def __init__(self, player: int, starting_money_option: StartingMoney, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - time: TimeLogic): - self.player = player + + def __init__(self, player: int, registry: LogicRegistry, starting_money_option: StartingMoney): + super().__init__(player, registry) self.starting_money_option = starting_money_option - self.received = received - self.has = has - self.region = region - self.time = time + self.money = self @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 3aeb0bf4c02b..f32a9999354e 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -3,17 +3,17 @@ from Utils import cache_self1 from .combat_logic import CombatLogic from .region_logic import RegionLogicMixin -from .time_logic import TimeLogic, MAX_MONTHS +from .time_logic import TimeLogicMixin, MAX_MONTHS from ..data.monster_data import StardewMonster, all_monsters_by_name from ..stardew_rule import StardewRule, Or, And class MonsterLogic: region: RegionLogicMixin - time: TimeLogic + time: TimeLogicMixin combat: CombatLogic - def __init__(self, player: int, region: RegionLogicMixin, time: TimeLogic, combat: CombatLogic): + def __init__(self, player: int, region: RegionLogicMixin, time: TimeLogicMixin, combat: CombatLogic): self.player = player self.region = region self.time = time diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index 0aff9d9ec7a4..f6e1d75b2fa3 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -3,7 +3,7 @@ from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic from ..data.villagers_data import Villager from ..options import Friendsanity, FriendsanityHeartSize @@ -17,11 +17,11 @@ class PetLogic: heart_size_option: FriendsanityHeartSize received: ReceivedLogicMixin region: RegionLogicMixin - time: TimeLogic + time: TimeLogicMixin tool: ToolLogic def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, - received_logic: ReceivedLogicMixin, region: RegionLogicMixin, time: TimeLogic, tool: ToolLogic): + received_logic: ReceivedLogicMixin, region: RegionLogicMixin, time: TimeLogicMixin, tool: ToolLogic): self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 17013d433d13..1cf61ac74bbf 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -7,13 +7,13 @@ from .fishing_logic import FishingLogic from .has_logic import HasLogicMixin from .mine_logic import MineLogic -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogic -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic from .wallet_logic import WalletLogic from ..options import Mods @@ -48,17 +48,17 @@ class QuestLogic: fishing: FishingLogic cooking: CookingLogic mods_option: Mods - money: MoneyLogic + money: MoneyLogicMixin combat: CombatLogic - season: SeasonLogic + season: SeasonLogicMixin skill: SkillLogic wallet: WalletLogic quest_rules: Dict[str, StardewRule] def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogicMixin, has: HasLogicMixin, mine: MineLogic, region: RegionLogicMixin, action: ActionLogic, - relationship: RelationshipLogic, building: BuildingLogic, time: TimeLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): + relationship: RelationshipLogic, building: BuildingLogic, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): self.player = player self.skill = skill self.received = received diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index c6411efa3cb1..1528666b1f86 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -9,6 +9,7 @@ class RegionLogicMixin(BaseLogic): def __init__(self, player: int, registry: LogicRegistry): super().__init__(player, registry) + self.region = self @cache_self1 def can_reach(self, region_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 8b8abba5abd7..368f311bd0ca 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -7,8 +7,8 @@ from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic -from .time_logic import TimeLogic +from .season_logic import SeasonLogicMixin +from .time_logic import TimeLogicMixin from ..data.villagers_data import all_villagers_by_name, Villager from ..options import Friendsanity, FriendsanityHeartSize, Mods from ..stardew_rule import StardewRule, True_, And, Or, Count @@ -26,8 +26,8 @@ class RelationshipLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - time: TimeLogic - season: SeasonLogic + time: TimeLogicMixin + season: SeasonLogicMixin gifts: GiftLogic buildings: BuildingLogic mods_option: Mods @@ -35,7 +35,7 @@ class RelationshipLogic: def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - time: TimeLogic, season: SeasonLogic, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): + time: TimeLogicMixin, season: SeasonLogicMixin, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 6295a95177ff..04c74e08600a 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,24 +1,23 @@ from typing import Iterable from Utils import cache_self1 +from .base_logic import LogicRegistry from .received_logic import ReceivedLogicMixin -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from ..options import SeasonRandomization from ..stardew_rule import StardewRule, True_, And, Or from ..strings.generic_names import Generic from ..strings.season_names import Season -class SeasonLogic: +class SeasonLogicMixin(TimeLogicMixin, ReceivedLogicMixin): season_option: SeasonRandomization - received: ReceivedLogicMixin - time: TimeLogic - def __init__(self, player: int, season_option: SeasonRandomization, received_logic: ReceivedLogicMixin, time: TimeLogic): + def __init__(self, player: int, registry: LogicRegistry, season_option: SeasonRandomization): + super().__init__(player, registry) self.player = player self.season_option = season_option - self.received = received_logic - self.time = time + self.season = self @cache_self1 def has(self, season: str) -> StardewRule: @@ -36,12 +35,12 @@ def has(self, season: str) -> StardewRule: def has_any(self, seasons: Iterable[str]): if not seasons: return True_() - return Or(*(self.has(season) for season in seasons)) + return Or(*(self.season.has(season) for season in seasons)) def has_any_not_winter(self): - return self.has_any([Season.spring, Season.summer, Season.fall]) + return self.season.has_any([Season.spring, Season.summer, Season.fall]) def has_all(self, seasons: Iterable[str]): if not seasons: return True_() - return And(*(self.has(season) for season in seasons)) + return And(*(self.season.has(season) for season in seasons)) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 7e949c8b1154..8fadeca1e5ae 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -8,8 +8,8 @@ from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic -from .time_logic import TimeLogic +from .season_logic import SeasonLogicMixin +from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic from .. import options from ..data import all_crops @@ -31,8 +31,8 @@ class SkillLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - season: SeasonLogic - time: TimeLogic + season: SeasonLogicMixin + time: TimeLogicMixin tool: ToolLogic combat: CombatLogic crop: CropLogic @@ -40,8 +40,8 @@ class SkillLogic: mods: Mods def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - season: SeasonLogic, - time: TimeLogic, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): + season: SeasonLogicMixin, + time: TimeLogicMixin, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): self.player = player self.skill_option = skill_option self.received = received diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 77f51e355017..47ffe5d369fa 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -6,14 +6,14 @@ from .cooking_logic import CookingLogic from .has_logic import HasLogicMixin from .mine_logic import MineLogic -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogic from .skill_logic import SkillLogic -from .time_logic import TimeLogic +from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic from ..stardew_rule import StardewRule, Has from ..strings.animal_product_names import AnimalProduct @@ -39,9 +39,9 @@ class SpecialOrderLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - season: SeasonLogic - time: TimeLogic - money: MoneyLogic + season: SeasonLogicMixin + time: TimeLogicMixin + money: MoneyLogicMixin shipping: ShippingLogic arcade: ArcadeLogic artisan: ArtisanLogic @@ -53,8 +53,8 @@ class SpecialOrderLogic: ability: AbilityLogic special_order_rules: Dict[str, StardewRule] - def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogic, time: TimeLogic, - money: MoneyLogic, + def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, + money: MoneyLogicMixin, shipping: ShippingLogic, arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, tool: ToolLogic, skill: SkillLogic, mine: MineLogic, cooking: CookingLogic, ability: AbilityLogic): self.player = player diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index f241bb93682b..a799ee85dfa8 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,6 +1,7 @@ from functools import cached_property from Utils import cache_self1 +from .base_logic import LogicRegistry from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule, CountPercent, True_ from ..strings.ap_names.event_names import Event @@ -9,12 +10,10 @@ MONTH_COEFFICIENT = 100 // MAX_MONTHS -class TimeLogic: - received: ReceivedLogicMixin - - def __init__(self, player: int, received_logic: ReceivedLogicMixin): - self.player = player - self.received = received_logic +class TimeLogicMixin(ReceivedLogicMixin): + def __init__(self, player: int, registry: LogicRegistry): + super().__init__(player, registry) + self.time = self @cache_self1 def has_lived_months(self, number: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 8ef2b403a8a6..2fbb6fc6e77e 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,9 +1,9 @@ from Utils import cache_self1 from .has_logic import HasLogicMixin -from .money_logic import MoneyLogic +from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic +from .season_logic import SeasonLogicMixin from ..mods.logic.magic_logic import MagicLogic from ..options import ToolProgression from ..stardew_rule import StardewRule, True_ @@ -32,13 +32,13 @@ class ToolLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - season: SeasonLogic - money: MoneyLogic + season: SeasonLogicMixin + money: MoneyLogicMixin magic: MagicLogic def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - season: SeasonLogic, - money: MoneyLogic): + season: SeasonLogicMixin, + money: MoneyLogicMixin): self.player = player self.tool_option = tool_option self.received = received diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index c047c2caf15d..d951a5fde284 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,15 +1,13 @@ +from .base_logic import LogicRegistry from .received_logic import ReceivedLogicMixin from ..stardew_rule import True_ from ..strings.calendar_names import Weekday -class TravelingMerchantLogic: - player: int - received: ReceivedLogicMixin +class TravelingMerchantLogicMixin(ReceivedLogicMixin): - def __init__(self, player: int, received_logic: ReceivedLogicMixin): - self.player = player - self.received = received_logic + def __init__(self, player: int, registry: LogicRegistry): + super().__init__(player, registry) def has_days(self, number_days: int = 1): if number_days <= 0: diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 2c59c2a45da3..13b9dc1bf6b2 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -3,7 +3,7 @@ from ..mod_data import ModNames from ...logic.base_logic import LogicRegistry from ...logic.has_logic import HasLogicMixin -from ...logic.money_logic import MoneyLogic +from ...logic.money_logic import MoneyLogicMixin from ...options import Mods from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ArtisanGood @@ -14,10 +14,10 @@ class ModBuildingLogic(HasLogicMixin): player: int - money: MoneyLogic + money: MoneyLogicMixin mods_option: Mods - def __init__(self, player: int, registry: LogicRegistry, money: MoneyLogic, mods_option: Mods): + def __init__(self, player: int, registry: LogicRegistry, money: MoneyLogicMixin, mods_option: Mods): super().__init__(player, registry) self.money = money self.mods_option = mods_option diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index f25f7569b3fb..1b22f42c7a9d 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -7,12 +7,12 @@ from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogicMixin -from ...logic.money_logic import MoneyLogic +from ...logic.money_logic import MoneyLogicMixin from ...logic.museum_logic import MuseumLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic -from ...logic.season_logic import SeasonLogic +from ...logic.season_logic import SeasonLogicMixin from ...logic.tool_logic import ToolLogic from ...options import Mods from ...stardew_rule import StardewRule @@ -39,17 +39,18 @@ class ModItemLogic: crop: CropLogic cooking: CookingLogic has: HasLogicMixin - money: MoneyLogic + money: MoneyLogicMixin region: RegionLogicMixin - season: SeasonLogic + season: SeasonLogicMixin relationship: RelationshipLogic museum: MuseumLogic received: ReceivedLogicMixin tool: ToolLogic crafting: CraftingLogic - def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogicMixin, money: MoneyLogic, - region: RegionLogicMixin, season: SeasonLogic, relationship: RelationshipLogic, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): + def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogicMixin, money: MoneyLogicMixin, + region: RegionLogicMixin, + season: SeasonLogicMixin, relationship: RelationshipLogic, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): self.combat = combat self.crop = crop self.cooking = cooking diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index f8bff41d6cdd..b81d89cb23a7 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -19,15 +19,15 @@ from ...logic.fishing_logic import FishingLogic from ...logic.has_logic import HasLogicMixin from ...logic.mine_logic import MineLogic -from ...logic.money_logic import MoneyLogic +from ...logic.money_logic import MoneyLogicMixin from ...logic.museum_logic import MuseumLogic from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic -from ...logic.season_logic import SeasonLogic +from ...logic.season_logic import SeasonLogicMixin from ...logic.skill_logic import SkillLogic -from ...logic.time_logic import TimeLogic +from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogic from ...logic.wallet_logic import WalletLogic from ...options import SkillProgression, ElevatorProgression, Mods @@ -48,10 +48,11 @@ class ModLogic(BaseLogic): def __init__(self, player: int, registry: LogicRegistry, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogic, money: MoneyLogic, relationship: RelationshipLogic, museum: MuseumLogic, building: BuildingLogic, + action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogic, + museum: MuseumLogic, building: BuildingLogic, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, - time: TimeLogic, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): + time: TimeLogicMixin, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): super().__init__(player, registry) self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, museum, tool, crafting) self.magic = MagicLogic(player, mods, received, region) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 098c24418ce3..229f3dbda7a3 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -5,8 +5,8 @@ from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic -from ...logic.season_logic import SeasonLogic -from ...logic.time_logic import TimeLogic +from ...logic.season_logic import SeasonLogicMixin +from ...logic.time_logic import TimeLogicMixin from ...options import Mods from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ArtisanGood @@ -28,11 +28,11 @@ class ModQuestLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - time: TimeLogic - season: SeasonLogic + time: TimeLogicMixin + season: SeasonLogicMixin relationship: RelationshipLogic - def __init__(self, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, time: TimeLogic, season: SeasonLogic, + def __init__(self, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, time: TimeLogicMixin, season: SeasonLogicMixin, relationship: RelationshipLogic, ): self.mods = mods self.received = received diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index a58d422c1b70..b3639699de49 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -6,7 +6,7 @@ from ...logic.has_logic import HasLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic -from ...logic.season_logic import SeasonLogic +from ...logic.season_logic import SeasonLogicMixin from ...logic.wallet_logic import WalletLogic from ...options import Mods from ...strings.artisan_good_names import ArtisanGood @@ -32,13 +32,13 @@ class ModSpecialOrderLogic: has: HasLogicMixin region: RegionLogicMixin relationship: RelationshipLogic - season: SeasonLogic + season: SeasonLogicMixin wallet: WalletLogic mods_option: Mods def __init__(self, player: int, action: ActionLogic, artisan: ArtisanLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, region: RegionLogicMixin, relationship: RelationshipLogic, - season: SeasonLogic, wallet: WalletLogic, mods_option: Mods): + season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): self.player = player self.action = action self.artisan = artisan diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 86aea748be20..606cdbcd4d6e 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -7,13 +7,13 @@ from ...logic.cooking_logic import CookingLogic from ...logic.fishing_logic import FishingLogic from ...logic.has_logic import HasLogicMixin -from ...logic.money_logic import MoneyLogic +from ...logic.money_logic import MoneyLogicMixin from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogic -from ...logic.season_logic import SeasonLogic -from ...logic.time_logic import TimeLogic +from ...logic.season_logic import SeasonLogicMixin +from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogic from ...options import SkillProgression from ...stardew_rule import StardewRule, Or @@ -26,20 +26,20 @@ class SVELogic: quest: QuestLogic region: RegionLogicMixin relationship: RelationshipLogic - time: TimeLogic + time: TimeLogicMixin tool: ToolLogic fishing: FishingLogic cooking: CookingLogic - money: MoneyLogic + money: MoneyLogicMixin combat: CombatLogic - season: SeasonLogic + season: SeasonLogicMixin sve_location_rules: Dict[str, StardewRule] def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, quest: QuestLogic, region: RegionLogicMixin, action: ActionLogic, relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - money: MoneyLogic, combat: CombatLogic, season: SeasonLogic, time: TimeLogic): + money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, time: TimeLogicMixin): self.player = player self.skill_option = skill_option self.received = received diff --git a/worlds/stardew_valley/strings/season_names.py b/worlds/stardew_valley/strings/season_names.py index 93c58fceb26c..5042c271e5bb 100644 --- a/worlds/stardew_valley/strings/season_names.py +++ b/worlds/stardew_valley/strings/season_names.py @@ -3,4 +3,4 @@ class Season: summer = "Summer" fall = "Fall" winter = "Winter" - progressive = "Progressive Season" \ No newline at end of file + progressive = "Progressive Season" From 9bab0aae2c10c8cc4d8b165adee6cd070d35a132 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 20:16:00 -0500 Subject: [PATCH 187/482] more mixin --- worlds/stardew_valley/logic/action_logic.py | 14 ++--- worlds/stardew_valley/logic/arcade_logic.py | 24 +++----- worlds/stardew_valley/logic/artisan_logic.py | 21 +++---- worlds/stardew_valley/logic/base_logic.py | 6 +- worlds/stardew_valley/logic/building_logic.py | 55 +++++++------------ worlds/stardew_valley/logic/cooking_logic.py | 12 ++-- worlds/stardew_valley/logic/gift_logic.py | 10 ++-- worlds/stardew_valley/logic/has_logic.py | 8 +-- worlds/stardew_valley/logic/logic.py | 47 ++++++++-------- worlds/stardew_valley/logic/money_logic.py | 15 ++--- worlds/stardew_valley/logic/museum_logic.py | 6 +- worlds/stardew_valley/logic/quest_logic.py | 9 +-- worlds/stardew_valley/logic/received_logic.py | 6 +- worlds/stardew_valley/logic/region_logic.py | 13 ++--- .../logic/relationship_logic.py | 10 ++-- worlds/stardew_valley/logic/season_logic.py | 13 ++--- worlds/stardew_valley/logic/shipping_logic.py | 32 +++-------- .../logic/special_order_logic.py | 15 ++--- worlds/stardew_valley/logic/time_logic.py | 5 +- .../logic/traveling_merchant_logic.py | 7 +-- .../mods/logic/buildings_logic.py | 17 ++---- worlds/stardew_valley/mods/logic/mod_logic.py | 16 +++--- .../stardew_valley/mods/logic/skills_logic.py | 12 ++-- .../mods/logic/special_orders_logic.py | 10 ++-- worlds/stardew_valley/mods/logic/sve_logic.py | 8 +-- worlds/stardew_valley/rules.py | 23 ++++---- worlds/stardew_valley/test/TestLogic.py | 4 +- 27 files changed, 175 insertions(+), 243 deletions(-) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index e70e7fa1a5f6..e200f6f30e44 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -8,16 +8,10 @@ from ..strings.region_names import Region -class ActionLogic: - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - - def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin): - self.player = player - self.received = received - self.has = has - self.region = region +class ActionLogicMixin(RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.action = self def can_watch(self, channel: str = None): tv_rule = True_() diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index eae7ce67be17..54d8f5cf573f 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,36 +1,28 @@ from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .. import options -from ..options import ArcadeMachineLocations from ..stardew_rule import StardewRule, True_ from ..strings.region_names import Region -class ArcadeLogic: - player: int - arcade_option: ArcadeMachineLocations - received = ReceivedLogicMixin - region: RegionLogicMixin - - def __init__(self, player: int, arcade_option: ArcadeMachineLocations, received: ReceivedLogicMixin, region: RegionLogicMixin): - self.player = player - self.arcade_option = arcade_option - self.received = received - self.region = region +class ArcadeLogicMixin(RegionLogicMixin, ReceivedLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.arcade = self def has_jotpk_power_level(self, power_level: int) -> StardewRule: - if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: + if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return True_() jotpk_buffs = ("JotPK: Progressive Boots", "JotPK: Progressive Gun", "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate") return self.received(jotpk_buffs, power_level) def has_junimo_kart_power_level(self, power_level: int) -> StardewRule: - if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: + if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return True_() return self.received("Junimo Kart: Extra Life", power_level) def has_junimo_kart_max_level(self) -> StardewRule: play_rule = self.region.can_reach(Region.junimo_kart_3) - if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling: + if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return play_rule - return self.has_junimo_kart_power_level(8) + return self.arcade.has_junimo_kart_power_level(8) diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index ecde1eb63543..2d753d5ec583 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -6,21 +6,16 @@ from ..strings.machine_names import Machine -class ArtisanLogic: - player: int - has: HasLogicMixin - time: TimeLogicMixin - - def __init__(self, player: int, has: HasLogicMixin, time: TimeLogicMixin): - self.player = player - self.has = has - self.time = time +class ArtisanLogicMixin(TimeLogicMixin, HasLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.artisan = self def has_jelly(self) -> StardewRule: - return self.can_preserves_jar(Fruit.any) + return self.artisan.can_preserves_jar(Fruit.any) def has_pickle(self) -> StardewRule: - return self.can_preserves_jar(Vegetable.any) + return self.artisan.can_preserves_jar(Vegetable.any) def can_preserves_jar(self, item: str) -> StardewRule: machine_rule = self.has(Machine.preserves_jar) @@ -33,10 +28,10 @@ def can_preserves_jar(self, item: str) -> StardewRule: return machine_rule & self.has(item) def has_wine(self) -> StardewRule: - return self.can_keg(Fruit.any) + return self.artisan.can_keg(Fruit.any) def has_juice(self) -> StardewRule: - return self.can_keg(Vegetable.any) + return self.artisan.can_keg(Vegetable.any) def can_keg(self, item: str) -> StardewRule: machine_rule = self.has(Machine.keg) diff --git a/worlds/stardew_valley/logic/base_logic.py b/worlds/stardew_valley/logic/base_logic.py index 2d315ba963a7..63af8042a440 100644 --- a/worlds/stardew_valley/logic/base_logic.py +++ b/worlds/stardew_valley/logic/base_logic.py @@ -11,6 +11,7 @@ class LogicRegistry: options: StardewValleyOptions item_rules: Dict[str, StardewRule] = field(default_factory=dict) + sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) seed_rules: Dict[str, StardewRule] = field(default_factory=dict) @@ -21,12 +22,15 @@ class LogicRegistry: museum_rules: Dict[str, StardewRule] = field(default_factory=dict) festival_rules: Dict[str, StardewRule] = field(default_factory=dict) quest_rules: Dict[str, StardewRule] = field(default_factory=dict) + building_rules: Dict[str, StardewRule] = field(default_factory=dict) class BaseLogic: player: int registry: LogicRegistry + options: StardewValleyOptions - def __init__(self, player: int, registry: LogicRegistry): + def __init__(self, player: int, registry: LogicRegistry, options: StardewValleyOptions): self.player = player self.registry = registry + self.options = options diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index e983f93c3fe2..72c11c6f3282 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -16,58 +16,43 @@ from ..strings.region_names import Region -class BuildingLogic: - player: int - building_option: BuildingProgression - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - money: MoneyLogicMixin - building_rules: Dict[str, StardewRule] - - def __init__(self, player: int, building_option: BuildingProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - money: MoneyLogicMixin): - self.player = player - self.player = player - self.building_option = building_option - self.received = received - self.has = has - self.region = region - self.money = money - self.building_rules = dict() +class BuildingLogicMixin(MoneyLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.buildings = self def initialize_rules(self): - self.building_rules.update({ + self.registry.building_rules.update({ # @formatter:off Building.barn: self.money.can_spend(6000) & self.has((Material.wood, Material.stone)), - Building.big_barn: self.money.can_spend(12000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.barn), - Building.deluxe_barn: self.money.can_spend(25000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_barn), + Building.big_barn: self.money.can_spend(12000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.barn), + Building.deluxe_barn: self.money.can_spend(25000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.big_barn), Building.coop: self.money.can_spend(4000) & self.has((Material.wood, Material.stone)), - Building.big_coop: self.money.can_spend(10000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.coop), - Building.deluxe_coop: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_coop), + Building.big_coop: self.money.can_spend(10000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.coop), + Building.deluxe_coop: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.big_coop), Building.fish_pond: self.money.can_spend(5000) & self.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), Building.mill: self.money.can_spend(2500) & self.has((Material.stone, Material.wood, ArtisanGood.cloth)), Building.shed: self.money.can_spend(15000) & self.has(Material.wood), - Building.big_shed: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.shed), + Building.big_shed: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.shed), Building.silo: self.money.can_spend(100) & self.has((Material.stone, Material.clay, MetalBar.copper)), Building.slime_hutch: self.money.can_spend(10000) & self.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), Building.stable: self.money.can_spend(10000) & self.has((Material.hardwood, MetalBar.iron)), Building.well: self.money.can_spend(1000) & self.has(Material.stone), Building.shipping_bin: self.money.can_spend(250) & self.has(Material.wood), - Building.kitchen: self.money.can_spend(10000) & self.has(Material.wood) & self.has_house(0), - Building.kids_room: self.money.can_spend(50000) & self.has(Material.hardwood) & self.has_house(1), - Building.cellar: self.money.can_spend(100000) & self.has_house(2), + Building.kitchen: self.money.can_spend(10000) & self.has(Material.wood) & self.buildings.has_house(0), + Building.kids_room: self.money.can_spend(50000) & self.has(Material.hardwood) & self.buildings.has_house(1), + Building.cellar: self.money.can_spend(100000) & self.buildings.has_house(2), # @formatter:on }) def update_rules(self, new_rules: Dict[str, StardewRule]): - self.building_rules.update(new_rules) + self.registry.building_rules.update(new_rules) @cache_self1 def has_building(self, building: str) -> StardewRule: carpenter_rule = self.received(Event.can_construct_buildings) - if not self.building_option & BuildingProgression.option_progressive: - return Has(building, self.building_rules) & carpenter_rule + if not self.options.building_progression & BuildingProgression.option_progressive: + return Has(building, self.registry.building_rules) & carpenter_rule count = 1 if building in [Building.coop, Building.barn, Building.shed]: @@ -89,14 +74,14 @@ def has_house(self, upgrade_level: int) -> StardewRule: return False_() carpenter_rule = self.received(Event.can_construct_buildings) - if self.building_option & BuildingProgression.option_progressive: + if self.options.building_progression & BuildingProgression.option_progressive: return carpenter_rule & self.received(f"Progressive House", upgrade_level) if upgrade_level == 1: - return carpenter_rule & Has(Building.kitchen, self.building_rules) + return carpenter_rule & Has(Building.kitchen, self.registry.building_rules) if upgrade_level == 2: - return carpenter_rule & Has(Building.kids_room, self.building_rules) + return carpenter_rule & Has(Building.kids_room, self.registry.building_rules) # if upgrade_level == 3: - return carpenter_rule & Has(Building.cellar, self.building_rules) + return carpenter_rule & Has(Building.cellar, self.registry.building_rules) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 2c0a6e2b1945..0f0e611a8deb 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,8 +1,8 @@ from functools import cached_property from Utils import cache_self1 -from .action_logic import ActionLogic -from .building_logic import BuildingLogic +from .action_logic import ActionLogicMixin +from .building_logic import BuildingLogicMixin from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin @@ -34,14 +34,14 @@ class CookingLogic: season: SeasonLogicMixin time: TimeLogicMixin money: MoneyLogicMixin - action: ActionLogic - buildings: BuildingLogic + action: ActionLogicMixin + buildings: BuildingLogicMixin relationship: RelationshipLogic skill: SkillLogic def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogicMixin, - has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, action: ActionLogic, - buildings: BuildingLogic, + has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, action: ActionLogicMixin, + buildings: BuildingLogicMixin, relationship: RelationshipLogic, skill: SkillLogic): self.player = player self.chefsanity_option = chefsanity_option diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 9b351fd9e9da..921fec02447f 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -6,12 +6,10 @@ from ..strings.gift_names import Gift -class GiftLogic: - has: HasLogicMixin - - def __init__(self, player: int, has: HasLogicMixin): - self.player = player - self.has = has +class GiftLogicMixin(HasLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.gifts = self @cached_property def has_any_universal_love(self) -> StardewRule: diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index 5d82c0f4acb9..f4a02163aa5d 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,14 +1,10 @@ from typing import Union, Optional, Tuple -from .base_logic import BaseLogic, LogicRegistry +from .base_logic import BaseLogic from ..stardew_rule import StardewRule, True_, And, Or, Has, Count class HasLogicMixin(BaseLogic): - - def __init__(self, player: int, registry: LogicRegistry): - super().__init__(player, registry) - def __call__(self, *args, **kwargs) -> StardewRule: count = None if len(args) >= 2: @@ -16,7 +12,7 @@ def __call__(self, *args, **kwargs) -> StardewRule: return self.has(args[0], count) # Should be cached - def has(self, items: Union[str, Tuple[str]], count: Optional[int] = None) -> StardewRule: + def has(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): return Has(items, self.registry.item_rules) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 3e77f1e27795..93b52c5a3816 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -4,11 +4,11 @@ from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from .ability_logic import AbilityLogic -from .action_logic import ActionLogic -from .arcade_logic import ArcadeLogic -from .artisan_logic import ArtisanLogic +from .action_logic import ActionLogicMixin +from .arcade_logic import ArcadeLogicMixin +from .artisan_logic import ArtisanLogicMixin from .base_logic import LogicRegistry, BaseLogic -from .building_logic import BuildingLogic +from .building_logic import BuildingLogicMixin from .bundle_logic import BundleLogic from .combat_logic import CombatLogic from .cooking_logic import CookingLogic @@ -16,7 +16,7 @@ from .crop_logic import CropLogic from .farming_logic import FarmingLogic from .fishing_logic import FishingLogic -from .gift_logic import GiftLogic +from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin from .mine_logic import MineLogic from .money_logic import MoneyLogicMixin @@ -28,7 +28,7 @@ from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogicMixin -from .shipping_logic import ShippingLogic +from .shipping_logic import ShippingLogicMixin from .skill_logic import SkillLogic from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogicMixin @@ -44,7 +44,7 @@ from ..data.recipe_data import all_cooking_recipes from ..mods.logic.mod_logic import ModLogic from ..mods.mod_data import ModNames -from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity +from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity, StardewValleyOptions from ..stardew_rule import False_, Or, True_, Count, And, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals from ..strings.animal_product_names import AnimalProduct @@ -89,22 +89,23 @@ @dataclass(frozen=False, repr=False) class StardewLogic(BaseLogic, LogicRegistry): player: int + options: StardewValleyOptions def __post_init__(self): - # FIXME this is awful + # FIXME self.registry = self - self.received = ReceivedLogicMixin(self.player, self.registry) - self.has = HasLogicMixin(self.player, self.registry) - self.region = RegionLogicMixin(self.player, self.registry) - self.traveling_merchant = TravelingMerchantLogicMixin(self.player, self.registry) - self.time = TimeLogicMixin(self.player, self.registry) - self.season = SeasonLogicMixin(self.player, self.registry, self.options.season_randomization) - self.money = MoneyLogicMixin(self.player, self.registry, self.options.starting_money) - self.action = ActionLogic(self.player, self.received, self.has, self.region) - self.arcade = ArcadeLogic(self.player, self.options.arcade_machine_locations, self.received, self.region) - self.artisan = ArtisanLogic(self.player, self.has, self.time) - self.gifts = GiftLogic(self.player, self.has) + self.received = ReceivedLogicMixin(self.player, self.registry, self.options) + self.has = HasLogicMixin(self.player, self.registry, self.options) + self.region = RegionLogicMixin(self.player, self.registry, self.options) + self.traveling_merchant = TravelingMerchantLogicMixin(self.player, self.registry, self.options) + self.time = TimeLogicMixin(self.player, self.registry, self.options) + self.season = SeasonLogicMixin(self.player, self.registry, self.options) + self.money = MoneyLogicMixin(self.player, self.registry, self.options) + self.action = ActionLogicMixin(self.player, self.registry, self.options) + self.arcade = ArcadeLogicMixin(self.player, self.registry, self.options) + self.artisan = ArtisanLogicMixin(self.player, self.registry, self.options) + self.gifts = GiftLogicMixin(self.player, self.registry, self.options) tool_option = self.options.tool_progression skill_option = self.options.skill_progression elevator_option = self.options.elevator_progression @@ -113,9 +114,8 @@ def __post_init__(self): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.buildings = BuildingLogic(self.player, self.options.building_progression, self.received, self.has, self.region, self.money) - self.shipping = ShippingLogic(self.player, exclude_ginger_island, special_order_locations, mods_option, self.has, self.region, - self.buildings) + self.buildings = BuildingLogicMixin(self.player, self.registry, self.options) + self.shipping = ShippingLogicMixin(self.player, self.registry, self.options) self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) self.museum = MuseumLogic(self.player, self.options.museumsanity, self.received, self.has, self.region, self.action) @@ -146,7 +146,8 @@ def __post_init__(self): self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, self.registry, skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, + self.mod = ModLogic(self.player, self.registry, self.options, skill_option, elevator_option, mods_option, self.received, self.has, self.region, + self.action, self.artisan, self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, self.fishing, diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index ea604b1c28bc..f9d4546477c0 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,10 +1,8 @@ from Utils import cache_self1 -from .base_logic import LogicRegistry from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin -from ..options import StartingMoney from ..stardew_rule import StardewRule, True_, CountPercent from ..strings.currency_names import Currency from ..strings.region_names import Region @@ -14,11 +12,8 @@ class MoneyLogicMixin(TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): - starting_money_option: StartingMoney - - def __init__(self, player: int, registry: LogicRegistry, starting_money_option: StartingMoney): - super().__init__(player, registry) - self.starting_money_option = starting_money_option + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.money = self @cache_self1 @@ -34,20 +29,20 @@ def can_have_earned_total(self, amount: int) -> StardewRule: @cache_self1 def can_spend(self, amount: int) -> StardewRule: - if self.starting_money_option == -1: + if self.options.starting_money == -1: return True_() return self.can_have_earned_total(amount * 5) # Should be cached def can_spend_at(self, region: str, amount: int) -> StardewRule: - return self.region.can_reach(region) & self.can_spend(amount) + return self.region.can_reach(region) & self.money.can_spend(amount) # Should be cached def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() if currency == Currency.money: - return self.can_spend_at(region, amount) + return self.money.can_spend_at(region, amount) if currency == Currency.qi_gem: number_rewards = min(10, max(1, (amount // 10) + 2)) return self.received(qi_gem_rewards, number_rewards) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 1ff9b56bad87..1fffaaf9175c 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -1,7 +1,7 @@ from typing import List from Utils import cache_self1 -from .action_logic import ActionLogic +from .action_logic import ActionLogicMixin from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -18,10 +18,10 @@ class MuseumLogic: received = ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - action: ActionLogic + action: ActionLogicMixin def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogic): + action: ActionLogicMixin): self.player = player self.museum_option = museum_option self.received = received diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 1cf61ac74bbf..ba047fd1917d 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -1,7 +1,7 @@ from typing import Dict -from .action_logic import ActionLogic -from .building_logic import BuildingLogic +from .action_logic import ActionLogicMixin +from .building_logic import BuildingLogicMixin from .combat_logic import CombatLogic from .cooking_logic import CookingLogic from .fishing_logic import FishingLogic @@ -56,8 +56,9 @@ class QuestLogic: quest_rules: Dict[str, StardewRule] def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogicMixin, has: HasLogicMixin, mine: MineLogic, region: RegionLogicMixin, - action: ActionLogic, - relationship: RelationshipLogic, building: BuildingLogic, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + action: ActionLogicMixin, + relationship: RelationshipLogic, building: BuildingLogicMixin, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, + cooking: CookingLogic, money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): self.player = player self.skill = skill diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index f481281bc90f..43ff16fc8198 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,14 +1,10 @@ from typing import Union, Optional, Tuple -from .base_logic import BaseLogic, LogicRegistry +from .base_logic import BaseLogic from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived class ReceivedLogicMixin(BaseLogic): - - def __init__(self, player: int, registry: LogicRegistry): - super().__init__(player, registry) - def __call__(self, *args, **kwargs) -> StardewRule: count = 1 if len(args) >= 2: diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 1528666b1f86..181268f982c6 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,14 +1,13 @@ from typing import Tuple from Utils import cache_self1 -from .base_logic import BaseLogic, LogicRegistry +from .base_logic import BaseLogic from ..stardew_rule import StardewRule, And, Or, Reach, Count class RegionLogicMixin(BaseLogic): - - def __init__(self, player: int, registry: LogicRegistry): - super().__init__(player, registry) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.region = self @cache_self1 @@ -17,11 +16,11 @@ def can_reach(self, region_name: str) -> StardewRule: @cache_self1 def can_reach_any(self, region_names: Tuple[str, ...]) -> StardewRule: - return Or(*(self.can_reach(spot) for spot in region_names)) + return Or(*(self.region.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all(self, region_names: Tuple[str, ...]) -> StardewRule: - return And(*(self.can_reach(spot) for spot in region_names)) + return And(*(self.region.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule: @@ -29,7 +28,7 @@ def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule num_required = len(region_names) - 1 if num_required <= 0: num_required = len(region_names) - return Count(num_required, [self.can_reach(spot) for spot in region_names]) + return Count(num_required, [self.region.can_reach(spot) for spot in region_names]) @cache_self1 def can_reach_location(self, location_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 368f311bd0ca..dd2eb0e040af 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -2,8 +2,8 @@ from typing import Union from Utils import cache_self1 -from .building_logic import BuildingLogic -from .gift_logic import GiftLogic +from .building_logic import BuildingLogicMixin +from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -28,14 +28,14 @@ class RelationshipLogic: region: RegionLogicMixin time: TimeLogicMixin season: SeasonLogicMixin - gifts: GiftLogic - buildings: BuildingLogic + gifts: GiftLogicMixin + buildings: BuildingLogicMixin mods_option: Mods def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, received_logic: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - time: TimeLogicMixin, season: SeasonLogicMixin, gifts: GiftLogic, buildings: BuildingLogic, mods_option: Mods): + time: TimeLogicMixin, season: SeasonLogicMixin, gifts: GiftLogicMixin, buildings: BuildingLogicMixin, mods_option: Mods): self.player = player self.friendsanity_option = friendsanity_option self.heart_size_option = heart_size_option diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 04c74e08600a..754dc9432d6a 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,7 +1,6 @@ from typing import Iterable from Utils import cache_self1 -from .base_logic import LogicRegistry from .received_logic import ReceivedLogicMixin from .time_logic import TimeLogicMixin from ..options import SeasonRandomization @@ -11,12 +10,8 @@ class SeasonLogicMixin(TimeLogicMixin, ReceivedLogicMixin): - season_option: SeasonRandomization - - def __init__(self, player: int, registry: LogicRegistry, season_option: SeasonRandomization): - super().__init__(player, registry) - self.player = player - self.season_option = season_option + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.season = self @cache_self1 @@ -24,9 +19,9 @@ def has(self, season: str) -> StardewRule: if season == Generic.any: return True_() seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] - if self.season_option == SeasonRandomization.option_progressive: + if self.options.season_randomization == SeasonRandomization.option_progressive: return self.received(Season.progressive, seasons_order.index(season)) - if self.season_option == SeasonRandomization.option_disabled: + if self.options.season_randomization == SeasonRandomization.option_disabled: if season == Season.spring: return True_() return self.time.has_lived_months(1) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 1318ed206d72..ef6400cd21de 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,35 +1,21 @@ from functools import cached_property from Utils import cache_self1 -from .building_logic import BuildingLogic +from .building_logic import BuildingLogicMixin from .has_logic import HasLogicMixin from .region_logic import RegionLogicMixin from ..locations import LocationTags, locations_by_tag from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations -from ..options import Mods from ..stardew_rule import StardewRule, And from ..strings.building_names import Building from ..strings.region_names import Region -class ShippingLogic: - exclude_ginger_island: ExcludeGingerIsland - special_orders_option: SpecialOrderLocations - mods: Mods - has: HasLogicMixin - region: RegionLogicMixin - buildings: BuildingLogic - - def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_orders_option: SpecialOrderLocations,mods: Mods, has: HasLogicMixin, - region: RegionLogicMixin, buildings: BuildingLogic): - self.player = player - self.exclude_ginger_island = exclude_ginger_island - self.special_orders_option = special_orders_option - self.mods = mods - self.has = has - self.region = region - self.buildings = buildings +class ShippingLogicMixin(BuildingLogicMixin, RegionLogicMixin, HasLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.shipping = self @cached_property def can_use_shipping_bin(self) -> StardewRule: @@ -37,7 +23,7 @@ def can_use_shipping_bin(self) -> StardewRule: @cache_self1 def can_ship(self, item: str) -> StardewRule: - return self.can_ship_items & self.has(item) + return self.shipping.can_ship_items & self.has(item) @cached_property def can_ship_items(self) -> StardewRule: @@ -46,9 +32,9 @@ def can_ship_items(self) -> StardewRule: def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " all_items_to_ship = [] - exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true - exclude_qi = self.special_orders_option != SpecialOrderLocations.option_board_qi - mod_list = self.mods.value + exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_qi = self.options.special_order_locations != SpecialOrderLocations.option_board_qi + mod_list = self.options.mods.value for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]: if exclude_island and LocationTags.GINGER_ISLAND in location.tags: continue diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 47ffe5d369fa..1c64a0b16f42 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -1,8 +1,8 @@ from typing import Dict from .ability_logic import AbilityLogic -from .arcade_logic import ArcadeLogic -from .artisan_logic import ArtisanLogic +from .arcade_logic import ArcadeLogicMixin +from .artisan_logic import ArtisanLogicMixin from .cooking_logic import CookingLogic from .has_logic import HasLogicMixin from .mine_logic import MineLogic @@ -11,7 +11,7 @@ from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogic from .season_logic import SeasonLogicMixin -from .shipping_logic import ShippingLogic +from .shipping_logic import ShippingLogicMixin from .skill_logic import SkillLogic from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic @@ -42,9 +42,9 @@ class SpecialOrderLogic: season: SeasonLogicMixin time: TimeLogicMixin money: MoneyLogicMixin - shipping: ShippingLogic - arcade: ArcadeLogic - artisan: ArtisanLogic + shipping: ShippingLogicMixin + arcade: ArcadeLogicMixin + artisan: ArtisanLogicMixin relationship: RelationshipLogic tool: ToolLogic skill: SkillLogic @@ -55,7 +55,8 @@ class SpecialOrderLogic: def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, - shipping: ShippingLogic, arcade: ArcadeLogic, artisan: ArtisanLogic, relationship: RelationshipLogic, tool: ToolLogic, skill: SkillLogic, + shipping: ShippingLogicMixin, arcade: ArcadeLogicMixin, artisan: ArtisanLogicMixin, relationship: RelationshipLogic, tool: ToolLogic, + skill: SkillLogic, mine: MineLogic, cooking: CookingLogic, ability: AbilityLogic): self.player = player self.received = received diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index a799ee85dfa8..ba3c38e01ed7 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,7 +1,6 @@ from functools import cached_property from Utils import cache_self1 -from .base_logic import LogicRegistry from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule, CountPercent, True_ from ..strings.ap_names.event_names import Event @@ -11,8 +10,8 @@ class TimeLogicMixin(ReceivedLogicMixin): - def __init__(self, player: int, registry: LogicRegistry): - super().__init__(player, registry) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.time = self @cache_self1 diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index d951a5fde284..aafa78e8380d 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,13 +1,12 @@ -from .base_logic import LogicRegistry from .received_logic import ReceivedLogicMixin from ..stardew_rule import True_ from ..strings.calendar_names import Weekday class TravelingMerchantLogicMixin(ReceivedLogicMixin): - - def __init__(self, player: int, registry: LogicRegistry): - super().__init__(player, registry) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.traveling_merchant = self def has_days(self, number_days: int = 1): if number_days <= 0: diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 13b9dc1bf6b2..459d8734070b 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -1,10 +1,8 @@ from typing import Dict from ..mod_data import ModNames -from ...logic.base_logic import LogicRegistry from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin -from ...options import Mods from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ArtisanGood from ...strings.building_names import ModBuilding @@ -12,19 +10,14 @@ from ...strings.region_names import Region -class ModBuildingLogic(HasLogicMixin): - player: int - money: MoneyLogicMixin - mods_option: Mods - - def __init__(self, player: int, registry: LogicRegistry, money: MoneyLogicMixin, mods_option: Mods): - super().__init__(player, registry) - self.money = money - self.mods_option = mods_option +class ModBuildingLogic(MoneyLogicMixin, HasLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.buildings = self def get_modded_building_rules(self) -> Dict[str, StardewRule]: buildings = dict() - if ModNames.tractor in self.mods_option: + if ModNames.tractor in self.options.mods: tractor_rule = self.money.can_spend_at(Region.carpenter, 150000) & self.has(MetalBar.iron) & self.has(MetalBar.iridium) & self.has( ArtisanGood.battery_pack) buildings.update({ModBuilding.tractor_garage: tractor_rule}) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index b81d89cb23a7..dbb5972d1136 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -8,10 +8,10 @@ from .special_orders_logic import ModSpecialOrderLogic from .sve_logic import SVELogic from ...logic.ability_logic import AbilityLogic -from ...logic.action_logic import ActionLogic -from ...logic.artisan_logic import ArtisanLogic +from ...logic.action_logic import ActionLogicMixin +from ...logic.artisan_logic import ArtisanLogicMixin from ...logic.base_logic import LogicRegistry, BaseLogic -from ...logic.building_logic import BuildingLogic +from ...logic.building_logic import BuildingLogicMixin from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic from ...logic.crafting_logic import CraftingLogic @@ -45,19 +45,19 @@ class ModLogic(BaseLogic): skill: ModSkillLogic sve: SVELogic - def __init__(self, player: int, registry: LogicRegistry, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, + def __init__(self, player: int, registry: LogicRegistry, options, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogic, artisan: ArtisanLogic, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogic, - museum: MuseumLogic, building: BuildingLogic, + action: ActionLogicMixin, artisan: ArtisanLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogic, + museum: MuseumLogic, building: BuildingLogicMixin, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogicMixin, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): - super().__init__(player, registry) + super().__init__(player, registry, options) self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, museum, tool, crafting) self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) - self.buildings = ModBuildingLogic(player, registry, money, mods) + self.buildings = ModBuildingLogic(player, registry, options) self.special_orders = ModSpecialOrderLogic(player, action, artisan, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index eaa4d0548c1e..59f0f5249b72 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -1,7 +1,7 @@ from .magic_logic import MagicLogic from ...data.villagers_data import all_villagers -from ...logic.action_logic import ActionLogic -from ...logic.building_logic import BuildingLogic +from ...logic.action_logic import ActionLogicMixin +from ...logic.building_logic import BuildingLogicMixin from ...logic.cooking_logic import CookingLogic from ...logic.fishing_logic import FishingLogic from ...logic.has_logic import HasLogicMixin @@ -27,9 +27,9 @@ class ModSkillLogic: received: ReceivedLogicMixin has: HasLogicMixin region: RegionLogicMixin - action: ActionLogic + action: ActionLogicMixin relationship: RelationshipLogic - building: BuildingLogic + building: BuildingLogicMixin tool: ToolLogic fishing: FishingLogic cooking: CookingLogic @@ -37,8 +37,8 @@ class ModSkillLogic: mods_option: Mods def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogic, - relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + action: ActionLogicMixin, + relationship: RelationshipLogic, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, magic: MagicLogic, mods_option: Mods): self.player = player self.skill_option = skill_option diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index b3639699de49..b33ff424f6e8 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -1,6 +1,6 @@ from ..mod_data import ModNames -from ...logic.action_logic import ActionLogic -from ...logic.artisan_logic import ArtisanLogic +from ...logic.action_logic import ActionLogicMixin +from ...logic.artisan_logic import ArtisanLogicMixin from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogicMixin @@ -25,8 +25,8 @@ class ModSpecialOrderLogic: player: int - action: ActionLogic - artisan: ArtisanLogic + action: ActionLogicMixin + artisan: ArtisanLogicMixin crafting: CraftingLogic crop: CropLogic has: HasLogicMixin @@ -36,7 +36,7 @@ class ModSpecialOrderLogic: wallet: WalletLogic mods_option: Mods - def __init__(self, player: int, action: ActionLogic, artisan: ArtisanLogic, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, + def __init__(self, player: int, action: ActionLogicMixin, artisan: ArtisanLogicMixin, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, region: RegionLogicMixin, relationship: RelationshipLogic, season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): self.player = player diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 606cdbcd4d6e..75c72f50f193 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -1,8 +1,8 @@ from typing import Dict from ..mod_regions import SVERegion -from ...logic.action_logic import ActionLogic -from ...logic.building_logic import BuildingLogic +from ...logic.action_logic import ActionLogicMixin +from ...logic.building_logic import BuildingLogicMixin from ...logic.combat_logic import CombatLogic from ...logic.cooking_logic import CookingLogic from ...logic.fishing_logic import FishingLogic @@ -37,8 +37,8 @@ class SVELogic: def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, quest: QuestLogic, region: RegionLogicMixin, - action: ActionLogic, - relationship: RelationshipLogic, building: BuildingLogic, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + action: ActionLogicMixin, + relationship: RelationshipLogic, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, time: TimeLogicMixin): self.player = player self.skill_option = skill_option diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index bdcd0d3a29b9..831d8952b199 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -3,7 +3,6 @@ from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules -from .strings.craftable_names import Bomb from . import locations from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name @@ -23,6 +22,7 @@ from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building from .strings.calendar_names import Weekday +from .strings.craftable_names import Bomb from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance, \ SVEEntrance from .strings.generic_names import Generic @@ -113,7 +113,7 @@ def set_building_rules(logic: StardewLogic, multiworld, player, world_options: S if building.mod_name is not None and building.mod_name not in world_options.mods: continue MultiWorldRules.set_rule(multiworld.get_location(building.name, player), - logic.buildings.building_rules[building.name.replace(" Blueprint", "")]) + logic.registry.building_rules[building.name.replace(" Blueprint", "")]) def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): @@ -124,22 +124,23 @@ def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): MultiWorldRules.set_rule(location, simplified_rules) MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]))) + for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]))) + for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]))) + for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]))) + for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]))) + for bundle + in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]))) MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]))) + for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]))) def set_skills_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -276,14 +277,16 @@ def set_farm_buildings_entrance_rules(logic, multiworld, player): def set_bedroom_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink())) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), + (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) if ModNames.alec in world_options.mods: - MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink())) + MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), + (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink())) def set_mines_floor_entrance_rules(logic, multiworld, player): diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 9497a6ded48b..e99b9c026958 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -31,9 +31,9 @@ def test_given_item_rule_then_can_be_resolved(self): self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve item rule for {item} {rule}") def test_given_building_rule_then_can_be_resolved(self): - for building in logic.buildings.building_rules.keys(): + for building in logic.registry.building_rules.keys(): with self.subTest(msg=building): - rule = logic.buildings.building_rules[building] + rule = logic.registry.building_rules[building] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve building rule for {building} {rule}") From bb7d6fa8e86ddf5e793df040956aec5cc905fa14 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 21:39:56 -0500 Subject: [PATCH 188/482] mixin rework to be independent --- worlds/stardew_valley/logic/action_logic.py | 8 ++- worlds/stardew_valley/logic/arcade_logic.py | 10 +++- worlds/stardew_valley/logic/artisan_logic.py | 16 ++++-- worlds/stardew_valley/logic/building_logic.py | 23 ++++---- worlds/stardew_valley/logic/cooking_logic.py | 6 +- worlds/stardew_valley/logic/crafting_logic.py | 6 +- worlds/stardew_valley/logic/crop_logic.py | 6 +- worlds/stardew_valley/logic/fishing_logic.py | 6 +- worlds/stardew_valley/logic/gift_logic.py | 8 ++- worlds/stardew_valley/logic/logic.py | 27 +++++---- worlds/stardew_valley/logic/money_logic.py | 9 ++- worlds/stardew_valley/logic/quest_logic.py | 6 +- worlds/stardew_valley/logic/region_logic.py | 11 ++-- .../logic/relationship_logic.py | 55 ++++++------------- worlds/stardew_valley/logic/season_logic.py | 14 +++-- worlds/stardew_valley/logic/shipping_logic.py | 10 +++- .../logic/special_order_logic.py | 6 +- worlds/stardew_valley/logic/time_logic.py | 9 ++- .../logic/traveling_merchant_logic.py | 8 ++- .../stardew_valley/mods/logic/item_logic.py | 6 +- worlds/stardew_valley/mods/logic/mod_logic.py | 4 +- .../stardew_valley/mods/logic/quests_logic.py | 6 +- .../stardew_valley/mods/logic/skills_logic.py | 6 +- .../mods/logic/special_orders_logic.py | 6 +- worlds/stardew_valley/mods/logic/sve_logic.py | 6 +- 25 files changed, 149 insertions(+), 129 deletions(-) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index e200f6f30e44..162c009ea0cb 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,4 +1,5 @@ from Utils import cache_self1 +from .base_logic import BaseLogic from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -8,10 +9,13 @@ from ..strings.region_names import Region -class ActionLogicMixin(RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class ActionLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.action = self + self.action = ActionLogic(*args, **kwargs) + + +class ActionLogic(RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): def can_watch(self, channel: str = None): tv_rule = True_() diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index 54d8f5cf573f..08990e86fd6c 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,3 +1,4 @@ +from .base_logic import BaseLogic from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .. import options @@ -5,10 +6,13 @@ from ..strings.region_names import Region -class ArcadeLogicMixin(RegionLogicMixin, ReceivedLogicMixin): +class ArcadeLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.arcade = self + self.arcade = ArcadeLogic(*args, **kwargs) + + +class ArcadeLogic(RegionLogicMixin, ReceivedLogicMixin): def has_jotpk_power_level(self, power_level: int) -> StardewRule: if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: @@ -25,4 +29,4 @@ def has_junimo_kart_max_level(self) -> StardewRule: play_rule = self.region.can_reach(Region.junimo_kart_3) if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return play_rule - return self.arcade.has_junimo_kart_power_level(8) + return self.has_junimo_kart_power_level(8) diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 2d753d5ec583..67b847da4e53 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -1,3 +1,4 @@ +from .base_logic import BaseLogic from .has_logic import HasLogicMixin from .time_logic import TimeLogicMixin from ..stardew_rule import StardewRule @@ -6,16 +7,19 @@ from ..strings.machine_names import Machine -class ArtisanLogicMixin(TimeLogicMixin, HasLogicMixin): +class ArtisanLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.artisan = self + self.artisan = ArtisanLogic(*args, **kwargs) + + +class ArtisanLogic(TimeLogicMixin, HasLogicMixin): def has_jelly(self) -> StardewRule: - return self.artisan.can_preserves_jar(Fruit.any) + return self.can_preserves_jar(Fruit.any) def has_pickle(self) -> StardewRule: - return self.artisan.can_preserves_jar(Vegetable.any) + return self.can_preserves_jar(Vegetable.any) def can_preserves_jar(self, item: str) -> StardewRule: machine_rule = self.has(Machine.preserves_jar) @@ -28,10 +32,10 @@ def can_preserves_jar(self, item: str) -> StardewRule: return machine_rule & self.has(item) def has_wine(self) -> StardewRule: - return self.artisan.can_keg(Fruit.any) + return self.can_keg(Fruit.any) def has_juice(self) -> StardewRule: - return self.artisan.can_keg(Vegetable.any) + return self.can_keg(Vegetable.any) def can_keg(self, item: str) -> StardewRule: machine_rule = self.has(Machine.keg) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 72c11c6f3282..84749b4ed5e7 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,6 +1,7 @@ from typing import Dict from Utils import cache_self1 +from .base_logic import BaseLogic from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin @@ -16,32 +17,34 @@ from ..strings.region_names import Region -class BuildingLogicMixin(MoneyLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class BuildingLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.buildings = self + self.buildings = BuildingLogic(*args, **kwargs) + +class BuildingLogic(MoneyLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): def initialize_rules(self): self.registry.building_rules.update({ # @formatter:off Building.barn: self.money.can_spend(6000) & self.has((Material.wood, Material.stone)), - Building.big_barn: self.money.can_spend(12000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.barn), - Building.deluxe_barn: self.money.can_spend(25000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.big_barn), + Building.big_barn: self.money.can_spend(12000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.barn), + Building.deluxe_barn: self.money.can_spend(25000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_barn), Building.coop: self.money.can_spend(4000) & self.has((Material.wood, Material.stone)), - Building.big_coop: self.money.can_spend(10000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.coop), - Building.deluxe_coop: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.big_coop), + Building.big_coop: self.money.can_spend(10000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.coop), + Building.deluxe_coop: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_coop), Building.fish_pond: self.money.can_spend(5000) & self.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), Building.mill: self.money.can_spend(2500) & self.has((Material.stone, Material.wood, ArtisanGood.cloth)), Building.shed: self.money.can_spend(15000) & self.has(Material.wood), - Building.big_shed: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.buildings.has_building(Building.shed), + Building.big_shed: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.shed), Building.silo: self.money.can_spend(100) & self.has((Material.stone, Material.clay, MetalBar.copper)), Building.slime_hutch: self.money.can_spend(10000) & self.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), Building.stable: self.money.can_spend(10000) & self.has((Material.hardwood, MetalBar.iron)), Building.well: self.money.can_spend(1000) & self.has(Material.stone), Building.shipping_bin: self.money.can_spend(250) & self.has(Material.wood), - Building.kitchen: self.money.can_spend(10000) & self.has(Material.wood) & self.buildings.has_house(0), - Building.kids_room: self.money.can_spend(50000) & self.has(Material.hardwood) & self.buildings.has_house(1), - Building.cellar: self.money.can_spend(100000) & self.buildings.has_house(2), + Building.kitchen: self.money.can_spend(10000) & self.has(Material.wood) & self.has_house(0), + Building.kids_room: self.money.can_spend(50000) & self.has(Material.hardwood) & self.has_house(1), + Building.cellar: self.money.can_spend(100000) & self.has_house(2), # @formatter:on }) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 0f0e611a8deb..f4675a0ebca6 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -7,7 +7,7 @@ from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .relationship_logic import RelationshipLogic +from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogic from .time_logic import TimeLogicMixin @@ -36,13 +36,13 @@ class CookingLogic: money: MoneyLogicMixin action: ActionLogicMixin buildings: BuildingLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin skill: SkillLogic def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, action: ActionLogicMixin, buildings: BuildingLogicMixin, - relationship: RelationshipLogic, skill: SkillLogic): + relationship: RelationshipLogicMixin, skill: SkillLogic): self.player = player self.chefsanity_option = chefsanity_option self.exclude_ginger_island = exclude_ginger_island diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 8d7ca63ddf1a..e8e66e4ce76c 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -5,7 +5,7 @@ from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .relationship_logic import RelationshipLogic +from .relationship_logic import RelationshipLogicMixin from .skill_logic import SkillLogic from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogicMixin @@ -31,14 +31,14 @@ class CraftingLogic: region: RegionLogicMixin time: TimeLogicMixin money: MoneyLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin skill: SkillLogic special_orders: SpecialOrderLogic def __init__(self, player: int, craftsanity_option: Craftsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - time: TimeLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogic, skill: SkillLogic, special_orders: SpecialOrderLogic): + time: TimeLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogicMixin, skill: SkillLogic, special_orders: SpecialOrderLogic): self.player = player self.craftsanity_option = craftsanity_option self.exclude_ginger_island = exclude_ginger_island diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index c97fea4c3b88..5b81b38ce2d6 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -5,7 +5,7 @@ from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogicMixin +from .season_logic import SeasonLogic from .tool_logic import ToolLogic from .traveling_merchant_logic import TravelingMerchantLogicMixin from ..data import CropItem, SeedItem @@ -26,13 +26,13 @@ class CropLogic: has: HasLogicMixin region: RegionLogicMixin traveling_merchant: TravelingMerchantLogicMixin - season: SeasonLogicMixin + season: SeasonLogic money: MoneyLogicMixin tool: ToolLogic def __init__(self, player: int, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogicMixin, has: HasLogicMixin, - region: RegionLogicMixin, traveling_merchant: TravelingMerchantLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, tool: ToolLogic): + region: RegionLogicMixin, traveling_merchant: TravelingMerchantLogicMixin, season: SeasonLogic, money: MoneyLogicMixin, tool: ToolLogic): self.player = player self.cropsanity_option = cropsanity_option self.exclude_ginger_island_option = exclude_ginger_island_option diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 8ee7791906c3..b42e9e2107e5 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,7 +1,7 @@ from Utils import cache_self1 from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogicMixin +from .season_logic import SeasonLogic from .skill_logic import SkillLogic from .tool_logic import ToolLogic from ..data import FishItem @@ -19,12 +19,12 @@ class FishingLogic: special_order_locations: SpecialOrderLocations received: ReceivedLogicMixin region: RegionLogicMixin - season: SeasonLogicMixin + season: SeasonLogic tool: ToolLogic skill: SkillLogic def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, received: ReceivedLogicMixin, - region: RegionLogicMixin, season: SeasonLogicMixin, tool: ToolLogic, skill: SkillLogic): + region: RegionLogicMixin, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): self.player = player self.exclude_ginger_island = exclude_ginger_island self.special_order_locations = special_order_locations diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 921fec02447f..d963913e9cd5 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,15 +1,19 @@ from functools import cached_property +from .base_logic import BaseLogic from .has_logic import HasLogicMixin from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct from ..strings.gift_names import Gift -class GiftLogicMixin(HasLogicMixin): +class GiftLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.gifts = self + self.gifts = GiftLogic(*args, **kwargs) + + +class GiftLogic(HasLogicMixin): @cached_property def has_any_universal_love(self) -> StardewRule: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 93b52c5a3816..9f26424d21d0 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -26,7 +26,7 @@ from .quest_logic import QuestLogic from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .relationship_logic import RelationshipLogic +from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogicMixin from .skill_logic import SkillLogic @@ -97,15 +97,15 @@ def __post_init__(self): self.received = ReceivedLogicMixin(self.player, self.registry, self.options) self.has = HasLogicMixin(self.player, self.registry, self.options) - self.region = RegionLogicMixin(self.player, self.registry, self.options) - self.traveling_merchant = TravelingMerchantLogicMixin(self.player, self.registry, self.options) - self.time = TimeLogicMixin(self.player, self.registry, self.options) - self.season = SeasonLogicMixin(self.player, self.registry, self.options) - self.money = MoneyLogicMixin(self.player, self.registry, self.options) - self.action = ActionLogicMixin(self.player, self.registry, self.options) - self.arcade = ArcadeLogicMixin(self.player, self.registry, self.options) - self.artisan = ArtisanLogicMixin(self.player, self.registry, self.options) - self.gifts = GiftLogicMixin(self.player, self.registry, self.options) + self.region = RegionLogicMixin(self.player, self.registry, self.options).region + self.traveling_merchant = TravelingMerchantLogicMixin(self.player, self.registry, self.options).traveling_merchant + self.time = TimeLogicMixin(self.player, self.registry, self.options).time + self.season = SeasonLogicMixin(self.player, self.registry, self.options).season + self.money = MoneyLogicMixin(self.player, self.registry, self.options).money + self.action = ActionLogicMixin(self.player, self.registry, self.options).action + self.arcade = ArcadeLogicMixin(self.player, self.registry, self.options).arcade + self.artisan = ArtisanLogicMixin(self.player, self.registry, self.options).artisan + self.gifts = GiftLogicMixin(self.player, self.registry, self.options).gifts tool_option = self.options.tool_progression skill_option = self.options.skill_progression elevator_option = self.options.elevator_progression @@ -114,10 +114,9 @@ def __post_init__(self): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.buildings = BuildingLogicMixin(self.player, self.registry, self.options) - self.shipping = ShippingLogicMixin(self.player, self.registry, self.options) - self.relationship = RelationshipLogic(self.player, friendsanity_option, heart_size_option, - self.received, self.has, self.region, self.time, self.season, self.gifts, self.buildings, mods_option) + self.buildings = BuildingLogicMixin(self.player, self.registry, self.options).buildings + self.shipping = ShippingLogicMixin(self.player, self.registry, self.options).shipping + self.relationship = RelationshipLogicMixin(self.player, self.registry, self.options).relationship self.museum = MuseumLogic(self.player, self.options.museumsanity, self.received, self.has, self.region, self.action) self.wallet = WalletLogic(self.player, self.received, self.museum) self.combat = CombatLogic(self.player, self.received, self.region) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index f9d4546477c0..e9ff441beb77 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -14,7 +14,10 @@ class MoneyLogicMixin(TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.money = self + self.money = MoneyLogic(*args, **kwargs) + + +class MoneyLogic(TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: @@ -35,14 +38,14 @@ def can_spend(self, amount: int) -> StardewRule: # Should be cached def can_spend_at(self, region: str, amount: int) -> StardewRule: - return self.region.can_reach(region) & self.money.can_spend(amount) + return self.region.can_reach(region) & self.can_spend(amount) # Should be cached def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() if currency == Currency.money: - return self.money.can_spend_at(region, amount) + return self.can_spend_at(region, amount) if currency == Currency.qi_gem: number_rewards = min(10, max(1, (amount // 10) + 2)) return self.received(qi_gem_rewards, number_rewards) diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index ba047fd1917d..b07de4c9ef8b 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -10,7 +10,7 @@ from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .relationship_logic import RelationshipLogic +from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogic from .time_logic import TimeLogicMixin @@ -43,7 +43,7 @@ class QuestLogic: has: HasLogicMixin mine: MineLogic region: RegionLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin tool: ToolLogic fishing: FishingLogic cooking: CookingLogic @@ -57,7 +57,7 @@ class QuestLogic: def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogicMixin, has: HasLogicMixin, mine: MineLogic, region: RegionLogicMixin, action: ActionLogicMixin, - relationship: RelationshipLogic, building: BuildingLogicMixin, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, + relationship: RelationshipLogicMixin, building: BuildingLogicMixin, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): self.player = player diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 181268f982c6..772cd3c35ab2 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -8,7 +8,10 @@ class RegionLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.region = self + self.region = RegionLogic(*args, **kwargs) + + +class RegionLogic(BaseLogic): @cache_self1 def can_reach(self, region_name: str) -> StardewRule: @@ -16,11 +19,11 @@ def can_reach(self, region_name: str) -> StardewRule: @cache_self1 def can_reach_any(self, region_names: Tuple[str, ...]) -> StardewRule: - return Or(*(self.region.can_reach(spot) for spot in region_names)) + return Or(*(self.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all(self, region_names: Tuple[str, ...]) -> StardewRule: - return And(*(self.region.can_reach(spot) for spot in region_names)) + return And(*(self.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule: @@ -28,7 +31,7 @@ def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule num_required = len(region_names) - 1 if num_required <= 0: num_required = len(region_names) - return Count(num_required, [self.region.can_reach(spot) for spot in region_names]) + return Count(num_required, [self.can_reach(spot) for spot in region_names]) @cache_self1 def can_reach_location(self, location_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index dd2eb0e040af..bc3896fe390c 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -2,6 +2,7 @@ from typing import Union from Utils import cache_self1 +from .base_logic import BaseLogic from .building_logic import BuildingLogicMixin from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin @@ -10,7 +11,7 @@ from .season_logic import SeasonLogicMixin from .time_logic import TimeLogicMixin from ..data.villagers_data import all_villagers_by_name, Villager -from ..options import Friendsanity, FriendsanityHeartSize, Mods +from ..options import Friendsanity from ..stardew_rule import StardewRule, True_, And, Or, Count from ..strings.generic_names import Generic from ..strings.gift_names import Gift @@ -20,33 +21,13 @@ possible_kids = ("Cute Baby", "Ugly Baby") -class RelationshipLogic: - friendsanity_option: Friendsanity - heart_size_option: FriendsanityHeartSize - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - time: TimeLogicMixin - season: SeasonLogicMixin - gifts: GiftLogicMixin - buildings: BuildingLogicMixin - mods_option: Mods - - def __init__(self, player: int, friendsanity_option: Friendsanity, - heart_size_option: FriendsanityHeartSize, - received_logic: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - time: TimeLogicMixin, season: SeasonLogicMixin, gifts: GiftLogicMixin, buildings: BuildingLogicMixin, mods_option: Mods): - self.player = player - self.friendsanity_option = friendsanity_option - self.heart_size_option = heart_size_option - self.received = received_logic - self.has = has - self.region = region - self.time = time - self.season = season - self.gifts = gifts - self.buildings = buildings - self.mods_option = mods_option +class RelationshipLogicMixin(BaseLogic): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.relationship = RelationshipLogic(*args, **kwargs) + + +class RelationshipLogic(BuildingLogicMixin, SeasonLogicMixin, TimeLogicMixin, GiftLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): def can_date(self, npc: str) -> StardewRule: return self.has_hearts(npc, 8) & self.has(Gift.bouquet) @@ -60,7 +41,7 @@ def can_get_married(self) -> StardewRule: def has_children(self, number_children: int) -> StardewRule: if number_children <= 0: return True_() - if self.friendsanity_option == Friendsanity.option_none: + if self.options.friendsanity == Friendsanity.option_none: return self.can_reproduce(number_children) return self.received(possible_kids, number_children) & self.buildings.has_house(2) @@ -75,7 +56,7 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule: def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() - if self.friendsanity_option == Friendsanity.option_none: + if self.options.friendsanity == Friendsanity.option_none: return self.can_earn_relationship(npc, hearts) if npc not in all_villagers_by_name: if npc == Generic.any or npc == Generic.bachelor: @@ -105,18 +86,18 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if not self.npc_is_in_current_slot(npc): return True_() villager = all_villagers_by_name[npc] - if self.friendsanity_option == Friendsanity.option_bachelors and not villager.bachelor: + if self.options.friendsanity == Friendsanity.option_bachelors and not villager.bachelor: return self.can_earn_relationship(npc, hearts) - if self.friendsanity_option == Friendsanity.option_starting_npcs and not villager.available: + if self.options.friendsanity == Friendsanity.option_starting_npcs and not villager.available: return self.can_earn_relationship(npc, hearts) - is_capped_at_8 = villager.bachelor and self.friendsanity_option != Friendsanity.option_all_with_marriage + is_capped_at_8 = villager.bachelor and self.options.friendsanity != Friendsanity.option_all_with_marriage if is_capped_at_8 and hearts > 8: return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) return self.received_hearts(villager.name, hearts) # Should be cached def received_hearts(self, npc: str, hearts: int) -> StardewRule: - return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) + return self.received(self.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) @cache_self1 def can_meet(self, npc: str) -> StardewRule: @@ -148,7 +129,7 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: if hearts <= 0: return True_() - previous_heart = hearts - self.heart_size_option + previous_heart = hearts - self.options.friendsanity_heart_size previous_heart_rule = self.has_hearts(npc, previous_heart) if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): @@ -156,7 +137,7 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: rules = [previous_heart_rule, self.can_meet(npc)] villager = all_villagers_by_name[npc] - if hearts > 2 or hearts > self.heart_size_option: + if hearts > 2 or hearts > self.options.friendsanity_heart_size: rules.append(self.season.has(villager.birthday)) if villager.bachelor: if hearts > 8: @@ -170,7 +151,7 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] mod = npc.mod_name - return mod is None or mod in self.mods_option + return mod is None or mod in self.options.mods def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 754dc9432d6a..77089fbb3fb2 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,6 +1,7 @@ from typing import Iterable from Utils import cache_self1 +from .base_logic import BaseLogic from .received_logic import ReceivedLogicMixin from .time_logic import TimeLogicMixin from ..options import SeasonRandomization @@ -9,10 +10,13 @@ from ..strings.season_names import Season -class SeasonLogicMixin(TimeLogicMixin, ReceivedLogicMixin): +class SeasonLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.season = self + self.season = SeasonLogic(*args, **kwargs) + + +class SeasonLogic(TimeLogicMixin, ReceivedLogicMixin): @cache_self1 def has(self, season: str) -> StardewRule: @@ -30,12 +34,12 @@ def has(self, season: str) -> StardewRule: def has_any(self, seasons: Iterable[str]): if not seasons: return True_() - return Or(*(self.season.has(season) for season in seasons)) + return Or(*(self.has(season) for season in seasons)) def has_any_not_winter(self): - return self.season.has_any([Season.spring, Season.summer, Season.fall]) + return self.has_any([Season.spring, Season.summer, Season.fall]) def has_all(self, seasons: Iterable[str]): if not seasons: return True_() - return And(*(self.season.has(season) for season in seasons)) + return And(*(self.has(season) for season in seasons)) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index ef6400cd21de..d84d514c0663 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,6 +1,7 @@ from functools import cached_property from Utils import cache_self1 +from .base_logic import BaseLogic from .building_logic import BuildingLogicMixin from .has_logic import HasLogicMixin from .region_logic import RegionLogicMixin @@ -12,10 +13,13 @@ from ..strings.region_names import Region -class ShippingLogicMixin(BuildingLogicMixin, RegionLogicMixin, HasLogicMixin): +class ShippingLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.shipping = self + self.shipping = ShippingLogic(*args, **kwargs) + + +class ShippingLogic(BuildingLogicMixin, RegionLogicMixin, HasLogicMixin): @cached_property def can_use_shipping_bin(self) -> StardewRule: @@ -23,7 +27,7 @@ def can_use_shipping_bin(self) -> StardewRule: @cache_self1 def can_ship(self, item: str) -> StardewRule: - return self.shipping.can_ship_items & self.has(item) + return self.can_ship_items & self.has(item) @cached_property def can_ship_items(self) -> StardewRule: diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 1c64a0b16f42..504cafce8ef0 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -9,7 +9,7 @@ from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .relationship_logic import RelationshipLogic +from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogicMixin from .skill_logic import SkillLogic @@ -45,7 +45,7 @@ class SpecialOrderLogic: shipping: ShippingLogicMixin arcade: ArcadeLogicMixin artisan: ArtisanLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin tool: ToolLogic skill: SkillLogic mine: MineLogic @@ -55,7 +55,7 @@ class SpecialOrderLogic: def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, - shipping: ShippingLogicMixin, arcade: ArcadeLogicMixin, artisan: ArtisanLogicMixin, relationship: RelationshipLogic, tool: ToolLogic, + shipping: ShippingLogicMixin, arcade: ArcadeLogicMixin, artisan: ArtisanLogicMixin, relationship: RelationshipLogicMixin, tool: ToolLogic, skill: SkillLogic, mine: MineLogic, cooking: CookingLogic, ability: AbilityLogic): self.player = player diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index ba3c38e01ed7..6af2408df32b 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,18 +1,21 @@ from functools import cached_property from Utils import cache_self1 +from .base_logic import BaseLogic from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule, CountPercent, True_ -from ..strings.ap_names.event_names import Event MAX_MONTHS = 12 MONTH_COEFFICIENT = 100 // MAX_MONTHS -class TimeLogicMixin(ReceivedLogicMixin): +class TimeLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.time = self + self.time = TimeLogic(*args, **kwargs) + + +class TimeLogic(ReceivedLogicMixin): @cache_self1 def has_lived_months(self, number: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index aafa78e8380d..d34cadacbde9 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,12 +1,16 @@ +from .base_logic import BaseLogic from .received_logic import ReceivedLogicMixin from ..stardew_rule import True_ from ..strings.calendar_names import Weekday -class TravelingMerchantLogicMixin(ReceivedLogicMixin): +class TravelingMerchantLogicMixin(BaseLogic): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.traveling_merchant = self + self.traveling_merchant = TravelingMerchantLogic(*args, **kwargs) + + +class TravelingMerchantLogic(ReceivedLogicMixin): def has_days(self, number_days: int = 1): if number_days <= 0: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 1b22f42c7a9d..98eb01ba207f 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -11,7 +11,7 @@ from ...logic.museum_logic import MuseumLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogic +from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.tool_logic import ToolLogic from ...options import Mods @@ -42,7 +42,7 @@ class ModItemLogic: money: MoneyLogicMixin region: RegionLogicMixin season: SeasonLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin museum: MuseumLogic received: ReceivedLogicMixin tool: ToolLogic @@ -50,7 +50,7 @@ class ModItemLogic: def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogicMixin, money: MoneyLogicMixin, region: RegionLogicMixin, - season: SeasonLogicMixin, relationship: RelationshipLogic, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): + season: SeasonLogicMixin, relationship: RelationshipLogicMixin, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): self.combat = combat self.crop = crop self.cooking = cooking diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index dbb5972d1136..326894f9e0eb 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -24,7 +24,7 @@ from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogic +from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.skill_logic import SkillLogic from ...logic.time_logic import TimeLogicMixin @@ -48,7 +48,7 @@ class ModLogic(BaseLogic): def __init__(self, player: int, registry: LogicRegistry, options, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogicMixin, artisan: ArtisanLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogic, + action: ActionLogicMixin, artisan: ArtisanLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogicMixin, museum: MuseumLogic, building: BuildingLogicMixin, wallet: WalletLogic, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 229f3dbda7a3..98874b1f5459 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -4,7 +4,7 @@ from ...logic.has_logic import HasLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogic +from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin from ...options import Mods @@ -30,10 +30,10 @@ class ModQuestLogic: region: RegionLogicMixin time: TimeLogicMixin season: SeasonLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin def __init__(self, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, time: TimeLogicMixin, season: SeasonLogicMixin, - relationship: RelationshipLogic, ): + relationship: RelationshipLogicMixin, ): self.mods = mods self.received = received self.has = has diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 59f0f5249b72..d69e081c9a72 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -7,7 +7,7 @@ from ...logic.has_logic import HasLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogic +from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.tool_logic import ToolLogic from ...mods.mod_data import ModNames from ...options import SkillProgression, Mods @@ -28,7 +28,7 @@ class ModSkillLogic: has: HasLogicMixin region: RegionLogicMixin action: ActionLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin building: BuildingLogicMixin tool: ToolLogic fishing: FishingLogic @@ -38,7 +38,7 @@ class ModSkillLogic: def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, action: ActionLogicMixin, - relationship: RelationshipLogic, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + relationship: RelationshipLogicMixin, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, magic: MagicLogic, mods_option: Mods): self.player = player self.skill_option = skill_option diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index b33ff424f6e8..a3e12339df2c 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -5,7 +5,7 @@ from ...logic.crop_logic import CropLogic from ...logic.has_logic import HasLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogic +from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.wallet_logic import WalletLogic from ...options import Mods @@ -31,13 +31,13 @@ class ModSpecialOrderLogic: crop: CropLogic has: HasLogicMixin region: RegionLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin season: SeasonLogicMixin wallet: WalletLogic mods_option: Mods def __init__(self, player: int, action: ActionLogicMixin, artisan: ArtisanLogicMixin, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, - region: RegionLogicMixin, relationship: RelationshipLogic, + region: RegionLogicMixin, relationship: RelationshipLogicMixin, season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): self.player = player self.action = action diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 75c72f50f193..0ea922f717fe 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -11,7 +11,7 @@ from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogic +from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogic @@ -25,7 +25,7 @@ class SVELogic: has: HasLogicMixin quest: QuestLogic region: RegionLogicMixin - relationship: RelationshipLogic + relationship: RelationshipLogicMixin time: TimeLogicMixin tool: ToolLogic fishing: FishingLogic @@ -38,7 +38,7 @@ class SVELogic: def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, quest: QuestLogic, region: RegionLogicMixin, action: ActionLogicMixin, - relationship: RelationshipLogic, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, + relationship: RelationshipLogicMixin, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, time: TimeLogicMixin): self.player = player self.skill_option = skill_option From 597d7f637e1a72e00f656adf6f4717c929b07337 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 19 Nov 2023 23:14:37 -0500 Subject: [PATCH 189/482] document logic mixins and content packs design --- worlds/stardew_valley/logic/logic.py | 8 ++--- .../logic/logic_and_mods_design.md | 33 +++++++++++++++++++ worlds/stardew_valley/logic/museum_logic.py | 25 +++++--------- worlds/stardew_valley/logic/quest_logic.py | 6 ++-- worlds/stardew_valley/logic/wallet_logic.py | 15 ++++----- worlds/stardew_valley/mods/logic/mod_logic.py | 4 +-- .../mods/logic/special_orders_logic.py | 6 ++-- 7 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 worlds/stardew_valley/logic/logic_and_mods_design.md diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9f26424d21d0..41a82698bca2 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -21,7 +21,7 @@ from .mine_logic import MineLogic from .money_logic import MoneyLogicMixin from .monster_logic import MonsterLogic -from .museum_logic import MuseumLogic +from .museum_logic import MuseumLogicMixin from .pet_logic import PetLogic from .quest_logic import QuestLogic from .received_logic import ReceivedLogicMixin @@ -34,7 +34,7 @@ from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic from .traveling_merchant_logic import TravelingMerchantLogicMixin -from .wallet_logic import WalletLogic +from .wallet_logic import WalletLogicMixin from ..data import all_fish, all_purchasable_seeds, all_crops from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name @@ -117,8 +117,8 @@ def __post_init__(self): self.buildings = BuildingLogicMixin(self.player, self.registry, self.options).buildings self.shipping = ShippingLogicMixin(self.player, self.registry, self.options).shipping self.relationship = RelationshipLogicMixin(self.player, self.registry, self.options).relationship - self.museum = MuseumLogic(self.player, self.options.museumsanity, self.received, self.has, self.region, self.action) - self.wallet = WalletLogic(self.player, self.received, self.museum) + self.museum = MuseumLogicMixin(self.player, self.registry, self.options).museum + self.wallet = WalletLogicMixin(self.player, self.registry, self.options).wallet self.combat = CombatLogic(self.player, self.received, self.region) self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) diff --git a/worlds/stardew_valley/logic/logic_and_mods_design.md b/worlds/stardew_valley/logic/logic_and_mods_design.md new file mode 100644 index 000000000000..ebd4bb26dfbd --- /dev/null +++ b/worlds/stardew_valley/logic/logic_and_mods_design.md @@ -0,0 +1,33 @@ +# Logic mixin + +Mixins are used to split the logic building methods in multiple classes, so it's more scoped and easier to extend specific methods. + +One single instance of Logic is necessary so mods can change the logics. + +Creating the rules for actual items has to be outside the `logic` instance. Once the vanilla logic builder is created, mods will be able to replace the logic +implementations by their own modified version. For instance, the `combat` logic can be replaced by the magic mod to extends its methods to add spells in the +combat logic. + +# Content pack (future) + +Instead of using modules to hold the data, and have each mods adding their data to existing content, each mod data should be in a `ContentPack`. Vanilla, Ginger +Island, or anything that could be disabled would be in a content pack as well. + +Eventually, Vanilla content could even be disabled (a split would be required for items that are necessary to all content packs) to have a Ginger Island only +play through created without the heavy vanilla logic computation. + +## Unpacking + +Steps to unpack content follows the same steps has the world initialisation. Content pack however need to be unpacked in a specific order, based on their +dependencies. Vanilla would always be first, then anything that depends only on Vanilla, etc. + +1. In `generate_early`, content packs are selected. The logic builders are created and content packs are unpacked so all their content is in the proper + item/npc/weapon lists. + - `ContentPack` instances are shared across players. However, some mods need to modify content of other packs. In that case, an instance of the content is + created specifically for that player (For instance, SVE changes the Wizard). This probably does not happen enough to require sharing those instances. If + necessary, a FlyWeight design pattern could be used. +2. In `create_regions`, AP regions and entrances are unpacked, and randomized if needed. +3. In `create_items`, AP items are unpacked, and randomized. +4. In `set_rules`, the rules are applied to the AP entrances and locations. Each content pack have to apply the proper rules for their entrances and locations. + - (future) To begin this step, sphere 0 could be simplified instantly as sphere 0 regions and items are already known. +5. Nothing to do in `generate_basic`. diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 1fffaaf9175c..924e2ee5cf35 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -2,32 +2,23 @@ from Utils import cache_self1 from .action_logic import ActionLogicMixin +from .base_logic import BaseLogic from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals -from ..options import Museumsanity from ..stardew_rule import StardewRule, And, False_, Count from ..strings.region_names import Region -class MuseumLogic: - player: int - museum_option: Museumsanity - received = ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - action: ActionLogicMixin +class MuseumLogicMixin(BaseLogic): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.museum = MuseumLogic(*args, **kwargs) - def __init__(self, player: int, museum_option: Museumsanity, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogicMixin): - self.player = player - self.museum_option = museum_option - self.received = received - self.has = has - self.region = region - self.action = action + +class MuseumLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, ActionLogicMixin): def can_donate_museum_items(self, number: int) -> StardewRule: return self.region.can_reach(Region.museum) & self.can_find_museum_items(number) @@ -70,7 +61,7 @@ def can_find_museum_items(self, number: int) -> StardewRule: def can_complete_museum(self) -> StardewRule: rules = [self.region.can_reach(Region.museum)] - if self.museum_option != options.Museumsanity.option_none: + if self.options.museumsanity != options.Museumsanity.option_none: rules.append(self.received("Traveling Merchant Metal Detector", 4)) for donation in all_museum_items: diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index b07de4c9ef8b..c5b6c496bdeb 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -15,7 +15,7 @@ from .skill_logic import SkillLogic from .time_logic import TimeLogicMixin from .tool_logic import ToolLogic -from .wallet_logic import WalletLogic +from .wallet_logic import WalletLogicMixin from ..options import Mods from ..stardew_rule import StardewRule, Has, True_ from ..strings.artisan_good_names import ArtisanGood @@ -52,14 +52,14 @@ class QuestLogic: combat: CombatLogic season: SeasonLogicMixin skill: SkillLogic - wallet: WalletLogic + wallet: WalletLogicMixin quest_rules: Dict[str, StardewRule] def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogicMixin, has: HasLogicMixin, mine: MineLogic, region: RegionLogicMixin, action: ActionLogicMixin, relationship: RelationshipLogicMixin, building: BuildingLogicMixin, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): + money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, wallet: WalletLogicMixin, mods_option: Mods): self.player = player self.skill = skill self.received = received diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index fe936b081eee..3ed36d1a3c6e 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,21 +1,18 @@ from functools import cached_property -from .museum_logic import MuseumLogic +from .base_logic import BaseLogic from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule from ..strings.wallet_item_names import Wallet -class WalletLogic: - player: int - received = ReceivedLogicMixin - museum: MuseumLogic +class WalletLogicMixin(BaseLogic): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.wallet = WalletLogic(*args, **kwargs) - def __init__(self, player: int, received: ReceivedLogicMixin, museum: MuseumLogic): - self.player = player - self.received = received - self.museum = museum +class WalletLogic(ReceivedLogicMixin): @cached_property def can_speak_dwarf(self) -> StardewRule: return self.received(Wallet.dwarvish_translation_guide) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 326894f9e0eb..32c40c9bcda7 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -29,7 +29,7 @@ from ...logic.skill_logic import SkillLogic from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogic -from ...logic.wallet_logic import WalletLogic +from ...logic.wallet_logic import WalletLogicMixin from ...options import SkillProgression, ElevatorProgression, Mods @@ -50,7 +50,7 @@ def __init__(self, player: int, registry: LogicRegistry, options, skill_option: has: HasLogicMixin, region: RegionLogicMixin, action: ActionLogicMixin, artisan: ArtisanLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogicMixin, museum: MuseumLogic, building: BuildingLogicMixin, - wallet: WalletLogic, + wallet: WalletLogicMixin, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogicMixin, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): super().__init__(player, registry, options) diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index a3e12339df2c..253e3813ae27 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -7,7 +7,7 @@ from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin -from ...logic.wallet_logic import WalletLogic +from ...logic.wallet_logic import WalletLogicMixin from ...options import Mods from ...strings.artisan_good_names import ArtisanGood from ...strings.craftable_names import Consumable, Edible, Bomb @@ -33,12 +33,12 @@ class ModSpecialOrderLogic: region: RegionLogicMixin relationship: RelationshipLogicMixin season: SeasonLogicMixin - wallet: WalletLogic + wallet: WalletLogicMixin mods_option: Mods def __init__(self, player: int, action: ActionLogicMixin, artisan: ArtisanLogicMixin, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, region: RegionLogicMixin, relationship: RelationshipLogicMixin, - season: SeasonLogicMixin, wallet: WalletLogic, mods_option: Mods): + season: SeasonLogicMixin, wallet: WalletLogicMixin, mods_option: Mods): self.player = player self.action = action self.artisan = artisan From 67445af587aade626aa0e9199d1f23b189e4b09d Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 20 Nov 2023 00:48:37 -0500 Subject: [PATCH 190/482] rework mixins again --- worlds/stardew_valley/logic/base_logic.py | 48 ++++++++++------- worlds/stardew_valley/logic/has_logic.py | 2 +- worlds/stardew_valley/logic/logic.py | 54 +++++++++++-------- .../logic/logic_and_mods_design.md | 31 +++++++++-- worlds/stardew_valley/logic/received_logic.py | 4 +- worlds/stardew_valley/logic/region_logic.py | 12 ++--- worlds/stardew_valley/logic/season_logic.py | 20 +++---- worlds/stardew_valley/logic/time_logic.py | 13 ++--- .../logic/traveling_merchant_logic.py | 10 ++-- worlds/stardew_valley/mods/logic/mod_logic.py | 8 +-- 10 files changed, 123 insertions(+), 79 deletions(-) diff --git a/worlds/stardew_valley/logic/base_logic.py b/worlds/stardew_valley/logic/base_logic.py index 63af8042a440..3d6521f19179 100644 --- a/worlds/stardew_valley/logic/base_logic.py +++ b/worlds/stardew_valley/logic/base_logic.py @@ -1,36 +1,44 @@ -from dataclasses import dataclass, field -from typing import Dict +from __future__ import annotations + +from typing import TypeVar, Generic from ..options import StardewValleyOptions -from ..stardew_rule import StardewRule -@dataclass(frozen=False) class LogicRegistry: - player: int - options: StardewValleyOptions - item_rules: Dict[str, StardewRule] = field(default_factory=dict) + def __init__(self): + self.item_rules = {} + self.sapling_rules = {} + self.tree_fruit_rules = {} + self.seed_rules = {} + self.cooking_rules = {} + self.crafting_rules = {} + self.crop_rules = {} + self.fish_rules = {} + self.museum_rules = {} + self.festival_rules = {} + self.quest_rules = {} + self.building_rules = {} + + +class BaseLogicMixin: + def __init__(self, *args, **kwargs): + pass + - sapling_rules: Dict[str, StardewRule] = field(default_factory=dict) - tree_fruit_rules: Dict[str, StardewRule] = field(default_factory=dict) - seed_rules: Dict[str, StardewRule] = field(default_factory=dict) - cooking_rules: Dict[str, StardewRule] = field(default_factory=dict) - crafting_rules: Dict[str, StardewRule] = field(default_factory=dict) - crop_rules: Dict[str, StardewRule] = field(default_factory=dict) - fish_rules: Dict[str, StardewRule] = field(default_factory=dict) - museum_rules: Dict[str, StardewRule] = field(default_factory=dict) - festival_rules: Dict[str, StardewRule] = field(default_factory=dict) - quest_rules: Dict[str, StardewRule] = field(default_factory=dict) - building_rules: Dict[str, StardewRule] = field(default_factory=dict) +T = TypeVar("T", bound=BaseLogicMixin) -class BaseLogic: +class BaseLogic(BaseLogicMixin, Generic[T]): player: int registry: LogicRegistry options: StardewValleyOptions + logic: T - def __init__(self, player: int, registry: LogicRegistry, options: StardewValleyOptions): + def __init__(self, player: int, registry: LogicRegistry, options: StardewValleyOptions, logic: T): + super().__init__(player, registry, options, logic) self.player = player self.registry = registry self.options = options + self.logic = logic diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index f4a02163aa5d..ae2293f1df77 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -4,7 +4,7 @@ from ..stardew_rule import StardewRule, True_, And, Or, Has, Count -class HasLogicMixin(BaseLogic): +class HasLogicMixin(BaseLogic[None]): def __call__(self, *args, **kwargs) -> StardewRule: count = None if len(args) >= 2: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 41a82698bca2..998cc1eb1b57 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -7,7 +7,7 @@ from .action_logic import ActionLogicMixin from .arcade_logic import ArcadeLogicMixin from .artisan_logic import ArtisanLogicMixin -from .base_logic import LogicRegistry, BaseLogic +from .base_logic import LogicRegistry from .building_logic import BuildingLogicMixin from .bundle_logic import BundleLogic from .combat_logic import CombatLogic @@ -87,25 +87,32 @@ # FIXME this should not extend LogicRegistry, but it's a step in the migration. @dataclass(frozen=False, repr=False) -class StardewLogic(BaseLogic, LogicRegistry): +class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin): player: int options: StardewValleyOptions - def __post_init__(self): - # FIXME - self.registry = self - - self.received = ReceivedLogicMixin(self.player, self.registry, self.options) - self.has = HasLogicMixin(self.player, self.registry, self.options) - self.region = RegionLogicMixin(self.player, self.registry, self.options).region - self.traveling_merchant = TravelingMerchantLogicMixin(self.player, self.registry, self.options).traveling_merchant - self.time = TimeLogicMixin(self.player, self.registry, self.options).time - self.season = SeasonLogicMixin(self.player, self.registry, self.options).season - self.money = MoneyLogicMixin(self.player, self.registry, self.options).money - self.action = ActionLogicMixin(self.player, self.registry, self.options).action - self.arcade = ArcadeLogicMixin(self.player, self.registry, self.options).arcade - self.artisan = ArtisanLogicMixin(self.player, self.registry, self.options).artisan - self.gifts = GiftLogicMixin(self.player, self.registry, self.options).gifts + def __init__(self, player: int, options: StardewValleyOptions): + self.registry = LogicRegistry() + super().__init__(player, self.registry, options, self) + + self.item_rules = self.registry.item_rules + self.sapling_rules = self.registry.sapling_rules + self.tree_fruit_rules = self.registry.tree_fruit_rules + self.seed_rules = self.registry.seed_rules + self.cooking_rules = self.registry.cooking_rules + self.crafting_rules = self.registry.crafting_rules + self.crop_rules = self.registry.crop_rules + self.fish_rules = self.registry.fish_rules + self.museum_rules = self.registry.museum_rules + self.festival_rules = self.registry.festival_rules + self.quest_rules = self.registry.quest_rules + self.building_rules = self.registry.building_rules + + self.money = MoneyLogicMixin(self.player, self.registry, self.options, self).money + self.action = ActionLogicMixin(self.player, self.registry, self.options, self).action + self.arcade = ArcadeLogicMixin(self.player, self.registry, self.options, self).arcade + self.artisan = ArtisanLogicMixin(self.player, self.registry, self.options, self).artisan + self.gifts = GiftLogicMixin(self.player, self.registry, self.options, self).gifts tool_option = self.options.tool_progression skill_option = self.options.skill_progression elevator_option = self.options.elevator_progression @@ -114,11 +121,11 @@ def __post_init__(self): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.buildings = BuildingLogicMixin(self.player, self.registry, self.options).buildings - self.shipping = ShippingLogicMixin(self.player, self.registry, self.options).shipping - self.relationship = RelationshipLogicMixin(self.player, self.registry, self.options).relationship - self.museum = MuseumLogicMixin(self.player, self.registry, self.options).museum - self.wallet = WalletLogicMixin(self.player, self.registry, self.options).wallet + self.buildings = BuildingLogicMixin(self.player, self.registry, self.options, self).buildings + self.shipping = ShippingLogicMixin(self.player, self.registry, self.options, self).shipping + self.relationship = RelationshipLogicMixin(self.player, self.registry, self.options, self).relationship + self.museum = MuseumLogicMixin(self.player, self.registry, self.options, self).museum + self.wallet = WalletLogicMixin(self.player, self.registry, self.options, self).wallet self.combat = CombatLogic(self.player, self.received, self.region) self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) @@ -145,7 +152,8 @@ def __post_init__(self): self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, self.registry, self.options, skill_option, elevator_option, mods_option, self.received, self.has, self.region, + self.mod = ModLogic(self.player, self.registry, self.options, self, + skill_option, elevator_option, mods_option, self.received, self.has, self.region, self.action, self.artisan, self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, diff --git a/worlds/stardew_valley/logic/logic_and_mods_design.md b/worlds/stardew_valley/logic/logic_and_mods_design.md index ebd4bb26dfbd..b1d2109af6ac 100644 --- a/worlds/stardew_valley/logic/logic_and_mods_design.md +++ b/worlds/stardew_valley/logic/logic_and_mods_design.md @@ -2,13 +2,38 @@ Mixins are used to split the logic building methods in multiple classes, so it's more scoped and easier to extend specific methods. -One single instance of Logic is necessary so mods can change the logics. +One single instance of Logic is necessary so mods can change the logics. This means that, when calling itself, a `Logic` class has to call its instance in +the `logic`, because it might have been overriden. + +```python +class TimeLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.time = TimeLogic(*args, **kwargs) + + +class TimeLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin]]): + + def has_lived_months(self, number: int) -> StardewRule: + return self.logic.received(Event.month_end, number) + + def has_year_two(self) -> StardewRule: + return self.logic.time.has_lived_months(4) + + def has_year_three(self) -> StardewRule: + return self.logic.time.has_lived_months(8) +``` Creating the rules for actual items has to be outside the `logic` instance. Once the vanilla logic builder is created, mods will be able to replace the logic implementations by their own modified version. For instance, the `combat` logic can be replaced by the magic mod to extends its methods to add spells in the combat logic. -# Content pack (future) +## Logic class created on the fly (idea) + +The logic class could be created dynamically, based on the `LogicMixin` provided by the content packs. This would allow replacing completely mixins, instead of +overriding their logic afterward. Might be too complicated for no real gain tho... + +# Content pack (idea) Instead of using modules to hold the data, and have each mods adding their data to existing content, each mod data should be in a `ContentPack`. Vanilla, Ginger Island, or anything that could be disabled would be in a content pack as well. @@ -29,5 +54,5 @@ dependencies. Vanilla would always be first, then anything that depends only on 2. In `create_regions`, AP regions and entrances are unpacked, and randomized if needed. 3. In `create_items`, AP items are unpacked, and randomized. 4. In `set_rules`, the rules are applied to the AP entrances and locations. Each content pack have to apply the proper rules for their entrances and locations. - - (future) To begin this step, sphere 0 could be simplified instantly as sphere 0 regions and items are already known. + - (idea) To begin this step, sphere 0 could be simplified instantly as sphere 0 regions and items are already known. 5. Nothing to do in `generate_basic`. diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 43ff16fc8198..2b35e4e21cbe 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,10 +1,10 @@ from typing import Union, Optional, Tuple -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived -class ReceivedLogicMixin(BaseLogic): +class ReceivedLogicMixin(BaseLogic[None], BaseLogicMixin): def __call__(self, *args, **kwargs) -> StardewRule: count = 1 if len(args) >= 2: diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 772cd3c35ab2..86bf5b35b783 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,17 +1,17 @@ from typing import Tuple from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from ..stardew_rule import StardewRule, And, Or, Reach, Count -class RegionLogicMixin(BaseLogic): +class RegionLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.region = RegionLogic(*args, **kwargs) -class RegionLogic(BaseLogic): +class RegionLogic(BaseLogic[RegionLogicMixin]): @cache_self1 def can_reach(self, region_name: str) -> StardewRule: @@ -19,11 +19,11 @@ def can_reach(self, region_name: str) -> StardewRule: @cache_self1 def can_reach_any(self, region_names: Tuple[str, ...]) -> StardewRule: - return Or(*(self.can_reach(spot) for spot in region_names)) + return Or(*(self.logic.region.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all(self, region_names: Tuple[str, ...]) -> StardewRule: - return And(*(self.can_reach(spot) for spot in region_names)) + return And(*(self.logic.region.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule: @@ -31,7 +31,7 @@ def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule num_required = len(region_names) - 1 if num_required <= 0: num_required = len(region_names) - return Count(num_required, [self.can_reach(spot) for spot in region_names]) + return Count(num_required, [self.logic.region.can_reach(spot) for spot in region_names]) @cache_self1 def can_reach_location(self, location_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 77089fbb3fb2..d006b799deea 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -1,7 +1,7 @@ -from typing import Iterable +from typing import Iterable, Union from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin from .time_logic import TimeLogicMixin from ..options import SeasonRandomization @@ -10,13 +10,13 @@ from ..strings.season_names import Season -class SeasonLogicMixin(BaseLogic): +class SeasonLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.season = SeasonLogic(*args, **kwargs) -class SeasonLogic(TimeLogicMixin, ReceivedLogicMixin): +class SeasonLogic(BaseLogic[Union[SeasonLogicMixin, TimeLogicMixin, ReceivedLogicMixin]]): @cache_self1 def has(self, season: str) -> StardewRule: @@ -24,22 +24,22 @@ def has(self, season: str) -> StardewRule: return True_() seasons_order = [Season.spring, Season.summer, Season.fall, Season.winter] if self.options.season_randomization == SeasonRandomization.option_progressive: - return self.received(Season.progressive, seasons_order.index(season)) + return self.logic.received(Season.progressive, seasons_order.index(season)) if self.options.season_randomization == SeasonRandomization.option_disabled: if season == Season.spring: return True_() - return self.time.has_lived_months(1) - return self.received(season) + return self.logic.time.has_lived_months(1) + return self.logic.received(season) def has_any(self, seasons: Iterable[str]): if not seasons: return True_() - return Or(*(self.has(season) for season in seasons)) + return Or(*(self.logic.season.has(season) for season in seasons)) def has_any_not_winter(self): - return self.has_any([Season.spring, Season.summer, Season.fall]) + return self.logic.season.has_any([Season.spring, Season.summer, Season.fall]) def has_all(self, seasons: Iterable[str]): if not seasons: return True_() - return And(*(self.has(season) for season in seasons)) + return And(*(self.logic.season.has(season) for season in seasons)) diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 6af2408df32b..9152c3fa2458 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -1,7 +1,8 @@ from functools import cached_property +from typing import Union from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule, CountPercent, True_ @@ -9,13 +10,13 @@ MONTH_COEFFICIENT = 100 // MAX_MONTHS -class TimeLogicMixin(BaseLogic): +class TimeLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.time = TimeLogic(*args, **kwargs) -class TimeLogic(ReceivedLogicMixin): +class TimeLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin]]): @cache_self1 def has_lived_months(self, number: int) -> StardewRule: @@ -26,12 +27,12 @@ def has_lived_months(self, number: int) -> StardewRule: @cached_property def has_lived_max_months(self) -> StardewRule: - return self.has_lived_months(MAX_MONTHS) + return self.logic.time.has_lived_months(MAX_MONTHS) @cached_property def has_year_two(self) -> StardewRule: - return self.has_lived_months(4) + return self.logic.time.has_lived_months(4) @cached_property def has_year_three(self) -> StardewRule: - return self.has_lived_months(8) + return self.logic.time.has_lived_months(8) diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index d34cadacbde9..7467c79718fc 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -1,20 +1,22 @@ -from .base_logic import BaseLogic +from typing import Union + +from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin from ..stardew_rule import True_ from ..strings.calendar_names import Weekday -class TravelingMerchantLogicMixin(BaseLogic): +class TravelingMerchantLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.traveling_merchant = TravelingMerchantLogic(*args, **kwargs) -class TravelingMerchantLogic(ReceivedLogicMixin): +class TravelingMerchantLogic(BaseLogic[Union[TravelingMerchantLogicMixin, ReceivedLogicMixin]]): def has_days(self, number_days: int = 1): if number_days <= 0: return True_() tier = min(7, max(1, number_days)) traveling_merchant_days = tuple(f"Traveling Merchant: {day}" for day in Weekday.all_days) - return self.received(traveling_merchant_days, tier) + return self.logic.received(traveling_merchant_days, tier) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 32c40c9bcda7..59c475f82e8c 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -45,19 +45,19 @@ class ModLogic(BaseLogic): skill: ModSkillLogic sve: SVELogic - def __init__(self, player: int, registry: LogicRegistry, options, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, + def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, action: ActionLogicMixin, artisan: ArtisanLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogicMixin, - museum: MuseumLogic, building: BuildingLogicMixin, + museum: MuseumLogic, building: BuildingLogicMixin, wallet: WalletLogicMixin, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, time: TimeLogicMixin, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): - super().__init__(player, registry, options) + super().__init__(player, registry, options, logic) self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, museum, tool, crafting) self.magic = MagicLogic(player, mods, received, region) self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) - self.buildings = ModBuildingLogic(player, registry, options) + self.buildings = ModBuildingLogic(player, registry, options, logic) self.special_orders = ModSpecialOrderLogic(player, action, artisan, crafting, crop, has, region, relationship, season, wallet, mods) self.elevator = ModElevatorLogic(player, elevator_option, mods, received) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) From abe0d45cd1caf7484e2adb7802fdd50d37ea83cb Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 20 Nov 2023 01:04:10 -0500 Subject: [PATCH 191/482] more mixin rework --- worlds/stardew_valley/logic/action_logic.py | 20 ++++++------ worlds/stardew_valley/logic/arcade_logic.py | 16 +++++---- worlds/stardew_valley/logic/artisan_logic.py | 34 +++++++++++--------- worlds/stardew_valley/logic/gift_logic.py | 8 ++--- worlds/stardew_valley/logic/logic.py | 9 ++---- worlds/stardew_valley/logic/money_logic.py | 19 ++++++----- 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/worlds/stardew_valley/logic/action_logic.py b/worlds/stardew_valley/logic/action_logic.py index 162c009ea0cb..820ae4ead429 100644 --- a/worlds/stardew_valley/logic/action_logic.py +++ b/worlds/stardew_valley/logic/action_logic.py @@ -1,5 +1,7 @@ +from typing import Union + from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -9,30 +11,30 @@ from ..strings.region_names import Region -class ActionLogicMixin(BaseLogic): +class ActionLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.action = ActionLogic(*args, **kwargs) -class ActionLogic(RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class ActionLogic(BaseLogic[Union[ActionLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): def can_watch(self, channel: str = None): tv_rule = True_() if channel is None: return tv_rule - return self.received(channel) & tv_rule + return self.logic.received(channel) & tv_rule def can_pan(self) -> StardewRule: - return self.received("Glittering Boulder Removed") & self.region.can_reach(Region.mountain) + return self.logic.received("Glittering Boulder Removed") & self.logic.region.can_reach(Region.mountain) def can_pan_at(self, region: str) -> StardewRule: - return self.region.can_reach(region) & self.can_pan() + return self.logic.region.can_reach(region) & self.logic.action.can_pan() @cache_self1 def can_open_geode(self, geode: str) -> StardewRule: - blacksmith_access = self.region.can_reach(Region.blacksmith) + blacksmith_access = self.logic.region.can_reach(Region.blacksmith) geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni] if geode == Generic.any: - return blacksmith_access & Or(*(self.has(geode_type) for geode_type in geodes)) - return blacksmith_access & self.has(geode) + return blacksmith_access & Or(*(self.logic.has(geode_type) for geode_type in geodes)) + return blacksmith_access & self.logic.has(geode) diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index 08990e86fd6c..a5d839a2a25c 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -1,4 +1,6 @@ -from .base_logic import BaseLogic +from typing import Union + +from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .. import options @@ -6,27 +8,27 @@ from ..strings.region_names import Region -class ArcadeLogicMixin(BaseLogic): +class ArcadeLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.arcade = ArcadeLogic(*args, **kwargs) -class ArcadeLogic(RegionLogicMixin, ReceivedLogicMixin): +class ArcadeLogic(BaseLogic[Union[ArcadeLogicMixin, RegionLogicMixin, ReceivedLogicMixin]]): def has_jotpk_power_level(self, power_level: int) -> StardewRule: if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return True_() jotpk_buffs = ("JotPK: Progressive Boots", "JotPK: Progressive Gun", "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate") - return self.received(jotpk_buffs, power_level) + return self.logic.received(jotpk_buffs, power_level) def has_junimo_kart_power_level(self, power_level: int) -> StardewRule: if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return True_() - return self.received("Junimo Kart: Extra Life", power_level) + return self.logic.received("Junimo Kart: Extra Life", power_level) def has_junimo_kart_max_level(self) -> StardewRule: - play_rule = self.region.can_reach(Region.junimo_kart_3) + play_rule = self.logic.region.can_reach(Region.junimo_kart_3) if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return play_rule - return self.has_junimo_kart_power_level(8) + return self.logic.arcade.has_junimo_kart_power_level(8) diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 67b847da4e53..6ac8a2d88677 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -1,4 +1,6 @@ -from .base_logic import BaseLogic +from typing import Union + +from .base_logic import BaseLogic, BaseLogicMixin from .has_logic import HasLogicMixin from .time_logic import TimeLogicMixin from ..stardew_rule import StardewRule @@ -7,45 +9,45 @@ from ..strings.machine_names import Machine -class ArtisanLogicMixin(BaseLogic): +class ArtisanLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.artisan = ArtisanLogic(*args, **kwargs) -class ArtisanLogic(TimeLogicMixin, HasLogicMixin): +class ArtisanLogic(BaseLogic[Union[ArtisanLogicMixin, TimeLogicMixin, HasLogicMixin]]): def has_jelly(self) -> StardewRule: - return self.can_preserves_jar(Fruit.any) + return self.logic.artisan.can_preserves_jar(Fruit.any) def has_pickle(self) -> StardewRule: - return self.can_preserves_jar(Vegetable.any) + return self.logic.artisan.can_preserves_jar(Vegetable.any) def can_preserves_jar(self, item: str) -> StardewRule: - machine_rule = self.has(Machine.preserves_jar) + machine_rule = self.logic.has(Machine.preserves_jar) if item == Generic.any: return machine_rule if item == Fruit.any: - return machine_rule & self.has(all_fruits, 1) + return machine_rule & self.logic.has(all_fruits, 1) if item == Vegetable.any: - return machine_rule & self.has(all_vegetables, 1) - return machine_rule & self.has(item) + return machine_rule & self.logic.has(all_vegetables, 1) + return machine_rule & self.logic.has(item) def has_wine(self) -> StardewRule: - return self.can_keg(Fruit.any) + return self.logic.artisan.can_keg(Fruit.any) def has_juice(self) -> StardewRule: - return self.can_keg(Vegetable.any) + return self.logic.artisan.can_keg(Vegetable.any) def can_keg(self, item: str) -> StardewRule: - machine_rule = self.has(Machine.keg) + machine_rule = self.logic.has(Machine.keg) if item == Generic.any: return machine_rule if item == Fruit.any: - return machine_rule & self.has(all_fruits, 1) + return machine_rule & self.logic.has(all_fruits, 1) if item == Vegetable.any: - return machine_rule & self.has(all_vegetables, 1) - return machine_rule & self.has(item) + return machine_rule & self.logic.has(all_vegetables, 1) + return machine_rule & self.logic.has(item) def can_mayonnaise(self, item: str) -> StardewRule: - return self.has(Machine.mayonnaise_machine) & self.has(item) + return self.logic.has(Machine.mayonnaise_machine) & self.logic.has(item) diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index d963913e9cd5..29be419a6d2b 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -1,20 +1,20 @@ from functools import cached_property -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .has_logic import HasLogicMixin from ..stardew_rule import StardewRule from ..strings.animal_product_names import AnimalProduct from ..strings.gift_names import Gift -class GiftLogicMixin(BaseLogic): +class GiftLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.gifts = GiftLogic(*args, **kwargs) -class GiftLogic(HasLogicMixin): +class GiftLogic(BaseLogic[HasLogicMixin]): @cached_property def has_any_universal_love(self) -> StardewRule: - return self.has(Gift.golden_pumpkin) | self.has(Gift.pearl) | self.has("Prismatic Shard") | self.has(AnimalProduct.rabbit_foot) + return self.logic.has(Gift.golden_pumpkin) | self.logic.has(Gift.pearl) | self.logic.has("Prismatic Shard") | self.logic.has(AnimalProduct.rabbit_foot) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 998cc1eb1b57..dc350dea12bb 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -85,9 +85,9 @@ fishing_regions = [Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west] -# FIXME this should not extend LogicRegistry, but it's a step in the migration. @dataclass(frozen=False, repr=False) -class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin): +class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, + ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin): player: int options: StardewValleyOptions @@ -108,11 +108,6 @@ def __init__(self, player: int, options: StardewValleyOptions): self.quest_rules = self.registry.quest_rules self.building_rules = self.registry.building_rules - self.money = MoneyLogicMixin(self.player, self.registry, self.options, self).money - self.action = ActionLogicMixin(self.player, self.registry, self.options, self).action - self.arcade = ArcadeLogicMixin(self.player, self.registry, self.options, self).arcade - self.artisan = ArtisanLogicMixin(self.player, self.registry, self.options, self).artisan - self.gifts = GiftLogicMixin(self.player, self.registry, self.options, self).gifts tool_option = self.options.tool_progression skill_option = self.options.skill_progression elevator_option = self.options.elevator_progression diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index e9ff441beb77..ef7b8c6c3811 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -1,4 +1,7 @@ +from typing import Union + from Utils import cache_self1 +from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -11,19 +14,19 @@ "25 Qi Gems", "20 Qi Gems", "10 Qi Gems") -class MoneyLogicMixin(TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class MoneyLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.money = MoneyLogic(*args, **kwargs) -class MoneyLogic(TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class MoneyLogic(BaseLogic[Union[MoneyLogicMixin, TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: if amount < 2000: return True_() - shipping_bin_rule = self.region.can_reach(Region.shipping) + shipping_bin_rule = self.logic.region.can_reach(Region.shipping) if amount < 10000: return shipping_bin_rule @@ -34,20 +37,20 @@ def can_have_earned_total(self, amount: int) -> StardewRule: def can_spend(self, amount: int) -> StardewRule: if self.options.starting_money == -1: return True_() - return self.can_have_earned_total(amount * 5) + return self.logic.money.can_have_earned_total(amount * 5) # Should be cached def can_spend_at(self, region: str, amount: int) -> StardewRule: - return self.region.can_reach(region) & self.can_spend(amount) + return self.logic.region.can_reach(region) & self.logic.money.can_spend(amount) # Should be cached def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() if currency == Currency.money: - return self.can_spend_at(region, amount) + return self.logic.money.can_spend_at(region, amount) if currency == Currency.qi_gem: number_rewards = min(10, max(1, (amount // 10) + 2)) - return self.received(qi_gem_rewards, number_rewards) + return self.logic.received(qi_gem_rewards, number_rewards) - return self.region.can_reach(region) & self.has(currency) + return self.logic.region.can_reach(region) & self.logic.has(currency) From 5b6e089d7cccd998f70174ea31a9ea9567d260c5 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 20 Nov 2023 22:34:41 -0500 Subject: [PATCH 192/482] more mixin rework --- worlds/stardew_valley/logic/building_logic.py | 52 ++++++------- worlds/stardew_valley/logic/combat_logic.py | 42 +++++------ worlds/stardew_valley/logic/logic.py | 24 ++---- worlds/stardew_valley/logic/monster_logic.py | 30 ++++---- worlds/stardew_valley/logic/museum_logic.py | 39 +++++----- .../logic/relationship_logic.py | 75 ++++++++++--------- worlds/stardew_valley/logic/shipping_logic.py | 15 ++-- worlds/stardew_valley/logic/wallet_logic.py | 10 +-- .../stardew_valley/mods/logic/magic_logic.py | 60 +++++++-------- worlds/stardew_valley/mods/logic/mod_logic.py | 48 ++++++------ 10 files changed, 188 insertions(+), 207 deletions(-) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 84749b4ed5e7..ecb503bf4797 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -1,7 +1,7 @@ -from typing import Dict +from typing import Dict, Union from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin @@ -17,34 +17,34 @@ from ..strings.region_names import Region -class BuildingLogicMixin(BaseLogic): +class BuildingLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.buildings = BuildingLogic(*args, **kwargs) -class BuildingLogic(MoneyLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class BuildingLogic(BaseLogic[Union[BuildingLogicMixin, MoneyLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): def initialize_rules(self): self.registry.building_rules.update({ # @formatter:off - Building.barn: self.money.can_spend(6000) & self.has((Material.wood, Material.stone)), - Building.big_barn: self.money.can_spend(12000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.barn), - Building.deluxe_barn: self.money.can_spend(25000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_barn), - Building.coop: self.money.can_spend(4000) & self.has((Material.wood, Material.stone)), - Building.big_coop: self.money.can_spend(10000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.coop), - Building.deluxe_coop: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.big_coop), - Building.fish_pond: self.money.can_spend(5000) & self.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), - Building.mill: self.money.can_spend(2500) & self.has((Material.stone, Material.wood, ArtisanGood.cloth)), - Building.shed: self.money.can_spend(15000) & self.has(Material.wood), - Building.big_shed: self.money.can_spend(20000) & self.has((Material.wood, Material.stone)) & self.has_building(Building.shed), - Building.silo: self.money.can_spend(100) & self.has((Material.stone, Material.clay, MetalBar.copper)), - Building.slime_hutch: self.money.can_spend(10000) & self.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), - Building.stable: self.money.can_spend(10000) & self.has((Material.hardwood, MetalBar.iron)), - Building.well: self.money.can_spend(1000) & self.has(Material.stone), - Building.shipping_bin: self.money.can_spend(250) & self.has(Material.wood), - Building.kitchen: self.money.can_spend(10000) & self.has(Material.wood) & self.has_house(0), - Building.kids_room: self.money.can_spend(50000) & self.has(Material.hardwood) & self.has_house(1), - Building.cellar: self.money.can_spend(100000) & self.has_house(2), + Building.barn: self.logic.money.can_spend(6000) & self.logic.has((Material.wood, Material.stone)), + Building.big_barn: self.logic.money.can_spend(12000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.barn), + Building.deluxe_barn: self.logic.money.can_spend(25000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.big_barn), + Building.coop: self.logic.money.can_spend(4000) & self.logic.has((Material.wood, Material.stone)), + Building.big_coop: self.logic.money.can_spend(10000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.coop), + Building.deluxe_coop: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.big_coop), + Building.fish_pond: self.logic.money.can_spend(5000) & self.logic.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), + Building.mill: self.logic.money.can_spend(2500) & self.logic.has((Material.stone, Material.wood, ArtisanGood.cloth)), + Building.shed: self.logic.money.can_spend(15000) & self.logic.has(Material.wood), + Building.big_shed: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.shed), + Building.silo: self.logic.money.can_spend(100) & self.logic.has((Material.stone, Material.clay, MetalBar.copper)), + Building.slime_hutch: self.logic.money.can_spend(10000) & self.logic.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), + Building.stable: self.logic.money.can_spend(10000) & self.logic.has((Material.hardwood, MetalBar.iron)), + Building.well: self.logic.money.can_spend(1000) & self.logic.has(Material.stone), + Building.shipping_bin: self.logic.money.can_spend(250) & self.logic.has(Material.wood), + Building.kitchen: self.logic.money.can_spend(10000) & self.logic.has(Material.wood) & self.logic.buildings.has_house(0), + Building.kids_room: self.logic.money.can_spend(50000) & self.logic.has(Material.hardwood) & self.logic.buildings.has_house(1), + Building.cellar: self.logic.money.can_spend(100000) & self.logic.buildings.has_house(2), # @formatter:on }) @@ -53,7 +53,7 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): @cache_self1 def has_building(self, building: str) -> StardewRule: - carpenter_rule = self.received(Event.can_construct_buildings) + carpenter_rule = self.logic.received(Event.can_construct_buildings) if not self.options.building_progression & BuildingProgression.option_progressive: return Has(building, self.registry.building_rules) & carpenter_rule @@ -66,7 +66,7 @@ def has_building(self, building: str) -> StardewRule: elif building.startswith("Deluxe"): count = 3 building = " ".join(["Progressive", *building.split(" ")[1:]]) - return self.received(f"{building}", count) & carpenter_rule + return self.logic.received(f"{building}", count) & carpenter_rule @cache_self1 def has_house(self, upgrade_level: int) -> StardewRule: @@ -76,9 +76,9 @@ def has_house(self, upgrade_level: int) -> StardewRule: if upgrade_level > 3: return False_() - carpenter_rule = self.received(Event.can_construct_buildings) + carpenter_rule = self.logic.received(Event.can_construct_buildings) if self.options.building_progression & BuildingProgression.option_progressive: - return carpenter_rule & self.received(f"Progressive House", upgrade_level) + return carpenter_rule & self.logic.received(f"Progressive House", upgrade_level) if upgrade_level == 1: return carpenter_rule & Has(Building.kitchen, self.registry.building_rules) diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 7575c3a2a945..11599b433833 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -1,9 +1,11 @@ from functools import cached_property +from typing import Union from Utils import cache_self1 +from .base_logic import BaseLogicMixin, BaseLogic from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from ..mods.logic.magic_logic import MagicLogic +from ..mods.logic.magic_logic import MagicLogicMixin from ..stardew_rule import StardewRule, Or, False_ from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.performance_names import Performance @@ -11,51 +13,45 @@ valid_weapons = (APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger) -class CombatLogic: - received: ReceivedLogicMixin - region: RegionLogicMixin - magic: MagicLogic +class CombatLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.combat = CombatLogic(*args, **kwargs) - def __init__(self, player: int, received: ReceivedLogicMixin, region: RegionLogicMixin): - self.player = player - self.region = region - self.received = received - - def set_magic(self, magic: MagicLogic): - self.magic = magic +class CombatLogic(BaseLogic[Union[CombatLogicMixin, RegionLogicMixin, ReceivedLogicMixin, MagicLogicMixin]]): @cache_self1 def can_fight_at_level(self, level: str) -> StardewRule: if level == Performance.basic: - return self.has_any_weapon | self.magic.has_any_spell() + return self.logic.combat.has_any_weapon | self.logic.magic.has_any_spell() if level == Performance.decent: - return self.has_decent_weapon | self.magic.has_decent_spells() + return self.logic.combat.has_decent_weapon | self.logic.magic.has_decent_spells() if level == Performance.good: - return self.has_good_weapon | self.magic.has_good_spells() + return self.logic.combat.has_good_weapon | self.logic.magic.has_good_spells() if level == Performance.great: - return self.has_great_weapon | self.magic.has_great_spells() + return self.logic.combat.has_great_weapon | self.logic.magic.has_great_spells() if level == Performance.galaxy: - return self.has_galaxy_weapon | self.magic.has_amazing_spells() + return self.logic.combat.has_galaxy_weapon | self.logic.magic.has_amazing_spells() if level == Performance.maximum: - return self.has_galaxy_weapon | self.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP + return self.logic.combat.has_galaxy_weapon | self.logic.magic.has_amazing_spells() # Someday we will have the ascended weapons in AP return False_() @cached_property def has_any_weapon(self) -> StardewRule: - return self.received(valid_weapons, 1) + return self.logic.received(valid_weapons, 1) @cached_property def has_decent_weapon(self) -> StardewRule: - return Or(*(self.received(weapon, 2) for weapon in valid_weapons)) + return Or(*(self.logic.received(weapon, 2) for weapon in valid_weapons)) @cached_property def has_good_weapon(self) -> StardewRule: - return Or(*(self.received(weapon, 3) for weapon in valid_weapons)) + return Or(*(self.logic.received(weapon, 3) for weapon in valid_weapons)) @cached_property def has_great_weapon(self) -> StardewRule: - return Or(*(self.received(weapon, 4) for weapon in valid_weapons)) + return Or(*(self.logic.received(weapon, 4) for weapon in valid_weapons)) @cached_property def has_galaxy_weapon(self) -> StardewRule: - return Or(*(self.received(weapon, 5) for weapon in valid_weapons)) + return Or(*(self.logic.received(weapon, 5) for weapon in valid_weapons)) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index dc350dea12bb..339cb88a2dda 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -10,7 +10,7 @@ from .base_logic import LogicRegistry from .building_logic import BuildingLogicMixin from .bundle_logic import BundleLogic -from .combat_logic import CombatLogic +from .combat_logic import CombatLogicMixin from .cooking_logic import CookingLogic from .crafting_logic import CraftingLogic from .crop_logic import CropLogic @@ -20,7 +20,7 @@ from .has_logic import HasLogicMixin from .mine_logic import MineLogic from .money_logic import MoneyLogicMixin -from .monster_logic import MonsterLogic +from .monster_logic import MonsterLogicMixin from .museum_logic import MuseumLogicMixin from .pet_logic import PetLogic from .quest_logic import QuestLogic @@ -42,6 +42,7 @@ from ..data.monster_data import all_monsters_by_category, all_monsters_by_name from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes +from ..mods.logic.magic_logic import MagicLogicMixin from ..mods.logic.mod_logic import ModLogic from ..mods.mod_data import ModNames from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity, StardewValleyOptions @@ -87,7 +88,8 @@ @dataclass(frozen=False, repr=False) class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, - ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin): + ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, + MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin): player: int options: StardewValleyOptions @@ -116,13 +118,6 @@ def __init__(self, player: int, options: StardewValleyOptions): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.buildings = BuildingLogicMixin(self.player, self.registry, self.options, self).buildings - self.shipping = ShippingLogicMixin(self.player, self.registry, self.options, self).shipping - self.relationship = RelationshipLogicMixin(self.player, self.registry, self.options, self).relationship - self.museum = MuseumLogicMixin(self.player, self.registry, self.options, self).museum - self.wallet = WalletLogicMixin(self.player, self.registry, self.options, self).wallet - self.combat = CombatLogic(self.player, self.received, self.region) - self.monster = MonsterLogic(self.player, self.region, self.time, self.combat) self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) self.crop = CropLogic(self.player, self.options.cropsanity, exclude_ginger_island, self.received, self.has, self.region, @@ -147,13 +142,8 @@ def __init__(self, player: int, options: StardewValleyOptions): self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, self.registry, self.options, self, - skill_option, elevator_option, mods_option, self.received, self.has, self.region, - self.action, - self.artisan, - self.season, self.money, self.relationship, self.museum, self.buildings, self.wallet, self.combat, self.tool, self.skill, - self.fishing, - self.cooking, self.mine, self.ability, self.time, self.quest, self.crafting, self.crop) + self.mod = ModLogic(self.player, self.registry, self.options, self, skill_option, elevator_option, mods_option, self.tool, self.skill, + self.fishing, self.cooking, self.mine, self.ability, self.quest, self.crafting, self.crop) self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index f32a9999354e..a00a855854a1 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,45 +1,41 @@ from typing import Iterable, Union, Hashable from Utils import cache_self1 -from .combat_logic import CombatLogic +from .base_logic import BaseLogicMixin, BaseLogic +from .combat_logic import CombatLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin, MAX_MONTHS from ..data.monster_data import StardewMonster, all_monsters_by_name from ..stardew_rule import StardewRule, Or, And -class MonsterLogic: - region: RegionLogicMixin - time: TimeLogicMixin - combat: CombatLogic +class MonsterLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.monster = MonsterLogic(*args, **kwargs) - def __init__(self, player: int, region: RegionLogicMixin, time: TimeLogicMixin, combat: CombatLogic): - self.player = player - self.region = region - self.time = time - self.combat = combat - # Should be cached +class MonsterLogic(BaseLogic[Union[MonsterLogicMixin, RegionLogicMixin, CombatLogicMixin, TimeLogicMixin]]): def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): monster = all_monsters_by_name[monster] - region_rule = self.region.can_reach_any(monster.locations) - combat_rule = self.combat.can_fight_at_level(monster.difficulty) + region_rule = self.logic.region.can_reach_any(monster.locations) + combat_rule = self.logic.combat.can_fight_at_level(monster.difficulty) if amount_tier <= 0: amount_tier = 0 - time_rule = self.time.has_lived_months(amount_tier * 2) + time_rule = self.logic.time.has_lived_months(amount_tier * 2) return region_rule & combat_rule & time_rule @cache_self1 def can_kill_max(self, monster: StardewMonster) -> StardewRule: - return self.can_kill(monster, MAX_MONTHS) + return self.logic.monster.can_kill(monster, MAX_MONTHS) # Should be cached def can_kill_any(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: - rules = [self.can_kill(monster, amount_tier) for monster in monsters] + rules = [self.logic.monster.can_kill(monster, amount_tier) for monster in monsters] return Or(*rules) # Should be cached def can_kill_all(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: - rules = [self.can_kill(monster, amount_tier) for monster in monsters] + rules = [self.logic.monster.can_kill(monster, amount_tier) for monster in monsters] return And(*rules) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 924e2ee5cf35..1d58c632b942 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -1,8 +1,8 @@ -from typing import List +from typing import Union from Utils import cache_self1 from .action_logic import ActionLogicMixin -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin @@ -12,66 +12,61 @@ from ..strings.region_names import Region -class MuseumLogicMixin(BaseLogic): +class MuseumLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.museum = MuseumLogic(*args, **kwargs) -class MuseumLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, ActionLogicMixin): +class MuseumLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, ActionLogicMixin, MuseumLogicMixin]]): def can_donate_museum_items(self, number: int) -> StardewRule: - return self.region.can_reach(Region.museum) & self.can_find_museum_items(number) + return self.logic.region.can_reach(Region.museum) & self.logic.museum.can_find_museum_items(number) def can_donate_museum_artifacts(self, number: int) -> StardewRule: - return self.region.can_reach(Region.museum) & self.can_find_museum_artifacts(number) + return self.logic.region.can_reach(Region.museum) & self.logic.museum.can_find_museum_artifacts(number) @cache_self1 def can_find_museum_item(self, item: MuseumItem) -> StardewRule: - region_rule = self.region.can_reach_all_except_one(item.locations) - geodes_rule = And(*(self.action.can_open_geode(geode) for geode in item.geodes)) + region_rule = self.logic.region.can_reach_all_except_one(item.locations) + geodes_rule = And(*(self.logic.action.can_open_geode(geode) for geode in item.geodes)) # monster_rule = self.can_farm_monster(item.monsters) # extra_rule = True_() pan_rule = False_() if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": - pan_rule = self.action.can_pan() + pan_rule = self.logic.action.can_pan() return pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule def can_find_museum_artifacts(self, number: int) -> StardewRule: rules = [] for artifact in all_museum_artifacts: - rules.append(self.can_find_museum_item(artifact)) + rules.append(self.logic.museum.can_find_museum_item(artifact)) return Count(number, rules) def can_find_museum_minerals(self, number: int) -> StardewRule: rules = [] for mineral in all_museum_minerals: - rules.append(self.can_find_museum_item(mineral)) + rules.append(self.logic.museum.can_find_museum_item(mineral)) return Count(number, rules) def can_find_museum_items(self, number: int) -> StardewRule: rules = [] for donation in all_museum_items: - rules.append(self.can_find_museum_item(donation)) + rules.append(self.logic.museum.can_find_museum_item(donation)) return Count(number, rules) def can_complete_museum(self) -> StardewRule: - rules = [self.region.can_reach(Region.museum)] + rules = [self.logic.region.can_reach(Region.museum)] if self.options.museumsanity != options.Museumsanity.option_none: - rules.append(self.received("Traveling Merchant Metal Detector", 4)) + rules.append(self.logic.received("Traveling Merchant Metal Detector", 4)) for donation in all_museum_items: - rules.append(self.can_find_museum_item(donation)) - return And(*rules) & self.region.can_reach(Region.museum) + rules.append(self.logic.museum.can_find_museum_item(donation)) + return And(*rules) & self.logic.region.can_reach(Region.museum) def can_donate(self, item: str) -> StardewRule: - return self.has(item) & self.region.can_reach(Region.museum) - - def can_donate_many(self, items: List[str], amount: int = -1) -> StardewRule: - if amount <= -1: - amount = len(items) - return self.has(items, amount) & self.region.can_reach(Region.museum) + return self.logic.has(item) & self.logic.region.can_reach(Region.museum) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index bc3896fe390c..d0fa651d0cd4 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -2,7 +2,7 @@ from typing import Union from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .building_logic import BuildingLogicMixin from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin @@ -21,35 +21,36 @@ possible_kids = ("Cute Baby", "Ugly Baby") -class RelationshipLogicMixin(BaseLogic): +class RelationshipLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.relationship = RelationshipLogic(*args, **kwargs) -class RelationshipLogic(BuildingLogicMixin, SeasonLogicMixin, TimeLogicMixin, GiftLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin): +class RelationshipLogic(BaseLogic[Union[ + RelationshipLogicMixin, BuildingLogicMixin, SeasonLogicMixin, TimeLogicMixin, GiftLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): def can_date(self, npc: str) -> StardewRule: - return self.has_hearts(npc, 8) & self.has(Gift.bouquet) + return self.logic.relationship.has_hearts(npc, 8) & self.logic.has(Gift.bouquet) def can_marry(self, npc: str) -> StardewRule: - return self.has_hearts(npc, 10) & self.has(Gift.mermaid_pendant) + return self.logic.relationship.has_hearts(npc, 10) & self.logic.has(Gift.mermaid_pendant) def can_get_married(self) -> StardewRule: - return self.has_hearts(Generic.bachelor, 10) & self.has(Gift.mermaid_pendant) + return self.logic.relationship.has_hearts(Generic.bachelor, 10) & self.logic.has(Gift.mermaid_pendant) def has_children(self, number_children: int) -> StardewRule: if number_children <= 0: return True_() if self.options.friendsanity == Friendsanity.option_none: - return self.can_reproduce(number_children) - return self.received(possible_kids, number_children) & self.buildings.has_house(2) + return self.logic.relationship.can_reproduce(number_children) + return self.logic.received(possible_kids, number_children) & self.logic.buildings.has_house(2) def can_reproduce(self, number_children: int = 1) -> StardewRule: if number_children <= 0: return True_() - baby_rules = [self.can_get_married(), self.buildings.has_house(2), self.has_hearts(Generic.bachelor, 12), - self.has_children(number_children - 1)] + baby_rules = [self.logic.relationship.can_get_married(), self.logic.buildings.has_house(2), self.logic.relationship.has_hearts(Generic.bachelor, 12), + self.logic.relationship.has_children(number_children - 1)] return And(*baby_rules) # Should be cached @@ -57,29 +58,29 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() if self.options.friendsanity == Friendsanity.option_none: - return self.can_earn_relationship(npc, hearts) + return self.logic.relationship.can_earn_relationship(npc, hearts) if npc not in all_villagers_by_name: if npc == Generic.any or npc == Generic.bachelor: possible_friends = [] for name in all_villagers_by_name: - if not self.npc_is_in_current_slot(name): + if not self.logic.relationship.npc_is_in_current_slot(name): continue if npc == Generic.any or all_villagers_by_name[name].bachelor: - possible_friends.append(self.has_hearts(name, hearts)) + possible_friends.append(self.logic.relationship.has_hearts(name, hearts)) return Or(*possible_friends) if npc == Generic.all: mandatory_friends = [] for name in all_villagers_by_name: - if not self.npc_is_in_current_slot(name): + if not self.logic.relationship.npc_is_in_current_slot(name): continue - mandatory_friends.append(self.has_hearts(name, hearts)) + mandatory_friends.append(self.logic.relationship.has_hearts(name, hearts)) return And(*mandatory_friends) if npc.isnumeric(): possible_friends = [] for name in all_villagers_by_name: - if not self.npc_is_in_current_slot(name): + if not self.logic.relationship.npc_is_in_current_slot(name): continue - possible_friends.append(self.has_hearts(name, hearts)) + possible_friends.append(self.logic.relationship.has_hearts(name, hearts)) return Count(int(npc), possible_friends) return self.can_earn_relationship(npc, hearts) @@ -87,41 +88,41 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: return True_() villager = all_villagers_by_name[npc] if self.options.friendsanity == Friendsanity.option_bachelors and not villager.bachelor: - return self.can_earn_relationship(npc, hearts) + return self.logic.relationship.can_earn_relationship(npc, hearts) if self.options.friendsanity == Friendsanity.option_starting_npcs and not villager.available: - return self.can_earn_relationship(npc, hearts) + return self.logic.relationship.can_earn_relationship(npc, hearts) is_capped_at_8 = villager.bachelor and self.options.friendsanity != Friendsanity.option_all_with_marriage if is_capped_at_8 and hearts > 8: - return self.received_hearts(villager.name, 8) & self.can_earn_relationship(npc, hearts) - return self.received_hearts(villager.name, hearts) + return self.logic.relationship.received_hearts(villager.name, 8) & self.logic.relationship.can_earn_relationship(npc, hearts) + return self.logic.relationship.received_hearts(villager.name, hearts) # Should be cached def received_hearts(self, npc: str, hearts: int) -> StardewRule: - return self.received(self.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) + return self.logic.received(self.logic.relationship.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) @cache_self1 def can_meet(self, npc: str) -> StardewRule: - if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): + if npc not in all_villagers_by_name or not self.logic.relationship.npc_is_in_current_slot(npc): return True_() villager = all_villagers_by_name[npc] - rules = [self.region.can_reach_any(villager.locations)] + rules = [self.logic.region.can_reach_any(villager.locations)] if npc == NPC.kent: - rules.append(self.time.has_year_two) + rules.append(self.logic.time.has_year_two) elif npc == NPC.leo: - rules.append(self.received("Island West Turtle")) + rules.append(self.logic.received("Island West Turtle")) elif npc == ModNPC.lance: - rules.append(self.region.can_reach(Region.volcano_floor_10)) + rules.append(self.logic.region.can_reach(Region.volcano_floor_10)) return And(*rules) def can_give_loved_gifts_to_everyone(self) -> StardewRule: rules = [] for npc in all_villagers_by_name: - if not self.npc_is_in_current_slot(npc): + if not self.logic.relationship.npc_is_in_current_slot(npc): continue - meet_rule = self.can_meet(npc) + meet_rule = self.logic.relationship.can_meet(npc) rules.append(meet_rule) - rules.append(self.gifts.has_any_universal_love) + rules.append(self.logic.gifts.has_any_universal_love) return And(*rules) # Should be cached @@ -130,20 +131,20 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: return True_() previous_heart = hearts - self.options.friendsanity_heart_size - previous_heart_rule = self.has_hearts(npc, previous_heart) + previous_heart_rule = self.logic.relationship.has_hearts(npc, previous_heart) - if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): + if npc not in all_villagers_by_name or not self.logic.relationship.npc_is_in_current_slot(npc): return previous_heart_rule - rules = [previous_heart_rule, self.can_meet(npc)] + rules = [previous_heart_rule, self.logic.relationship.can_meet(npc)] villager = all_villagers_by_name[npc] if hearts > 2 or hearts > self.options.friendsanity_heart_size: - rules.append(self.season.has(villager.birthday)) + rules.append(self.logic.season.has(villager.birthday)) if villager.bachelor: if hearts > 8: - rules.append(self.can_date(npc)) + rules.append(self.logic.relationship.can_date(npc)) if hearts > 10: - rules.append(self.can_marry(npc)) + rules.append(self.logic.relationship.can_marry(npc)) return And(*rules) @@ -156,4 +157,4 @@ def npc_is_in_current_slot(self, name: str) -> bool: def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): return f"{npc} <3" - return self.heart(npc.name) + return self.logic.relationship.heart(npc.name) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index d84d514c0663..d293738c4504 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,7 +1,8 @@ from functools import cached_property +from typing import Union from Utils import cache_self1 -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .building_logic import BuildingLogicMixin from .has_logic import HasLogicMixin from .region_logic import RegionLogicMixin @@ -13,25 +14,25 @@ from ..strings.region_names import Region -class ShippingLogicMixin(BaseLogic): +class ShippingLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.shipping = ShippingLogic(*args, **kwargs) -class ShippingLogic(BuildingLogicMixin, RegionLogicMixin, HasLogicMixin): +class ShippingLogic(BaseLogic[Union[ShippingLogicMixin, BuildingLogicMixin, RegionLogicMixin, HasLogicMixin]]): @cached_property def can_use_shipping_bin(self) -> StardewRule: - return self.buildings.has_building(Building.shipping_bin) + return self.logic.buildings.has_building(Building.shipping_bin) @cache_self1 def can_ship(self, item: str) -> StardewRule: - return self.can_ship_items & self.has(item) + return self.logic.shipping.can_ship_items & self.logic.has(item) @cached_property def can_ship_items(self) -> StardewRule: - return self.region.can_reach(Region.shipping) + return self.logic.region.can_reach(Region.shipping) def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " @@ -47,4 +48,4 @@ def can_ship_everything(self) -> StardewRule: if location.mod_name and location.mod_name not in mod_list: continue all_items_to_ship.append(location.name[len(shipsanity_prefix):]) - return self.buildings.has_building(Building.shipping_bin) & And(*(self.has(item) for item in all_items_to_ship)) + return self.logic.buildings.has_building(Building.shipping_bin) & And(*(self.logic.has(item) for item in all_items_to_ship)) diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index 3ed36d1a3c6e..34a1343f65f5 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,22 +1,22 @@ from functools import cached_property -from .base_logic import BaseLogic +from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule from ..strings.wallet_item_names import Wallet -class WalletLogicMixin(BaseLogic): +class WalletLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.wallet = WalletLogic(*args, **kwargs) -class WalletLogic(ReceivedLogicMixin): +class WalletLogic(BaseLogic[ReceivedLogicMixin]): @cached_property def can_speak_dwarf(self) -> StardewRule: - return self.received(Wallet.dwarvish_translation_guide) + return self.logic.received(Wallet.dwarvish_translation_guide) @cached_property def has_rusty_key(self) -> StardewRule: - return self.received(Wallet.rusty_key) + return self.logic.received(Wallet.rusty_key) diff --git a/worlds/stardew_valley/mods/logic/magic_logic.py b/worlds/stardew_valley/mods/logic/magic_logic.py index 3e7e08c239e7..164780f63194 100644 --- a/worlds/stardew_valley/mods/logic/magic_logic.py +++ b/worlds/stardew_valley/mods/logic/magic_logic.py @@ -1,83 +1,81 @@ +from typing import Union + +from ...logic.base_logic import BaseLogicMixin, BaseLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...mods.mod_data import ModNames -from ...options import Mods from ...stardew_rule import Count, StardewRule, False_ from ...strings.ap_names.skill_level_names import ModSkillLevel from ...strings.region_names import MagicRegion from ...strings.spells import MagicSpell -class MagicLogic: - player: int - mods: Mods - received: ReceivedLogicMixin - region: RegionLogicMixin +class MagicLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.magic = MagicLogic(*args, **kwargs) - def __init__(self, player: int, mods: Mods, received: ReceivedLogicMixin, region: RegionLogicMixin): - self.player = player - self.mods = mods - self.received = received - self.region = region +# TODO add logic.mods.magic for altar +class MagicLogic(BaseLogic[Union[RegionLogicMixin, ReceivedLogicMixin]]): def can_use_clear_debris_instead_of_tool_level(self, level: int) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - return self.received(MagicSpell.clear_debris) & self.can_use_altar() & self.received(ModSkillLevel.magic_level, level) + return self.logic.received(MagicSpell.clear_debris) & self.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, level) def can_use_altar(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - return self.region.can_reach(MagicRegion.altar) + return self.logic.region.can_reach(MagicRegion.altar) def has_any_spell(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() return self.can_use_altar() def has_attack_spell_count(self, count: int) -> StardewRule: - attack_spell_rule = [self.received(MagicSpell.fireball), self.received(MagicSpell.frostbite), self.received(MagicSpell.shockwave), - self.received(MagicSpell.spirit), self.received(MagicSpell.meteor)] + attack_spell_rule = [self.logic.received(MagicSpell.fireball), self.logic.received(MagicSpell.frostbite), self.logic.received(MagicSpell.shockwave), + self.logic.received(MagicSpell.spirit), self.logic.received(MagicSpell.meteor)] return Count(count, attack_spell_rule) def has_support_spell_count(self, count: int) -> StardewRule: - support_spell_rule = [self.can_use_altar(), self.received(ModSkillLevel.magic_level, 2), - self.received(MagicSpell.descend), self.received(MagicSpell.heal), - self.received(MagicSpell.tendrils)] + support_spell_rule = [self.can_use_altar(), self.logic.received(ModSkillLevel.magic_level, 2), + self.logic.received(MagicSpell.descend), self.logic.received(MagicSpell.heal), + self.logic.received(MagicSpell.tendrils)] return Count(count, support_spell_rule) def has_decent_spells(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 2) + magic_resource_rule = self.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, 2) magic_attack_options_rule = self.has_attack_spell_count(1) return magic_resource_rule & magic_attack_options_rule def has_good_spells(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 4) + magic_resource_rule = self.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, 4) magic_attack_options_rule = self.has_attack_spell_count(2) magic_support_options_rule = self.has_support_spell_count(1) return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule def has_great_spells(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 6) + magic_resource_rule = self.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, 6) magic_attack_options_rule = self.has_attack_spell_count(3) magic_support_options_rule = self.has_support_spell_count(1) return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule def has_amazing_spells(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - magic_resource_rule = self.can_use_altar() & self.received(ModSkillLevel.magic_level, 8) + magic_resource_rule = self.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, 8) magic_attack_options_rule = self.has_attack_spell_count(4) magic_support_options_rule = self.has_support_spell_count(2) return magic_resource_rule & magic_attack_options_rule & magic_support_options_rule def can_blink(self) -> StardewRule: - if ModNames.magic not in self.mods: + if ModNames.magic not in self.options.mods: return False_() - return self.received(MagicSpell.blink) & self.can_use_altar() + return self.logic.received(MagicSpell.blink) & self.can_use_altar() diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 59c475f82e8c..b005b4f73ea6 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -1,8 +1,10 @@ +from typing import Union + from .buildings_logic import ModBuildingLogic from .deepwoods_logic import DeepWoodsLogic from .elevator_logic import ModElevatorLogic from .item_logic import ModItemLogic -from .magic_logic import MagicLogic +from .magic_logic import MagicLogic, MagicLogicMixin from .quests_logic import ModQuestLogic from .skills_logic import ModSkillLogic from .special_orders_logic import ModSpecialOrderLogic @@ -10,9 +12,9 @@ from ...logic.ability_logic import AbilityLogic from ...logic.action_logic import ActionLogicMixin from ...logic.artisan_logic import ArtisanLogicMixin -from ...logic.base_logic import LogicRegistry, BaseLogic +from ...logic.base_logic import LogicRegistry, BaseLogic, BaseLogicMixin from ...logic.building_logic import BuildingLogicMixin -from ...logic.combat_logic import CombatLogic +from ...logic.combat_logic import CombatLogicMixin from ...logic.cooking_logic import CookingLogic from ...logic.crafting_logic import CraftingLogic from ...logic.crop_logic import CropLogic @@ -20,7 +22,7 @@ from ...logic.has_logic import HasLogicMixin from ...logic.mine_logic import MineLogic from ...logic.money_logic import MoneyLogicMixin -from ...logic.museum_logic import MuseumLogic +from ...logic.museum_logic import MuseumLogicMixin from ...logic.quest_logic import QuestLogic from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin @@ -33,7 +35,14 @@ from ...options import SkillProgression, ElevatorProgression, Mods -class ModLogic(BaseLogic): +class ModLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.mod = ModLogic(*args, **kwargs) + + +class ModLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, ActionLogicMixin, ArtisanLogicMixin, SeasonLogicMixin, +MoneyLogicMixin, MuseumLogicMixin, RelationshipLogicMixin, BuildingLogicMixin, WalletLogicMixin, CombatLogicMixin]], MagicLogicMixin): items: ModItemLogic quests: ModQuestLogic region: RegionLogicMixin @@ -46,25 +55,20 @@ class ModLogic(BaseLogic): sve: SVELogic def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, - received: ReceivedLogicMixin, - has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogicMixin, artisan: ArtisanLogicMixin, season: SeasonLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogicMixin, - museum: MuseumLogic, building: BuildingLogicMixin, - wallet: WalletLogicMixin, - combat: CombatLogic, tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, - time: TimeLogicMixin, quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): + tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, + quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): super().__init__(player, registry, options, logic) - self.item = ModItemLogic(mods, combat, crop, cooking, has, money, region, season, relationship, museum, tool, crafting) - self.magic = MagicLogic(player, mods, received, region) - self.quests = ModQuestLogic(mods, received, has, region, time, season, relationship) + self.item = ModItemLogic(mods, logic.combat, crop, cooking, logic.has, logic.money, logic.region, logic.season, logic.relationship, logic.museum, tool, crafting) + self.quests = ModQuestLogic(mods, logic.received, logic.has, logic.region, logic.time, logic.season, logic.relationship) self.buildings = ModBuildingLogic(player, registry, options, logic) - self.special_orders = ModSpecialOrderLogic(player, action, artisan, crafting, crop, has, region, relationship, season, wallet, mods) - self.elevator = ModElevatorLogic(player, elevator_option, mods, received) - self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, received, has, combat, tool, skill, cooking) - self.skill = ModSkillLogic(player, skill_option, received, has, region, action, relationship, building, tool, fishing, cooking, self.magic, mods) - self.sve = SVELogic(player, skill_option, received, has, quest, region, action, relationship, building, tool, fishing, cooking, money, combat, season, - time) - combat.set_magic(self.magic) + self.special_orders = ModSpecialOrderLogic(player, logic.action, logic.artisan, crafting, crop, logic.has, logic.region, logic.relationship, + logic.season, logic.wallet, mods) + self.elevator = ModElevatorLogic(player, elevator_option, mods, logic.received) + self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, logic.received, logic.has, logic.combat, tool, skill, cooking) + self.skill = ModSkillLogic(player, skill_option, logic.received, logic.has, logic.region, logic.action, logic.relationship, logic.buildings, tool, + fishing, cooking, self.magic, mods) + self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.buildings, tool, + fishing, cooking, logic.money, logic.combat, logic.season, logic.time) tool.set_magic(self.magic) ability.set_magic(self.magic, self.skill) skill.set_mod_logic(self.magic, mods) From 9edbaa5c1b820de6979ad2dfe9e21c731d4c04dc Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 20 Nov 2023 23:34:33 -0500 Subject: [PATCH 193/482] skill and farming mixin --- worlds/stardew_valley/logic/crop_logic.py | 72 ++++------ worlds/stardew_valley/logic/farming_logic.py | 38 +++--- worlds/stardew_valley/logic/logic.py | 25 ++-- worlds/stardew_valley/logic/mine_logic.py | 5 - worlds/stardew_valley/logic/pet_logic.py | 40 +++--- .../logic/relationship_logic.py | 16 +-- worlds/stardew_valley/logic/skill_logic.py | 123 +++++++----------- worlds/stardew_valley/logic/tool_logic.py | 56 +++----- .../mods/logic/elevator_logic.py | 22 ++-- worlds/stardew_valley/mods/logic/mod_logic.py | 51 ++------ 10 files changed, 172 insertions(+), 276 deletions(-) diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 5b81b38ce2d6..52d9d1b1d4cb 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -1,12 +1,13 @@ from typing import Union, Iterable from Utils import cache_self1 +from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic -from .tool_logic import ToolLogic +from .season_logic import SeasonLogicMixin +from .tool_logic import ToolLogicMixin from .traveling_merchant_logic import TravelingMerchantLogicMixin from ..data import CropItem, SeedItem from ..options import Cropsanity, ExcludeGingerIsland @@ -18,69 +19,50 @@ from ..strings.tool_names import Tool -class CropLogic: - player: int - cropsanity_option: Cropsanity - exclude_ginger_island_option: ExcludeGingerIsland - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - traveling_merchant: TravelingMerchantLogicMixin - season: SeasonLogic - money: MoneyLogicMixin - tool: ToolLogic +class CropLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.crop = CropLogic(*args, **kwargs) - def __init__(self, player: int, cropsanity_option: Cropsanity, exclude_ginger_island_option: ExcludeGingerIsland, received: ReceivedLogicMixin, - has: HasLogicMixin, - region: RegionLogicMixin, traveling_merchant: TravelingMerchantLogicMixin, season: SeasonLogic, money: MoneyLogicMixin, tool: ToolLogic): - self.player = player - self.cropsanity_option = cropsanity_option - self.exclude_ginger_island_option = exclude_ginger_island_option - self.received = received - self.has = has - self.region = region - self.traveling_merchant = traveling_merchant - self.season = season - self.money = money - self.tool = tool +class CropLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, SeasonLogicMixin, MoneyLogicMixin, +ToolLogicMixin, CropLogicMixin]]): @cache_self1 def can_grow(self, crop: CropItem) -> StardewRule: - season_rule = self.season.has_any(crop.farm_growth_seasons) - seed_rule = self.has(crop.seed.name) - farm_rule = self.region.can_reach(Region.farm) & season_rule - tool_rule = self.tool.has_tool(Tool.hoe) & self.tool.has_tool(Tool.watering_can) - region_rule = farm_rule | self.region.can_reach(Region.greenhouse) | self.has_island_farm() + season_rule = self.logic.season.has_any(crop.farm_growth_seasons) + seed_rule = self.logic.has(crop.seed.name) + farm_rule = self.logic.region.can_reach(Region.farm) & season_rule + tool_rule = self.logic.tool.has_tool(Tool.hoe) & self.logic.tool.has_tool(Tool.watering_can) + region_rule = farm_rule | self.logic.region.can_reach(Region.greenhouse) | self.logic.crop.has_island_farm() return seed_rule & region_rule & tool_rule def can_plant_and_grow_item(self, seasons: Union[str, Iterable[str]]) -> StardewRule: if isinstance(seasons, str): seasons = [seasons] - season_rule = self.season.has_any(seasons) | self.region.can_reach(Region.greenhouse) | self.has_island_farm() - farm_rule = self.region.can_reach(Region.farm) | self.region.can_reach( - Region.greenhouse) | self.has_island_farm() + season_rule = self.logic.season.has_any(seasons) | self.logic.region.can_reach(Region.greenhouse) | self.logic.crop.has_island_farm() + farm_rule = self.logic.region.can_reach(Region.farm) | self.logic.region.can_reach(Region.greenhouse) | self.logic.crop.has_island_farm() return season_rule & farm_rule def has_island_farm(self) -> StardewRule: - if self.exclude_ginger_island_option == ExcludeGingerIsland.option_false: - return self.region.can_reach(Region.island_west) + if self.options.exclude_ginger_island == ExcludeGingerIsland.option_false: + return self.logic.region.can_reach(Region.island_west) return False_() @cache_self1 def can_buy_seed(self, seed: SeedItem) -> StardewRule: - if seed.requires_island and self.exclude_ginger_island_option == ExcludeGingerIsland.option_true: + if seed.requires_island and self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: return False_() - if self.cropsanity_option == Cropsanity.option_disabled or seed.name == Seed.qi_bean: + if self.options.cropsanity == Cropsanity.option_disabled or seed.name == Seed.qi_bean: item_rule = True_() else: - item_rule = self.received(seed.name) + item_rule = self.logic.received(seed.name) if seed.name == Seed.coffee: - item_rule = item_rule & self.traveling_merchant.has_days(3) - season_rule = self.season.has_any(seed.seasons) - region_rule = self.region.can_reach_all(seed.regions) - currency_rule = self.money.can_spend(1000) + item_rule = item_rule & self.logic.traveling_merchant.has_days(3) + season_rule = self.logic.season.has_any(seed.seasons) + region_rule = self.logic.region.can_reach_all(seed.regions) + currency_rule = self.logic.money.can_spend(1000) if seed.name == Seed.pineapple: - currency_rule = self.has(Forageable.magma_cap) + currency_rule = self.logic.has(Forageable.magma_cap) if seed.name == Seed.taro: - currency_rule = self.has(Fossil.bone_fragment) + currency_rule = self.logic.has(Fossil.bone_fragment) return season_rule & region_rule & item_rule & currency_rule diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index cf20021d50af..6a09b3ee1091 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -1,39 +1,39 @@ +from typing import Union + +from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin -from .skill_logic import SkillLogic +from .skill_logic import SkillLogicMixin from ..stardew_rule import StardewRule, True_ from ..strings.fertilizer_names import Fertilizer -class FarmingLogic: - player: int - has: HasLogicMixin - skill: SkillLogic +class FarmingLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.farming = FarmingLogic(*args, **kwargs) - def __init__(self, player: int, has: HasLogicMixin, skill: SkillLogic): - self.player = player - self.has = has - self.skill = skill +class FarmingLogic(BaseLogic[Union[HasLogicMixin, SkillLogicMixin, FarmingLogicMixin]]): def has_fertilizer(self, tier: int) -> StardewRule: if tier <= 0: return True_() if tier == 1: - return self.has(Fertilizer.basic) + return self.logic.has(Fertilizer.basic) if tier == 2: - return self.has(Fertilizer.quality) + return self.logic.has(Fertilizer.quality) if tier >= 3: - return self.has(Fertilizer.deluxe) + return self.logic.has(Fertilizer.deluxe) def can_grow_crop_quality(self, quality: int) -> StardewRule: if quality <= 0: return True_() if quality == 1: - return self.skill.has_farming_level(5) | (self.has_fertilizer(1) & self.skill.has_farming_level(2)) | ( - self.has_fertilizer(2) & self.skill.has_farming_level(1)) | self.has_fertilizer(3) + return self.logic.skill.has_farming_level(5) | (self.logic.farming.has_fertilizer(1) & self.logic.skill.has_farming_level(2)) | ( + self.logic.farming.has_fertilizer(2) & self.logic.skill.has_farming_level(1)) | self.logic.farming.has_fertilizer(3) if quality == 2: - return self.skill.has_farming_level(10) | ( - self.has_fertilizer(1) & self.skill.has_farming_level(5)) | ( - self.has_fertilizer(2) & self.skill.has_farming_level(3)) | ( - self.has_fertilizer(3) & self.skill.has_farming_level(2)) + return self.logic.skill.has_farming_level(10) | ( + self.logic.farming.has_fertilizer(1) & self.logic.skill.has_farming_level(5)) | ( + self.logic.farming.has_fertilizer(2) & self.logic.skill.has_farming_level(3)) | ( + self.logic.farming.has_fertilizer(3) & self.logic.skill.has_farming_level(2)) if quality >= 3: - return self.has_fertilizer(3) & self.skill.has_farming_level(4) + return self.logic.farming.has_fertilizer(3) & self.logic.skill.has_farming_level(4) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 339cb88a2dda..ace67d606eb0 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -13,8 +13,8 @@ from .combat_logic import CombatLogicMixin from .cooking_logic import CookingLogic from .crafting_logic import CraftingLogic -from .crop_logic import CropLogic -from .farming_logic import FarmingLogic +from .crop_logic import CropLogicMixin +from .farming_logic import FarmingLogicMixin from .fishing_logic import FishingLogic from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin @@ -22,17 +22,17 @@ from .money_logic import MoneyLogicMixin from .monster_logic import MonsterLogicMixin from .museum_logic import MuseumLogicMixin -from .pet_logic import PetLogic +from .pet_logic import PetLogicMixin from .quest_logic import QuestLogic from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogicMixin -from .skill_logic import SkillLogic +from .skill_logic import SkillLogicMixin from .special_order_logic import SpecialOrderLogic from .time_logic import TimeLogicMixin -from .tool_logic import ToolLogic +from .tool_logic import ToolLogicMixin from .traveling_merchant_logic import TravelingMerchantLogicMixin from .wallet_logic import WalletLogicMixin from ..data import all_fish, all_purchasable_seeds, all_crops @@ -89,7 +89,8 @@ @dataclass(frozen=False, repr=False) class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, - MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin): + MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, + SkillLogicMixin, FarmingLogicMixin): player: int options: StardewValleyOptions @@ -118,14 +119,6 @@ def __init__(self, player: int, options: StardewValleyOptions): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.tool = ToolLogic(self.player, tool_option, self.received, self.has, self.region, self.season, self.money) - self.pet = PetLogic(self.player, friendsanity_option, heart_size_option, self.received, self.region, self.time, self.tool) - self.crop = CropLogic(self.player, self.options.cropsanity, exclude_ginger_island, self.received, self.has, self.region, - self.traveling_merchant, - self.season, self.money, self.tool) - self.skill = SkillLogic(self.player, skill_option, self.received, self.has, self.region, self.season, self.time, self.tool, - self.combat, self.crop) - self.farming = FarmingLogic(self.player, self.has, self.skill) self.bundle = BundleLogic(self.player, self.has, self.region, self.money, self.farming) self.fishing = FishingLogic(self.player, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, self.tool, self.skill) @@ -142,8 +135,8 @@ def __init__(self, player: int, options: StardewValleyOptions): self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, self.relationship, self.skill, self.special_order) - self.mod = ModLogic(self.player, self.registry, self.options, self, skill_option, elevator_option, mods_option, self.tool, self.skill, - self.fishing, self.cooking, self.mine, self.ability, self.quest, self.crafting, self.crop) + self.mod = ModLogic(self.player, self.registry, self.options, self, skill_option, elevator_option, mods_option, self.skill, + self.fishing, self.cooking, self.mine, self.ability, self.quest, self.crafting) self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 3b1b6b9e30e2..315931280d55 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -5,7 +5,6 @@ from .skill_logic import SkillLogic from .tool_logic import ToolLogic from .. import options -from ..mods.logic.elevator_logic import ModElevatorLogic from ..options import ToolProgression, SkillProgression, ElevatorProgression from ..stardew_rule import StardewRule, And, True_ from ..strings.performance_names import Performance @@ -23,7 +22,6 @@ class MineLogic: combat: CombatLogic tool: ToolLogic skill: SkillLogic - mod_elevator: ModElevatorLogic def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogicMixin, @@ -38,9 +36,6 @@ def __init__(self, player: int, tool_option: ToolProgression, skill_option: Skil self.tool = tool self.skill = skill - def set_modded_elevator(self, mod_elevator: ModElevatorLogic): - self.mod_elevator = mod_elevator - # Regions def can_mine_in_the_mines_floor_1_40(self) -> StardewRule: return self.region.can_reach(Region.mines_floor_5) diff --git a/worlds/stardew_valley/logic/pet_logic.py b/worlds/stardew_valley/logic/pet_logic.py index f6e1d75b2fa3..5d7d79a358ca 100644 --- a/worlds/stardew_valley/logic/pet_logic.py +++ b/worlds/stardew_valley/logic/pet_logic.py @@ -1,56 +1,46 @@ import math from typing import Union +from .base_logic import BaseLogicMixin, BaseLogic from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin -from .tool_logic import ToolLogic +from .tool_logic import ToolLogicMixin from ..data.villagers_data import Villager -from ..options import Friendsanity, FriendsanityHeartSize +from ..options import Friendsanity from ..stardew_rule import StardewRule, True_ from ..strings.region_names import Region from ..strings.villager_names import NPC -class PetLogic: - friendsanity_option: Friendsanity - heart_size_option: FriendsanityHeartSize - received: ReceivedLogicMixin - region: RegionLogicMixin - time: TimeLogicMixin - tool: ToolLogic - - def __init__(self, player: int, friendsanity_option: Friendsanity, heart_size_option: FriendsanityHeartSize, - received_logic: ReceivedLogicMixin, region: RegionLogicMixin, time: TimeLogicMixin, tool: ToolLogic): - self.player = player - self.friendsanity_option = friendsanity_option - self.heart_size_option = heart_size_option - self.received = received_logic - self.region = region - self.time = time - self.tool = tool +class PetLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.pet = PetLogic(*args, **kwargs) + +class PetLogic(BaseLogic[Union[RegionLogicMixin, ReceivedLogicMixin, TimeLogicMixin, ToolLogicMixin]]): def has_hearts(self, hearts: int = 1) -> StardewRule: if hearts <= 0: return True_() - if self.friendsanity_option == Friendsanity.option_none or self.friendsanity_option == Friendsanity.option_bachelors: + if self.options.friendsanity == Friendsanity.option_none or self.options.friendsanity == Friendsanity.option_bachelors: return self.can_befriend_pet(hearts) return self.received_hearts(NPC.pet, hearts) def received_hearts(self, npc: Union[str, Villager], hearts: int) -> StardewRule: if isinstance(npc, Villager): return self.received_hearts(npc.name, hearts) - return self.received(self.heart(npc), math.ceil(hearts / self.heart_size_option)) + return self.logic.received(self.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) - def can_befriend_pet(self, hearts: int): + def can_befriend_pet(self, hearts: int) -> StardewRule: if hearts <= 0: return True_() points = hearts * 200 points_per_month = 12 * 14 points_per_water_month = 18 * 14 - farm_rule = self.region.can_reach(Region.farm) - time_with_water_rule = self.tool.can_water(0) & self.time.has_lived_months(points // points_per_water_month) - time_without_water_rule = self.time.has_lived_months(points // points_per_month) + farm_rule = self.logic.region.can_reach(Region.farm) + time_with_water_rule = self.logic.tool.can_water(0) & self.logic.time.has_lived_months(points // points_per_water_month) + time_without_water_rule = self.logic.time.has_lived_months(points // points_per_month) time_rule = time_with_water_rule | time_without_water_rule return farm_rule & time_rule diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index d0fa651d0cd4..0021efc0feb3 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -63,7 +63,7 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if npc == Generic.any or npc == Generic.bachelor: possible_friends = [] for name in all_villagers_by_name: - if not self.logic.relationship.npc_is_in_current_slot(name): + if not self.npc_is_in_current_slot(name): continue if npc == Generic.any or all_villagers_by_name[name].bachelor: possible_friends.append(self.logic.relationship.has_hearts(name, hearts)) @@ -71,14 +71,14 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if npc == Generic.all: mandatory_friends = [] for name in all_villagers_by_name: - if not self.logic.relationship.npc_is_in_current_slot(name): + if not self.npc_is_in_current_slot(name): continue mandatory_friends.append(self.logic.relationship.has_hearts(name, hearts)) return And(*mandatory_friends) if npc.isnumeric(): possible_friends = [] for name in all_villagers_by_name: - if not self.logic.relationship.npc_is_in_current_slot(name): + if not self.npc_is_in_current_slot(name): continue possible_friends.append(self.logic.relationship.has_hearts(name, hearts)) return Count(int(npc), possible_friends) @@ -98,11 +98,11 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: # Should be cached def received_hearts(self, npc: str, hearts: int) -> StardewRule: - return self.logic.received(self.logic.relationship.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) + return self.logic.received(self.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) @cache_self1 def can_meet(self, npc: str) -> StardewRule: - if npc not in all_villagers_by_name or not self.logic.relationship.npc_is_in_current_slot(npc): + if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): return True_() villager = all_villagers_by_name[npc] rules = [self.logic.region.can_reach_any(villager.locations)] @@ -118,7 +118,7 @@ def can_meet(self, npc: str) -> StardewRule: def can_give_loved_gifts_to_everyone(self) -> StardewRule: rules = [] for npc in all_villagers_by_name: - if not self.logic.relationship.npc_is_in_current_slot(npc): + if not self.npc_is_in_current_slot(npc): continue meet_rule = self.logic.relationship.can_meet(npc) rules.append(meet_rule) @@ -133,7 +133,7 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: previous_heart = hearts - self.options.friendsanity_heart_size previous_heart_rule = self.logic.relationship.has_hearts(npc, previous_heart) - if npc not in all_villagers_by_name or not self.logic.relationship.npc_is_in_current_slot(npc): + if npc not in all_villagers_by_name or not self.npc_is_in_current_slot(npc): return previous_heart_rule rules = [previous_heart_rule, self.logic.relationship.can_meet(npc)] @@ -157,4 +157,4 @@ def npc_is_in_current_slot(self, name: str) -> bool: def heart(self, npc: Union[str, Villager]) -> str: if isinstance(npc, str): return f"{npc} <3" - return self.logic.relationship.heart(npc.name) + return self.heart(npc.name) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 8fadeca1e5ae..951f06bbed80 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -3,19 +3,19 @@ from Utils import cache_self1 from worlds.stardew_valley.strings.craftable_names import Fishing -from .combat_logic import CombatLogic -from .crop_logic import CropLogic +from .base_logic import BaseLogicMixin, BaseLogic +from .combat_logic import CombatLogicMixin +from .crop_logic import CropLogicMixin from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .season_logic import SeasonLogicMixin from .time_logic import TimeLogicMixin -from .tool_logic import ToolLogic +from .tool_logic import ToolLogicMixin from .. import options from ..data import all_crops -from ..mods.logic.magic_logic import MagicLogic +from ..mods.logic.magic_logic import MagicLogicMixin from ..mods.logic.mod_skills_levels import get_mod_skill_levels -from ..options import SkillProgression, Mods from ..stardew_rule import StardewRule, True_, Or from ..strings.machine_names import Machine from ..strings.performance_names import Performance @@ -26,37 +26,14 @@ fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west) -class SkillLogic: - skill_option: SkillProgression - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - season: SeasonLogicMixin - time: TimeLogicMixin - tool: ToolLogic - combat: CombatLogic - crop: CropLogic - magic: MagicLogic - mods: Mods - - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - season: SeasonLogicMixin, - time: TimeLogicMixin, tool: ToolLogic, combat: CombatLogic, crop: CropLogic): - self.player = player - self.skill_option = skill_option - self.received = received - self.has = has - self.region = region - self.season = season - self.time = time - self.tool = tool - self.combat = combat - self.crop = crop - - def set_mod_logic(self, magic: MagicLogic, mods: Mods): - self.magic = magic - self.mods = mods +class SkillLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.skill = SkillLogic(*args, **kwargs) + +class SkillLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, ToolLogicMixin, SkillLogicMixin, +CombatLogicMixin, CropLogicMixin, MagicLogicMixin]]): # Should be cached def can_earn_level(self, skill: str, level: int) -> StardewRule: if level <= 0: @@ -65,24 +42,24 @@ def can_earn_level(self, skill: str, level: int) -> StardewRule: tool_level = (level - 1) // 2 tool_material = ToolMaterial.tiers[tool_level] months = max(1, level - 1) - months_rule = self.time.has_lived_months(months) - previous_level_rule = self.has_level(skill, level - 1) + months_rule = self.logic.time.has_lived_months(months) + previous_level_rule = self.logic.skill.has_level(skill, level - 1) if skill == Skill.fishing: - xp_rule = self.tool.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) + xp_rule = self.logic.tool.has_tool(Tool.fishing_rod, ToolMaterial.tiers[max(tool_level, 3)]) elif skill == Skill.farming: - xp_rule = self.tool.has_tool(Tool.hoe, tool_material) & self.tool.can_water(tool_level) + xp_rule = self.logic.tool.has_tool(Tool.hoe, tool_material) & self.logic.tool.can_water(tool_level) elif skill == Skill.foraging: - xp_rule = self.tool.has_tool(Tool.axe, - tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level( + xp_rule = self.logic.tool.has_tool(Tool.axe, + tool_material) | self.logic.magic.can_use_clear_debris_instead_of_tool_level( tool_level) elif skill == Skill.mining: - xp_rule = self.tool.has_tool(Tool.pickaxe, - tool_material) | self.magic.can_use_clear_debris_instead_of_tool_level( + xp_rule = self.logic.tool.has_tool(Tool.pickaxe, + tool_material) | self.logic.magic.can_use_clear_debris_instead_of_tool_level( tool_level) elif skill == Skill.combat: combat_tier = Performance.tiers[tool_level] - xp_rule = self.combat.can_fight_at_level(combat_tier) + xp_rule = self.logic.combat.can_fight_at_level(combat_tier) else: raise Exception(f"Unknown skill: {skill}") @@ -93,65 +70,65 @@ def has_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() - if self.skill_option == options.SkillProgression.option_progressive: - return self.received(f"{skill} Level", level) + if self.options.skill_progression == options.SkillProgression.option_progressive: + return self.logic.received(f"{skill} Level", level) - return self.can_earn_level(skill, level) + return self.logic.skill.can_earn_level(skill, level) @cache_self1 def has_farming_level(self, level: int) -> StardewRule: - return self.has_level(Skill.farming, level) + return self.logic.skill.has_level(Skill.farming, level) # Should be cached def has_total_level(self, level: int, allow_modded_skills: bool = False) -> StardewRule: if level <= 0: return True_() - if self.skill_option == options.SkillProgression.option_progressive: + if self.options.skill_progression == options.SkillProgression.option_progressive: skills_items = ("Farming Level", "Mining Level", "Foraging Level", "Fishing Level", "Combat Level") if allow_modded_skills: - skills_items += get_mod_skill_levels(self.mods) - return self.received(skills_items, level) + skills_items += get_mod_skill_levels(self.options.mods) + return self.logic.received(skills_items, level) months_with_4_skills = max(1, (level // 4) - 1) months_with_5_skills = max(1, (level // 5) - 1) - rule_with_fishing = self.time.has_lived_months(months_with_5_skills) & self.can_get_fishing_xp + rule_with_fishing = self.logic.time.has_lived_months(months_with_5_skills) & self.logic.skill.can_get_fishing_xp if level > 40: return rule_with_fishing - return self.time.has_lived_months(months_with_4_skills) | rule_with_fishing + return self.logic.time.has_lived_months(months_with_4_skills) | rule_with_fishing @cached_property def can_get_farming_xp(self) -> StardewRule: crop_rules = [] for crop in all_crops: - crop_rules.append(self.crop.can_grow(crop)) + crop_rules.append(self.logic.crop.can_grow(crop)) return Or(*crop_rules) @cached_property def can_get_foraging_xp(self) -> StardewRule: - tool_rule = self.tool.has_tool(Tool.axe) - tree_rule = self.region.can_reach(Region.forest) & self.season.has_any_not_winter() - stump_rule = self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.axe, ToolMaterial.copper) + tool_rule = self.logic.tool.has_tool(Tool.axe) + tree_rule = self.logic.region.can_reach(Region.forest) & self.logic.season.has_any_not_winter() + stump_rule = self.logic.region.can_reach(Region.secret_woods) & self.logic.tool.has_tool(Tool.axe, ToolMaterial.copper) return tool_rule & (tree_rule | stump_rule) @cached_property def can_get_mining_xp(self) -> StardewRule: - tool_rule = self.tool.has_tool(Tool.pickaxe) - stone_rule = self.region.can_reach_any((Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5)) + tool_rule = self.logic.tool.has_tool(Tool.pickaxe) + stone_rule = self.logic.region.can_reach_any((Region.mines_floor_5, Region.quarry, Region.skull_cavern_25, Region.volcano_floor_5)) return tool_rule & stone_rule @cached_property def can_get_combat_xp(self) -> StardewRule: - tool_rule = self.combat.has_any_weapon() - enemy_rule = self.region.can_reach_any((Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5)) + tool_rule = self.logic.combat.has_any_weapon() + enemy_rule = self.logic.region.can_reach_any((Region.mines_floor_5, Region.skull_cavern_25, Region.volcano_floor_5)) return tool_rule & enemy_rule @cached_property def can_get_fishing_xp(self) -> StardewRule: - if self.skill_option == options.SkillProgression.option_progressive: - return self.can_fish() | self.can_crab_pot + if self.options.skill_progression == options.SkillProgression.option_progressive: + return self.logic.skill.can_fish() | self.logic.skill.can_crab_pot - return self.can_fish() + return self.logic.skill.can_fish() # Should be cached def can_fish(self, regions: Union[str, Tuple[str, ...]] = None, difficulty: int = 0) -> StardewRule: @@ -162,22 +139,22 @@ def can_fish(self, regions: Union[str, Tuple[str, ...]] = None, difficulty: int skill_required = min(10, max(0, int((difficulty / 10) - 1))) if difficulty <= 40: skill_required = 0 - skill_rule = self.has_level(Skill.fishing, skill_required) - region_rule = self.region.can_reach_any(regions) + skill_rule = self.logic.skill.has_level(Skill.fishing, skill_required) + region_rule = self.logic.region.can_reach_any(regions) number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4) - return self.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule + return self.logic.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule @cache_self1 def can_crab_pot_at(self, region: str) -> StardewRule: - return self.can_crab_pot & self.region.can_reach(region) + return self.logic.skill.can_crab_pot & self.logic.region.can_reach(region) @cached_property def can_crab_pot(self) -> StardewRule: - crab_pot_rule = self.has(Fishing.bait) - if self.skill_option == options.SkillProgression.option_progressive: - crab_pot_rule = crab_pot_rule & self.has(Machine.crab_pot) + crab_pot_rule = self.logic.has(Fishing.bait) + if self.options.skill_progression == options.SkillProgression.option_progressive: + crab_pot_rule = crab_pot_rule & self.logic.has(Machine.crab_pot) else: - crab_pot_rule = crab_pot_rule & self.can_get_fishing_xp + crab_pot_rule = crab_pot_rule & self.logic.skill.can_get_fishing_xp - water_region_rules = self.region.can_reach_any(fishing_regions) + water_region_rules = self.logic.region.can_reach_any(fishing_regions) return crab_pot_rule & water_region_rules diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 2fbb6fc6e77e..dfa15a5bb07c 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,10 +1,13 @@ +from typing import Union + from Utils import cache_self1 +from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .season_logic import SeasonLogicMixin -from ..mods.logic.magic_logic import MagicLogic +from ..mods.logic.magic_logic import MagicLogicMixin from ..options import ToolProgression from ..stardew_rule import StardewRule, True_ from ..strings.region_names import Region @@ -27,61 +30,44 @@ } -class ToolLogic: - tool_option = ToolProgression - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - season: SeasonLogicMixin - money: MoneyLogicMixin - magic: MagicLogic - - def __init__(self, player: int, tool_option: ToolProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - season: SeasonLogicMixin, - money: MoneyLogicMixin): - self.player = player - self.tool_option = tool_option - self.received = received - self.has = has - self.region = region - self.season = season - self.money = money +class ToolLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.tool = ToolLogic(*args, **kwargs) - def set_magic(self, magic: MagicLogic): - self.magic = magic +class ToolLogic(BaseLogic[Union[ToolLogicMixin, HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, MoneyLogicMixin, MagicLogicMixin]]): # Should be cached def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule: if material == ToolMaterial.basic or tool == Tool.scythe: return True_() - if self.tool_option & ToolProgression.option_progressive: - return self.received(f"Progressive {tool}", tool_materials[material]) + if self.options.tool_progression & ToolProgression.option_progressive: + return self.logic.received(f"Progressive {tool}", tool_materials[material]) - return self.has(f"{material} Bar") & self.money.can_spend(tool_upgrade_prices[material]) + return self.logic.has(f"{material} Bar") & self.logic.money.can_spend(tool_upgrade_prices[material]) @cache_self1 def has_fishing_rod(self, level: int) -> StardewRule: - if self.tool_option & ToolProgression.option_progressive: - return self.received(f"Progressive {Tool.fishing_rod}", level) + if self.options.tool_progression & ToolProgression.option_progressive: + return self.logic.received(f"Progressive {Tool.fishing_rod}", level) if level <= 1: - return self.region.can_reach(Region.beach) + return self.logic.region.can_reach(Region.beach) prices = {2: 500, 3: 1800, 4: 7500} level = min(level, 4) - return self.money.can_spend_at(Region.fish_shop, prices[level]) + return self.logic.money.can_spend_at(Region.fish_shop, prices[level]) # Should be cached def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: - season_rule = self.season.has(season) - region_rule = self.region.can_reach(region) + season_rule = self.logic.season.has(season) + region_rule = self.logic.region.can_reach(region) if need_hoe: - return season_rule & region_rule & self.has_tool(Tool.hoe) + return season_rule & region_rule & self.logic.tool.has_tool(Tool.hoe) return season_rule & region_rule @cache_self1 def can_water(self, level: int) -> StardewRule: - tool_rule = self.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) - spell_rule = self.received(MagicSpell.water) & self.magic.can_use_altar() & self.received( - f"{ModSkill.magic} Level", level) + tool_rule = self.logic.tool.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) + spell_rule = self.logic.received(MagicSpell.water) & self.logic.magic.can_use_altar() & self.logic.received(f"{ModSkill.magic} Level", level) return tool_rule | spell_rule diff --git a/worlds/stardew_valley/mods/logic/elevator_logic.py b/worlds/stardew_valley/mods/logic/elevator_logic.py index 4abf17687c2f..f1d12bcb1c37 100644 --- a/worlds/stardew_valley/mods/logic/elevator_logic.py +++ b/worlds/stardew_valley/mods/logic/elevator_logic.py @@ -1,22 +1,18 @@ +from ...logic.base_logic import BaseLogicMixin, BaseLogic from ...logic.received_logic import ReceivedLogicMixin from ...mods.mod_data import ModNames -from ...options import ElevatorProgression, Mods +from ...options import ElevatorProgression from ...stardew_rule import StardewRule, True_ -class ModElevatorLogic: - player: int - elevator_option: ElevatorProgression - mods: Mods - received: ReceivedLogicMixin +class ModElevatorLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.elevator = ModElevatorLogic(*args, **kwargs) - def __init__(self, player: int, elevator_option: ElevatorProgression, mods: Mods, received: ReceivedLogicMixin): - self.player = player - self.elevator_option = elevator_option - self.mods = mods - self.received = received +class ModElevatorLogic(BaseLogic[ReceivedLogicMixin]): def has_skull_cavern_elevator_to_floor(self, floor: int) -> StardewRule: - if self.elevator_option != ElevatorProgression.option_vanilla and ModNames.skull_cavern_elevator in self.mods: - return self.received("Progressive Skull Cavern Elevator", floor // 25) + if self.options.elevator_progression != ElevatorProgression.option_vanilla and ModNames.skull_cavern_elevator in self.options.mods: + return self.logic.received("Progressive Skull Cavern Elevator", floor // 25) return True_() diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index b005b4f73ea6..4457aade3369 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -1,75 +1,52 @@ -from typing import Union - from .buildings_logic import ModBuildingLogic from .deepwoods_logic import DeepWoodsLogic -from .elevator_logic import ModElevatorLogic +from .elevator_logic import ModElevatorLogicMixin from .item_logic import ModItemLogic -from .magic_logic import MagicLogic, MagicLogicMixin +from .magic_logic import MagicLogicMixin from .quests_logic import ModQuestLogic from .skills_logic import ModSkillLogic from .special_orders_logic import ModSpecialOrderLogic from .sve_logic import SVELogic from ...logic.ability_logic import AbilityLogic -from ...logic.action_logic import ActionLogicMixin -from ...logic.artisan_logic import ArtisanLogicMixin -from ...logic.base_logic import LogicRegistry, BaseLogic, BaseLogicMixin -from ...logic.building_logic import BuildingLogicMixin -from ...logic.combat_logic import CombatLogicMixin +from ...logic.base_logic import LogicRegistry, BaseLogicMixin from ...logic.cooking_logic import CookingLogic from ...logic.crafting_logic import CraftingLogic -from ...logic.crop_logic import CropLogic from ...logic.fishing_logic import FishingLogic -from ...logic.has_logic import HasLogicMixin from ...logic.mine_logic import MineLogic -from ...logic.money_logic import MoneyLogicMixin -from ...logic.museum_logic import MuseumLogicMixin from ...logic.quest_logic import QuestLogic -from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin -from ...logic.relationship_logic import RelationshipLogicMixin -from ...logic.season_logic import SeasonLogicMixin from ...logic.skill_logic import SkillLogic -from ...logic.time_logic import TimeLogicMixin -from ...logic.tool_logic import ToolLogic -from ...logic.wallet_logic import WalletLogicMixin from ...options import SkillProgression, ElevatorProgression, Mods class ModLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.mod = ModLogic(*args, **kwargs) + self.mod = None -class ModLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, ActionLogicMixin, ArtisanLogicMixin, SeasonLogicMixin, -MoneyLogicMixin, MuseumLogicMixin, RelationshipLogicMixin, BuildingLogicMixin, WalletLogicMixin, CombatLogicMixin]], MagicLogicMixin): +class ModLogic(ModElevatorLogicMixin, MagicLogicMixin): items: ModItemLogic quests: ModQuestLogic region: RegionLogicMixin - magic: MagicLogic buildings: ModBuildingLogic special_orders: ModSpecialOrderLogic - elevator: ModElevatorLogic deepwoods: DeepWoodsLogic skill: ModSkillLogic sve: SVELogic def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, - tool: ToolLogic, skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, - quest: QuestLogic, crafting: CraftingLogic, crop: CropLogic): + skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, + quest: QuestLogic, crafting: CraftingLogic): super().__init__(player, registry, options, logic) - self.item = ModItemLogic(mods, logic.combat, crop, cooking, logic.has, logic.money, logic.region, logic.season, logic.relationship, logic.museum, tool, crafting) + self.item = ModItemLogic(mods, logic.combat, logic.crop, cooking, logic.has, logic.money, logic.region, logic.season, logic.relationship, logic.museum, logic.tool, crafting) self.quests = ModQuestLogic(mods, logic.received, logic.has, logic.region, logic.time, logic.season, logic.relationship) self.buildings = ModBuildingLogic(player, registry, options, logic) - self.special_orders = ModSpecialOrderLogic(player, logic.action, logic.artisan, crafting, crop, logic.has, logic.region, logic.relationship, + self.special_orders = ModSpecialOrderLogic(player, logic.action, logic.artisan, crafting, logic.crop, logic.has, logic.region, logic.relationship, logic.season, logic.wallet, mods) - self.elevator = ModElevatorLogic(player, elevator_option, mods, logic.received) - self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, logic.received, logic.has, logic.combat, tool, skill, cooking) - self.skill = ModSkillLogic(player, skill_option, logic.received, logic.has, logic.region, logic.action, logic.relationship, logic.buildings, tool, - fishing, cooking, self.magic, mods) - self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.buildings, tool, + self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, logic.received, logic.has, logic.combat, logic.tool, skill, cooking) + self.skill = ModSkillLogic(player, skill_option, logic.received, logic.has, logic.region, logic.action, logic.relationship, logic.buildings, logic.tool, + fishing, cooking, logic.magic, mods) + self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.buildings, logic.tool, fishing, cooking, logic.money, logic.combat, logic.season, logic.time) - tool.set_magic(self.magic) - ability.set_magic(self.magic, self.skill) - skill.set_mod_logic(self.magic, mods) - mine.set_modded_elevator(self.elevator) + ability.set_magic(logic.magic, self.skill) From 0db282ce20d601b558f2e460bb8361b835971f2a Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 20 Nov 2023 23:43:56 -0500 Subject: [PATCH 194/482] fishing and bundle mixin --- worlds/stardew_valley/logic/bundle_logic.py | 40 ++++++------- worlds/stardew_valley/logic/fishing_logic.py | 62 ++++++++------------ worlds/stardew_valley/logic/logic.py | 9 +-- 3 files changed, 46 insertions(+), 65 deletions(-) diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 826256573e1d..6098e6b09f98 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,7 +1,8 @@ from functools import cached_property -from typing import Tuple +from typing import Tuple, Union -from .farming_logic import FarmingLogic +from .base_logic import BaseLogicMixin, BaseLogic +from .farming_logic import FarmingLogicMixin from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .region_logic import RegionLogicMixin @@ -10,39 +11,32 @@ from ..strings.region_names import Region -class BundleLogic: - has: HasLogicMixin - region: RegionLogicMixin - money: MoneyLogicMixin - farming: FarmingLogic +class BundleLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.bundle = BundleLogic(*args, **kwargs) - def __init__(self, player: int, has: HasLogicMixin, region: RegionLogicMixin, money: MoneyLogicMixin, farming: FarmingLogic): - self.player = player - self.has = has - self.region = region - self.money = money - self.farming = farming +class BundleLogic(BaseLogic[Union[HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, FarmingLogicMixin]]): # Should be cached def can_complete_bundle(self, bundle_requirements: Tuple[BundleItem], number_required: int) -> StardewRule: item_rules = [] highest_quality_yet = 0 - can_speak_junimo = self.region.can_reach(Region.wizard_tower) + can_speak_junimo = self.logic.region.can_reach(Region.wizard_tower) for bundle_item in bundle_requirements: if bundle_item.item.item_id == -1: - return can_speak_junimo & self.money.can_spend(bundle_item.amount) + return can_speak_junimo & self.logic.money.can_spend(bundle_item.amount) else: item_rules.append(bundle_item.item.name) if bundle_item.quality > highest_quality_yet: highest_quality_yet = bundle_item.quality - return can_speak_junimo & self.has(tuple(item_rules), number_required) & self.farming.can_grow_crop_quality( - highest_quality_yet) + return can_speak_junimo & self.logic.has(tuple(item_rules), number_required) & self.logic.farming.can_grow_crop_quality(highest_quality_yet) @cached_property def can_complete_community_center(self) -> StardewRule: - return (self.region.can_reach_location("Complete Crafts Room") & - self.region.can_reach_location("Complete Pantry") & - self.region.can_reach_location("Complete Fish Tank") & - self.region.can_reach_location("Complete Bulletin Board") & - self.region.can_reach_location("Complete Vault") & - self.region.can_reach_location("Complete Boiler Room")) + return (self.logic.region.can_reach_location("Complete Crafts Room") & + self.logic.region.can_reach_location("Complete Pantry") & + self.logic.region.can_reach_location("Complete Fish Tank") & + self.logic.region.can_reach_location("Complete Bulletin Board") & + self.logic.region.can_reach_location("Complete Vault") & + self.logic.region.can_reach_location("Complete Boiler Room")) diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index b42e9e2107e5..2fe53510b96e 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,9 +1,12 @@ +from typing import Union + from Utils import cache_self1 +from .base_logic import BaseLogicMixin, BaseLogic from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .season_logic import SeasonLogic -from .skill_logic import SkillLogic -from .tool_logic import ToolLogic +from .season_logic import SeasonLogicMixin +from .skill_logic import SkillLogicMixin +from .tool_logic import ToolLogicMixin from ..data import FishItem from ..data.fish_data import legendary_fish from ..options import ExcludeGingerIsland @@ -14,60 +17,47 @@ from ..strings.skill_names import Skill -class FishingLogic: - exclude_ginger_island: ExcludeGingerIsland - special_order_locations: SpecialOrderLocations - received: ReceivedLogicMixin - region: RegionLogicMixin - season: SeasonLogic - tool: ToolLogic - skill: SkillLogic +class FishingLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fishing = FishingLogic(*args, **kwargs) - def __init__(self, player: int, exclude_ginger_island: ExcludeGingerIsland, special_order_locations: SpecialOrderLocations, received: ReceivedLogicMixin, - region: RegionLogicMixin, season: SeasonLogic, tool: ToolLogic, skill: SkillLogic): - self.player = player - self.exclude_ginger_island = exclude_ginger_island - self.special_order_locations = special_order_locations - self.received = received - self.region = region - self.season = season - self.tool = tool - self.skill = skill +class FishingLogic(BaseLogic[Union[FishingLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, ToolLogicMixin, SkillLogicMixin]]): def can_fish_in_freshwater(self) -> StardewRule: - return self.skill.can_fish() & self.region.can_reach_any((Region.forest, Region.town, Region.mountain)) + return self.logic.skill.can_fish() & self.logic.region.can_reach_any((Region.forest, Region.town, Region.mountain)) def has_max_fishing(self) -> StardewRule: - skill_rule = self.skill.has_level(Skill.fishing, 10) - return self.tool.has_fishing_rod(4) & skill_rule + skill_rule = self.logic.skill.has_level(Skill.fishing, 10) + return self.logic.tool.has_fishing_rod(4) & skill_rule def can_fish_chests(self) -> StardewRule: - skill_rule = self.skill.has_level(Skill.fishing, 6) - return self.tool.has_fishing_rod(4) & skill_rule + skill_rule = self.logic.skill.has_level(Skill.fishing, 6) + return self.logic.tool.has_fishing_rod(4) & skill_rule def can_fish_at(self, region: str) -> StardewRule: - return self.skill.can_fish() & self.region.can_reach(region) + return self.logic.skill.can_fish() & self.logic.region.can_reach(region) @cache_self1 def can_catch_fish(self, fish: FishItem) -> StardewRule: quest_rule = True_() if fish.extended_family: - quest_rule = self.can_start_extended_family_quest() - region_rule = self.region.can_reach_any(fish.locations) - season_rule = self.season.has_any(fish.seasons) + quest_rule = self.logic.fishing.can_start_extended_family_quest() + region_rule = self.logic.region.can_reach_any(fish.locations) + season_rule = self.logic.season.has_any(fish.seasons) if fish.difficulty == -1: - difficulty_rule = self.skill.can_crab_pot + difficulty_rule = self.logic.skill.can_crab_pot else: - difficulty_rule = self.skill.can_fish(difficulty=(120 if fish.legendary else fish.difficulty)) + difficulty_rule = self.logic.skill.can_fish(difficulty=(120 if fish.legendary else fish.difficulty)) if fish.name == SVEFish.kittyfish: - item_rule = self.received("Kittyfish Spell") + item_rule = self.logic.received("Kittyfish Spell") else: item_rule = True_() return quest_rule & region_rule & season_rule & difficulty_rule & item_rule def can_start_extended_family_quest(self) -> StardewRule: - if self.exclude_ginger_island == ExcludeGingerIsland.option_true: + if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: return False_() - if self.special_order_locations != SpecialOrderLocations.option_board_qi: + if self.options.special_order_locations != SpecialOrderLocations.option_board_qi: return False_() - return self.region.can_reach(Region.qi_walnut_room) & And(*(self.can_catch_fish(fish) for fish in legendary_fish)) + return self.logic.region.can_reach(Region.qi_walnut_room) & And(*(self.logic.fishing.can_catch_fish(fish) for fish in legendary_fish)) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index ace67d606eb0..847ef249ba55 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -9,13 +9,13 @@ from .artisan_logic import ArtisanLogicMixin from .base_logic import LogicRegistry from .building_logic import BuildingLogicMixin -from .bundle_logic import BundleLogic +from .bundle_logic import BundleLogicMixin from .combat_logic import CombatLogicMixin from .cooking_logic import CookingLogic from .crafting_logic import CraftingLogic from .crop_logic import CropLogicMixin from .farming_logic import FarmingLogicMixin -from .fishing_logic import FishingLogic +from .fishing_logic import FishingLogicMixin from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin from .mine_logic import MineLogic @@ -90,7 +90,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, - SkillLogicMixin, FarmingLogicMixin): + SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin): player: int options: StardewValleyOptions @@ -119,9 +119,6 @@ def __init__(self, player: int, options: StardewValleyOptions): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.bundle = BundleLogic(self.player, self.has, self.region, self.money, self.farming) - self.fishing = FishingLogic(self.player, exclude_ginger_island, special_order_locations, self.received, self.region, self.season, - self.tool, self.skill) self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, self.tool, self.skill) self.cooking = CookingLogic(self.player, self.options.chefsanity, exclude_ginger_island, mods_option, self.received, self.has, From e91005d65956fa5669ef5d1c823555fab8cc24bb Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 20 Nov 2023 23:55:46 -0500 Subject: [PATCH 195/482] cooking and mine mixin --- worlds/stardew_valley/logic/cooking_logic.py | 104 +++++++------------ worlds/stardew_valley/logic/logic.py | 10 +- worlds/stardew_valley/logic/mine_logic.py | 85 +++++++-------- 3 files changed, 79 insertions(+), 120 deletions(-) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index f4675a0ebca6..ddbfefdfd446 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -1,7 +1,9 @@ from functools import cached_property +from typing import Union from Utils import cache_self1 from .action_logic import ActionLogicMixin +from .base_logic import BaseLogicMixin, BaseLogic from .building_logic import BuildingLogicMixin from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin @@ -9,7 +11,7 @@ from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin -from .skill_logic import SkillLogic +from .skill_logic import SkillLogicMixin from .time_logic import TimeLogicMixin from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \ QueenOfSauceSource, CookingRecipe, \ @@ -17,113 +19,87 @@ from ..data.recipe_source import CutsceneSource, ShopTradeSource from ..locations import locations_by_tag, LocationTags from ..options import Chefsanity -from ..options import ExcludeGingerIsland, Mods +from ..options import ExcludeGingerIsland from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region from ..strings.skill_names import Skill from ..strings.tv_channel_names import Channel -class CookingLogic: - chefsanity_option: Chefsanity - exclude_ginger_island: ExcludeGingerIsland - mods: Mods - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - season: SeasonLogicMixin - time: TimeLogicMixin - money: MoneyLogicMixin - action: ActionLogicMixin - buildings: BuildingLogicMixin - relationship: RelationshipLogicMixin - skill: SkillLogic +class CookingLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.cooking = CookingLogic(*args, **kwargs) - def __init__(self, player: int, chefsanity_option: Chefsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, received: ReceivedLogicMixin, - has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, money: MoneyLogicMixin, action: ActionLogicMixin, - buildings: BuildingLogicMixin, - relationship: RelationshipLogicMixin, skill: SkillLogic): - self.player = player - self.chefsanity_option = chefsanity_option - self.exclude_ginger_island = exclude_ginger_island - self.mods = mods - self.received = received - self.has = has - self.region = region - self.season = season - self.time = time - self.money = money - self.action = action - self.buildings = buildings - self.relationship = relationship - self.skill = skill +class CookingLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, MoneyLogicMixin, ActionLogicMixin, +BuildingLogicMixin, RelationshipLogicMixin, SkillLogicMixin, CookingLogicMixin]]): @cached_property def can_cook_in_kitchen(self) -> StardewRule: - return self.buildings.has_house(1) | self.skill.has_level(Skill.foraging, 9) + return self.logic.buildings.has_house(1) | self.logic.skill.has_level(Skill.foraging, 9) # Should be cached def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: - cook_rule = self.region.can_reach(Region.kitchen) + cook_rule = self.logic.region.can_reach(Region.kitchen) if recipe is None: return cook_rule - recipe_rule = self.knows_recipe(recipe.source, recipe.meal) - ingredients_rule = And(*(self.has(ingredient) for ingredient in recipe.ingredients)) + recipe_rule = self.logic.cooking.knows_recipe(recipe.source, recipe.meal) + ingredients_rule = And(*(self.logic.has(ingredient) for ingredient in recipe.ingredients)) return cook_rule & recipe_rule & ingredients_rule # Should be cached def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: - if self.chefsanity_option == Chefsanity.option_none: - return self.can_learn_recipe(source) + if self.options.chefsanity == Chefsanity.option_none: + return self.logic.cooking.can_learn_recipe(source) if isinstance(source, StarterSource): - return self.received_recipe(meal_name) - if isinstance(source, ShopTradeSource) and self.chefsanity_option & Chefsanity.option_purchases: - return self.received_recipe(meal_name) - if isinstance(source, ShopSource) and self.chefsanity_option & Chefsanity.option_purchases: - return self.received_recipe(meal_name) - if isinstance(source, SkillSource) and self.chefsanity_option & Chefsanity.option_skills: - return self.received_recipe(meal_name) - if isinstance(source, CutsceneSource) and self.chefsanity_option & Chefsanity.option_friendship: - return self.received_recipe(meal_name) - if isinstance(source, FriendshipSource) and self.chefsanity_option & Chefsanity.option_friendship: - return self.received_recipe(meal_name) - if isinstance(source, QueenOfSauceSource) and self.chefsanity_option & Chefsanity.option_queen_of_sauce: - return self.received_recipe(meal_name) - return self.can_learn_recipe(source) + return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, ShopTradeSource) and self.options.chefsanity & Chefsanity.option_purchases: + return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, ShopSource) and self.options.chefsanity & Chefsanity.option_purchases: + return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, SkillSource) and self.options.chefsanity & Chefsanity.option_skills: + return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, CutsceneSource) and self.options.chefsanity & Chefsanity.option_friendship: + return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, FriendshipSource) and self.options.chefsanity & Chefsanity.option_friendship: + return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, QueenOfSauceSource) and self.options.chefsanity & Chefsanity.option_queen_of_sauce: + return self.logic.cooking.received_recipe(meal_name) + return self.logic.cooking.can_learn_recipe(source) @cache_self1 def can_learn_recipe(self, source: RecipeSource) -> StardewRule: if isinstance(source, StarterSource): return True_() if isinstance(source, ShopTradeSource): - return self.money.can_trade_at(source.region, source.currency, source.price) + return self.logic.money.can_trade_at(source.region, source.currency, source.price) if isinstance(source, ShopSource): - return self.money.can_spend_at(source.region, source.price) + return self.logic.money.can_spend_at(source.region, source.price) if isinstance(source, SkillSource): - return self.skill.has_level(source.skill, source.level) + return self.logic.skill.has_level(source.skill, source.level) if isinstance(source, CutsceneSource): - return self.region.can_reach(source.region) & self.relationship.has_hearts(source.friend, source.hearts) + return self.logic.region.can_reach(source.region) & self.logic.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, FriendshipSource): - return self.relationship.has_hearts(source.friend, source.hearts) + return self.logic.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, QueenOfSauceSource): - return self.action.can_watch(Channel.queen_of_sauce) & self.season.has(source.season) + return self.logic.action.can_watch(Channel.queen_of_sauce) & self.logic.season.has(source.season) return False_() @cache_self1 def received_recipe(self, meal_name: str): - return self.received(f"{meal_name} Recipe") + return self.logic.received(f"{meal_name} Recipe") @cached_property def can_cook_everything(self) -> StardewRule: cooksanity_prefix = "Cook " all_recipes_names = [] - exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true for location in locations_by_tag[LocationTags.COOKSANITY]: if exclude_island and LocationTags.GINGER_ISLAND in location.tags: continue - if location.mod_name and location.mod_name not in self.mods: + if location.mod_name and location.mod_name not in self.options.mods: continue all_recipes_names.append(location.name[len(cooksanity_prefix):]) all_recipes = [all_cooking_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] - return And(*(self.can_cook(recipe) for recipe in all_recipes)) + return And(*(self.logic.cooking.can_cook(recipe) for recipe in all_recipes)) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 847ef249ba55..c7ce1ae04101 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -11,14 +11,14 @@ from .building_logic import BuildingLogicMixin from .bundle_logic import BundleLogicMixin from .combat_logic import CombatLogicMixin -from .cooking_logic import CookingLogic +from .cooking_logic import CookingLogicMixin from .crafting_logic import CraftingLogic from .crop_logic import CropLogicMixin from .farming_logic import FarmingLogicMixin from .fishing_logic import FishingLogicMixin from .gift_logic import GiftLogicMixin from .has_logic import HasLogicMixin -from .mine_logic import MineLogic +from .mine_logic import MineLogicMixin from .money_logic import MoneyLogicMixin from .monster_logic import MonsterLogicMixin from .museum_logic import MuseumLogicMixin @@ -90,7 +90,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, - SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin): + SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin): player: int options: StardewValleyOptions @@ -119,10 +119,6 @@ def __init__(self, player: int, options: StardewValleyOptions): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.mine = MineLogic(self.player, tool_option, skill_option, elevator_option, self.received, self.region, self.combat, - self.tool, self.skill) - self.cooking = CookingLogic(self.player, self.options.chefsanity, exclude_ginger_island, mods_option, self.received, self.has, - self.region, self.season, self.time, self.money, self.action, self.buildings, self.relationship, self.skill) self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, diff --git a/worlds/stardew_valley/logic/mine_logic.py b/worlds/stardew_valley/logic/mine_logic.py index 315931280d55..2c2eaabfd8ee 100644 --- a/worlds/stardew_valley/logic/mine_logic.py +++ b/worlds/stardew_valley/logic/mine_logic.py @@ -1,11 +1,14 @@ +from typing import Union + from Utils import cache_self1 -from .combat_logic import CombatLogic +from .base_logic import BaseLogicMixin, BaseLogic +from .combat_logic import CombatLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .skill_logic import SkillLogic -from .tool_logic import ToolLogic +from .skill_logic import SkillLogicMixin +from .tool_logic import ToolLogicMixin from .. import options -from ..options import ToolProgression, SkillProgression, ElevatorProgression +from ..options import ToolProgression from ..stardew_rule import StardewRule, And, True_ from ..strings.performance_names import Performance from ..strings.region_names import Region @@ -13,87 +16,71 @@ from ..strings.tool_names import Tool, ToolMaterial -class MineLogic: - tool_option: ToolProgression - skill_option: SkillProgression - elevator_option: ElevatorProgression - received: ReceivedLogicMixin - region: RegionLogicMixin - combat: CombatLogic - tool: ToolLogic - skill: SkillLogic +class MineLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.mine = MineLogic(*args, **kwargs) - def __init__(self, player: int, tool_option: ToolProgression, skill_option: SkillProgression, elevator_option: ElevatorProgression, - received: ReceivedLogicMixin, - region: RegionLogicMixin, combat: CombatLogic, tool: ToolLogic, skill: SkillLogic): - self.player = player - self.tool_option = tool_option - self.skill_option = skill_option - self.elevator_option = elevator_option - self.received = received - self.region = region - self.combat = combat - self.tool = tool - self.skill = skill +class MineLogic(BaseLogic[Union[MineLogicMixin, RegionLogicMixin, ReceivedLogicMixin, CombatLogicMixin, ToolLogicMixin, SkillLogicMixin]]): # Regions def can_mine_in_the_mines_floor_1_40(self) -> StardewRule: - return self.region.can_reach(Region.mines_floor_5) + return self.logic.region.can_reach(Region.mines_floor_5) def can_mine_in_the_mines_floor_41_80(self) -> StardewRule: - return self.region.can_reach(Region.mines_floor_45) + return self.logic.region.can_reach(Region.mines_floor_45) def can_mine_in_the_mines_floor_81_120(self) -> StardewRule: - return self.region.can_reach(Region.mines_floor_85) + return self.logic.region.can_reach(Region.mines_floor_85) def can_mine_in_the_skull_cavern(self) -> StardewRule: - return (self.can_progress_in_the_mines_from_floor(120) & - self.region.can_reach(Region.skull_cavern)) + return (self.logic.mine.can_progress_in_the_mines_from_floor(120) & + self.logic.region.can_reach(Region.skull_cavern)) @cache_self1 def get_weapon_rule_for_floor_tier(self, tier: int): if tier >= 4: - return self.combat.can_fight_at_level(Performance.galaxy) + return self.logic.combat.can_fight_at_level(Performance.galaxy) if tier >= 3: - return self.combat.can_fight_at_level(Performance.great) + return self.logic.combat.can_fight_at_level(Performance.great) if tier >= 2: - return self.combat.can_fight_at_level(Performance.good) + return self.logic.combat.can_fight_at_level(Performance.good) if tier >= 1: - return self.combat.can_fight_at_level(Performance.decent) - return self.combat.can_fight_at_level(Performance.basic) + return self.logic.combat.can_fight_at_level(Performance.decent) + return self.logic.combat.can_fight_at_level(Performance.basic) @cache_self1 def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule: tier = floor // 40 rules = [] - weapon_rule = self.get_weapon_rule_for_floor_tier(tier) + weapon_rule = self.logic.mine.get_weapon_rule_for_floor_tier(tier) rules.append(weapon_rule) - if self.tool_option & ToolProgression.option_progressive: - rules.append(self.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) - if self.skill_option == options.SkillProgression.option_progressive: + if self.options.tool_progression & ToolProgression.option_progressive: + rules.append(self.logic.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier])) + if self.options.skill_progression == options.SkillProgression.option_progressive: skill_tier = min(10, max(0, tier * 2)) - rules.append(self.skill.has_level(Skill.combat, skill_tier)) - rules.append(self.skill.has_level(Skill.mining, skill_tier)) + rules.append(self.logic.skill.has_level(Skill.combat, skill_tier)) + rules.append(self.logic.skill.has_level(Skill.mining, skill_tier)) return And(*rules) @cache_self1 def has_mine_elevator_to_floor(self, floor: int) -> StardewRule: if floor < 0: floor = 0 - if self.elevator_option != options.ElevatorProgression.option_vanilla: - return self.received("Progressive Mine Elevator", floor // 5) + if self.options.elevator_progression != options.ElevatorProgression.option_vanilla: + return self.logic.received("Progressive Mine Elevator", floor // 5) return True_() @cache_self1 def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule: tier = floor // 50 rules = [] - weapon_rule = self.combat.has_great_weapon + weapon_rule = self.logic.combat.has_great_weapon rules.append(weapon_rule) - if self.tool_option & ToolProgression.option_progressive: - rules.append(self.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) - if self.skill_option == options.SkillProgression.option_progressive: + if self.options.tool_progression & ToolProgression.option_progressive: + rules.append(self.logic.received("Progressive Pickaxe", min(4, max(0, tier + 2)))) + if self.options.skill_progression == options.SkillProgression.option_progressive: skill_tier = min(10, max(0, tier * 2 + 6)) - rules.extend({self.skill.has_level(Skill.combat, skill_tier), - self.skill.has_level(Skill.mining, skill_tier)}) + rules.extend({self.logic.skill.has_level(Skill.combat, skill_tier), + self.logic.skill.has_level(Skill.mining, skill_tier)}) return And(*rules) From 8665307689b4bdf2148e1d6934df6c97cdb5d178 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 21 Nov 2023 00:12:53 -0500 Subject: [PATCH 196/482] ability and mod skill mixin --- worlds/stardew_valley/logic/ability_logic.py | 69 +++++------- worlds/stardew_valley/logic/logic.py | 6 +- worlds/stardew_valley/mods/logic/mod_logic.py | 8 +- .../stardew_valley/mods/logic/skills_logic.py | 100 +++++++----------- 4 files changed, 68 insertions(+), 115 deletions(-) diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index 21c1dfee6987..ad444ad99fca 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -1,11 +1,12 @@ -from .mine_logic import MineLogic +from typing import Union + +from .base_logic import BaseLogicMixin, BaseLogic +from .mine_logic import MineLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin -from .skill_logic import SkillLogic -from .tool_logic import ToolLogic -from ..mods.logic.magic_logic import MagicLogic -from ..mods.logic.skills_logic import ModSkillLogic -from ..options import NumberOfMovementBuffs, NumberOfLuckBuffs +from .skill_logic import SkillLogicMixin +from .tool_logic import ToolLogicMixin +from ..mods.logic.magic_logic import MagicLogicMixin from ..stardew_rule import StardewRule from ..strings.ap_names.buff_names import Buff from ..strings.region_names import Region @@ -13,57 +14,37 @@ from ..strings.tool_names import ToolMaterial, Tool -class AbilityLogic: - player: int - movement_buff_option: NumberOfMovementBuffs - luck_buff_option: NumberOfLuckBuffs - received: ReceivedLogicMixin - region: RegionLogicMixin - tool: ToolLogic - skill: SkillLogic - mine: MineLogic - magic: MagicLogic - mod_skill: ModSkillLogic - - def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogicMixin, - region: RegionLogicMixin, tool: ToolLogic, skill: SkillLogic, mine: MineLogic): - self.player = player - self.movement_buff_option = movement_buff_option - self.luck_buff_option = luck_buff_option - self.received = received - self.region = region - self.tool = tool - self.skill = skill - self.mine = mine +class AbilityLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.ability = AbilityLogic(*args, **kwargs) - def set_magic(self, magic: MagicLogic, mod_skill: ModSkillLogic): - self.magic = magic - self.mod_skill = mod_skill +class AbilityLogic(BaseLogic[Union[AbilityLogicMixin, RegionLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, MagicLogicMixin]]): def can_mine_perfectly(self) -> StardewRule: - return self.mine.can_progress_in_the_mines_from_floor(160) + return self.logic.mine.can_progress_in_the_mines_from_floor(160) def can_mine_perfectly_in_the_skull_cavern(self) -> StardewRule: - return (self.can_mine_perfectly() & - self.region.can_reach(Region.skull_cavern)) + return (self.logic.ability.can_mine_perfectly() & + self.logic.region.can_reach(Region.skull_cavern)) def can_farm_perfectly(self) -> StardewRule: - tool_rule = self.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.tool.can_water(4) - return tool_rule & self.skill.has_farming_level(10) + tool_rule = self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.logic.tool.can_water(4) + return tool_rule & self.logic.skill.has_farming_level(10) def can_fish_perfectly(self) -> StardewRule: - skill_rule = self.skill.has_level(Skill.fishing, 10) - return skill_rule & self.tool.has_fishing_rod(4) + skill_rule = self.logic.skill.has_level(Skill.fishing, 10) + return skill_rule & self.logic.tool.has_fishing_rod(4) def can_chop_trees(self) -> StardewRule: - return self.tool.has_tool(Tool.axe) & self.region.can_reach(Region.forest) + return self.logic.tool.has_tool(Tool.axe) & self.logic.region.can_reach(Region.forest) def can_chop_perfectly(self) -> StardewRule: - magic_rule = (self.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.mod_skill.has_mod_level(ModSkill.magic, 10) - tool_rule = self.tool.has_tool(Tool.axe, ToolMaterial.iridium) - foraging_rule = self.skill.has_level(Skill.foraging, 10) - region_rule = self.region.can_reach(Region.forest) + magic_rule = (self.logic.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.logic.mod.skill.has_mod_level(ModSkill.magic, 10) + tool_rule = self.logic.tool.has_tool(Tool.axe, ToolMaterial.iridium) + foraging_rule = self.logic.skill.has_level(Skill.foraging, 10) + region_rule = self.logic.region.can_reach(Region.forest) return region_rule & ((tool_rule & foraging_rule) | magic_rule) def has_max_buffs(self) -> StardewRule: - return self.received(Buff.movement, self.movement_buff_option.value) & self.received(Buff.luck, self.luck_buff_option.value) + return self.logic.received(Buff.movement, self.options.movement_buff_number.value) & self.logic.received(Buff.luck, self.options.luck_buff_number.value) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index c7ce1ae04101..4d73aa6f4079 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting -from .ability_logic import AbilityLogic +from .ability_logic import AbilityLogicMixin from .action_logic import ActionLogicMixin from .arcade_logic import ArcadeLogicMixin from .artisan_logic import ArtisanLogicMixin @@ -90,7 +90,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, - SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin): + SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin): player: int options: StardewValleyOptions @@ -119,8 +119,6 @@ def __init__(self, player: int, options: StardewValleyOptions): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.ability = AbilityLogic(self.player, self.options.movement_buff_number, self.options.luck_buff_number, self.received, - self.region, self.tool, self.skill, self.mine) self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 4457aade3369..48b7185367a1 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -4,7 +4,7 @@ from .item_logic import ModItemLogic from .magic_logic import MagicLogicMixin from .quests_logic import ModQuestLogic -from .skills_logic import ModSkillLogic +from .skills_logic import ModSkillLogicMixin from .special_orders_logic import ModSpecialOrderLogic from .sve_logic import SVELogic from ...logic.ability_logic import AbilityLogic @@ -25,14 +25,13 @@ def __init__(self, *args, **kwargs): self.mod = None -class ModLogic(ModElevatorLogicMixin, MagicLogicMixin): +class ModLogic(ModElevatorLogicMixin, MagicLogicMixin, ModSkillLogicMixin): items: ModItemLogic quests: ModQuestLogic region: RegionLogicMixin buildings: ModBuildingLogic special_orders: ModSpecialOrderLogic deepwoods: DeepWoodsLogic - skill: ModSkillLogic sve: SVELogic def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, @@ -45,8 +44,5 @@ def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_o self.special_orders = ModSpecialOrderLogic(player, logic.action, logic.artisan, crafting, logic.crop, logic.has, logic.region, logic.relationship, logic.season, logic.wallet, mods) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, logic.received, logic.has, logic.combat, logic.tool, skill, cooking) - self.skill = ModSkillLogic(player, skill_option, logic.received, logic.has, logic.region, logic.action, logic.relationship, logic.buildings, logic.tool, - fishing, cooking, logic.magic, mods) self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.buildings, logic.tool, fishing, cooking, logic.money, logic.combat, logic.season, logic.time) - ability.set_magic(logic.magic, self.skill) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index d69e081c9a72..6d08dc522417 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -1,16 +1,19 @@ -from .magic_logic import MagicLogic +from typing import Union + +from .magic_logic import MagicLogicMixin from ...data.villagers_data import all_villagers from ...logic.action_logic import ActionLogicMixin +from ...logic.base_logic import BaseLogicMixin, BaseLogic from ...logic.building_logic import BuildingLogicMixin -from ...logic.cooking_logic import CookingLogic -from ...logic.fishing_logic import FishingLogic +from ...logic.cooking_logic import CookingLogicMixin +from ...logic.fishing_logic import FishingLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin -from ...logic.tool_logic import ToolLogic +from ...logic.tool_logic import ToolLogicMixin from ...mods.mod_data import ModNames -from ...options import SkillProgression, Mods +from ...options import SkillProgression from ...stardew_rule import Count, StardewRule, False_, True_ from ...strings.building_names import Building from ...strings.geode_names import Geode @@ -21,101 +24,76 @@ from ...strings.tool_names import Tool, ToolMaterial -class ModSkillLogic: - player: int - skill_option: SkillProgression - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - action: ActionLogicMixin - relationship: RelationshipLogicMixin - building: BuildingLogicMixin - tool: ToolLogic - fishing: FishingLogic - cooking: CookingLogic - magic: MagicLogic - mods_option: Mods +class ModSkillLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.skill = ModSkillLogic(*args, **kwargs) - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, - action: ActionLogicMixin, - relationship: RelationshipLogicMixin, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - magic: MagicLogic, mods_option: Mods): - self.player = player - self.skill_option = skill_option - self.received = received - self.has = has - self.region = region - self.action = action - self.relationship = relationship - self.building = building - self.tool = tool - self.fishing = fishing - self.cooking = cooking - self.magic = magic - self.mods_option = mods_option +class ModSkillLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, ActionLogicMixin, RelationshipLogicMixin, BuildingLogicMixin, +ToolLogicMixin, FishingLogicMixin, CookingLogicMixin, MagicLogicMixin]]): def has_mod_level(self, skill: str, level: int) -> StardewRule: if level <= 0: return True_() - if self.skill_option == SkillProgression.option_progressive: - return self.received(f"{skill} Level", level) + if self.options.skill_progression == SkillProgression.option_progressive: + return self.logic.received(f"{skill} Level", level) return self.can_earn_mod_skill_level(skill, level) def can_earn_mod_skill_level(self, skill: str, level: int) -> StardewRule: - if ModNames.luck_skill in self.mods_option and skill == ModSkill.luck: + if ModNames.luck_skill in self.options.mods and skill == ModSkill.luck: return self.can_earn_luck_skill_level(level) - if ModNames.magic in self.mods_option and skill == ModSkill.magic: + if ModNames.magic in self.options.mods and skill == ModSkill.magic: return self.can_earn_magic_skill_level(level) - if ModNames.socializing_skill in self.mods_option and skill == ModSkill.socializing: + if ModNames.socializing_skill in self.options.mods and skill == ModSkill.socializing: return self.can_earn_socializing_skill_level(level) - if ModNames.archaeology in self.mods_option and skill == ModSkill.archaeology: + if ModNames.archaeology in self.options.mods and skill == ModSkill.archaeology: return self.can_earn_archaeology_skill_level(level) - if ModNames.cooking_skill in self.mods_option and skill == ModSkill.cooking: + if ModNames.cooking_skill in self.options.mods and skill == ModSkill.cooking: return self.can_earn_cooking_skill_level(level) - if ModNames.binning_skill in self.mods_option and skill == ModSkill.binning: + if ModNames.binning_skill in self.options.mods and skill == ModSkill.binning: return self.can_earn_binning_skill_level(level) return False_() def can_earn_luck_skill_level(self, level: int) -> StardewRule: if level >= 6: - return self.fishing.can_fish_chests() | self.action.can_open_geode(Geode.magma) + return self.logic.fishing.can_fish_chests() | self.logic.action.can_open_geode(Geode.magma) else: - return self.fishing.can_fish_chests() | self.action.can_open_geode(Geode.geode) + return self.logic.fishing.can_fish_chests() | self.logic.action.can_open_geode(Geode.geode) def can_earn_magic_skill_level(self, level: int) -> StardewRule: - spell_count = [self.received(MagicSpell.clear_debris), self.received(MagicSpell.water), - self.received(MagicSpell.blink), self.received(MagicSpell.fireball), - self.received(MagicSpell.frostbite), - self.received(MagicSpell.descend), self.received(MagicSpell.tendrils), - self.received(MagicSpell.shockwave), - self.received(MagicSpell.meteor), - self.received(MagicSpell.spirit)] + spell_count = [self.logic.received(MagicSpell.clear_debris), self.logic.received(MagicSpell.water), + self.logic.received(MagicSpell.blink), self.logic.received(MagicSpell.fireball), + self.logic.received(MagicSpell.frostbite), + self.logic.received(MagicSpell.descend), self.logic.received(MagicSpell.tendrils), + self.logic.received(MagicSpell.shockwave), + self.logic.received(MagicSpell.meteor), + self.logic.received(MagicSpell.spirit)] return Count(level, spell_count) def can_earn_socializing_skill_level(self, level: int) -> StardewRule: villager_count = [] for villager in all_villagers: - if villager.mod_name in self.mods_option or villager.mod_name is None: - villager_count.append(self.relationship.can_earn_relationship(villager.name, level)) + if villager.mod_name in self.options.mods or villager.mod_name is None: + villager_count.append(self.logic.relationship.can_earn_relationship(villager.name, level)) return Count(level * 2, villager_count) def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: if level >= 6: - return self.action.can_pan() | self.tool.has_tool(Tool.hoe, ToolMaterial.gold) + return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.gold) else: - return self.action.can_pan() | self.tool.has_tool(Tool.hoe, ToolMaterial.basic) + return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic) def can_earn_cooking_skill_level(self, level: int) -> StardewRule: if level >= 6: - return self.cooking.can_cook() & self.region.can_reach(Region.saloon) & \ - self.building.has_building(Building.coop) & self.building.has_building(Building.barn) + return self.logic.cooking.can_cook() & self.logic.region.can_reach(Region.saloon) & \ + self.logic.buildings.has_building(Building.coop) & self.logic.buildings.has_building(Building.barn) else: - return self.cooking.can_cook() + return self.logic.cooking.can_cook() def can_earn_binning_skill_level(self, level: int) -> StardewRule: if level >= 6: - return self.has(Machine.recycling_machine) + return self.logic.has(Machine.recycling_machine) else: return True_() # You can always earn levels 1-5 with trash cans From b493b4906374cf7c0380944b571bc3a2bf888c66 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 21 Nov 2023 00:41:19 -0500 Subject: [PATCH 197/482] quest and crafting mixin --- worlds/stardew_valley/logic/base_logic.py | 28 +-- worlds/stardew_valley/logic/building_logic.py | 18 +- worlds/stardew_valley/logic/cooking_logic.py | 2 +- worlds/stardew_valley/logic/crafting_logic.py | 100 ++++------ worlds/stardew_valley/logic/logic.py | 58 +++--- worlds/stardew_valley/logic/quest_logic.py | 178 +++++++----------- .../logic/relationship_logic.py | 4 +- worlds/stardew_valley/logic/shipping_logic.py | 4 +- .../logic/special_order_logic.py | 160 +++++++--------- worlds/stardew_valley/mods/logic/mod_logic.py | 2 +- .../stardew_valley/mods/logic/skills_logic.py | 2 +- worlds/stardew_valley/rules.py | 14 +- worlds/stardew_valley/test/TestLogic.py | 8 +- 13 files changed, 244 insertions(+), 334 deletions(-) diff --git a/worlds/stardew_valley/logic/base_logic.py b/worlds/stardew_valley/logic/base_logic.py index 3d6521f19179..ea4f90798418 100644 --- a/worlds/stardew_valley/logic/base_logic.py +++ b/worlds/stardew_valley/logic/base_logic.py @@ -1,25 +1,27 @@ from __future__ import annotations -from typing import TypeVar, Generic +from typing import TypeVar, Generic, Dict from ..options import StardewValleyOptions +from ..stardew_rule import StardewRule class LogicRegistry: def __init__(self): - self.item_rules = {} - self.sapling_rules = {} - self.tree_fruit_rules = {} - self.seed_rules = {} - self.cooking_rules = {} - self.crafting_rules = {} - self.crop_rules = {} - self.fish_rules = {} - self.museum_rules = {} - self.festival_rules = {} - self.quest_rules = {} - self.building_rules = {} + self.item_rules: Dict[str, StardewRule] = {} + self.sapling_rules: Dict[str, StardewRule] = {} + self.tree_fruit_rules: Dict[str, StardewRule] = {} + self.seed_rules: Dict[str, StardewRule] = {} + self.cooking_rules: Dict[str, StardewRule] = {} + self.crafting_rules: Dict[str, StardewRule] = {} + self.crop_rules: Dict[str, StardewRule] = {} + self.fish_rules: Dict[str, StardewRule] = {} + self.museum_rules: Dict[str, StardewRule] = {} + self.festival_rules: Dict[str, StardewRule] = {} + self.quest_rules: Dict[str, StardewRule] = {} + self.building_rules: Dict[str, StardewRule] = {} + self.special_order_rules: Dict[str, StardewRule] = {} class BaseLogicMixin: diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index ecb503bf4797..5faac888c70c 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -20,7 +20,7 @@ class BuildingLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.buildings = BuildingLogic(*args, **kwargs) + self.building = BuildingLogic(*args, **kwargs) class BuildingLogic(BaseLogic[Union[BuildingLogicMixin, MoneyLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): @@ -28,23 +28,23 @@ def initialize_rules(self): self.registry.building_rules.update({ # @formatter:off Building.barn: self.logic.money.can_spend(6000) & self.logic.has((Material.wood, Material.stone)), - Building.big_barn: self.logic.money.can_spend(12000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.barn), - Building.deluxe_barn: self.logic.money.can_spend(25000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.big_barn), + Building.big_barn: self.logic.money.can_spend(12000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.barn), + Building.deluxe_barn: self.logic.money.can_spend(25000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.big_barn), Building.coop: self.logic.money.can_spend(4000) & self.logic.has((Material.wood, Material.stone)), - Building.big_coop: self.logic.money.can_spend(10000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.coop), - Building.deluxe_coop: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.big_coop), + Building.big_coop: self.logic.money.can_spend(10000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.coop), + Building.deluxe_coop: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.big_coop), Building.fish_pond: self.logic.money.can_spend(5000) & self.logic.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), Building.mill: self.logic.money.can_spend(2500) & self.logic.has((Material.stone, Material.wood, ArtisanGood.cloth)), Building.shed: self.logic.money.can_spend(15000) & self.logic.has(Material.wood), - Building.big_shed: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.buildings.has_building(Building.shed), + Building.big_shed: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.shed), Building.silo: self.logic.money.can_spend(100) & self.logic.has((Material.stone, Material.clay, MetalBar.copper)), Building.slime_hutch: self.logic.money.can_spend(10000) & self.logic.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), Building.stable: self.logic.money.can_spend(10000) & self.logic.has((Material.hardwood, MetalBar.iron)), Building.well: self.logic.money.can_spend(1000) & self.logic.has(Material.stone), Building.shipping_bin: self.logic.money.can_spend(250) & self.logic.has(Material.wood), - Building.kitchen: self.logic.money.can_spend(10000) & self.logic.has(Material.wood) & self.logic.buildings.has_house(0), - Building.kids_room: self.logic.money.can_spend(50000) & self.logic.has(Material.hardwood) & self.logic.buildings.has_house(1), - Building.cellar: self.logic.money.can_spend(100000) & self.logic.buildings.has_house(2), + Building.kitchen: self.logic.money.can_spend(10000) & self.logic.has(Material.wood) & self.logic.building.has_house(0), + Building.kids_room: self.logic.money.can_spend(50000) & self.logic.has(Material.hardwood) & self.logic.building.has_house(1), + Building.cellar: self.logic.money.can_spend(100000) & self.logic.building.has_house(2), # @formatter:on }) diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index ddbfefdfd446..b6c47f23fc8b 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -36,7 +36,7 @@ class CookingLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogi BuildingLogicMixin, RelationshipLogicMixin, SkillLogicMixin, CookingLogicMixin]]): @cached_property def can_cook_in_kitchen(self) -> StardewRule: - return self.logic.buildings.has_house(1) | self.logic.skill.has_level(Skill.foraging, 9) + return self.logic.building.has_house(1) | self.logic.skill.has_level(Skill.foraging, 9) # Should be cached def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index e8e66e4ce76c..be553cd3b198 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -1,13 +1,15 @@ from functools import cached_property +from typing import Union from Utils import cache_self1 +from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin -from .skill_logic import SkillLogic -from .special_order_logic import SpecialOrderLogic +from .skill_logic import SkillLogicMixin +from .special_order_logic import SpecialOrderLogicMixin from .time_logic import TimeLogicMixin from .. import options from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name @@ -15,116 +17,88 @@ from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, \ FestivalShopSource from ..locations import locations_by_tag, LocationTags -from ..options import Craftsanity, FestivalLocations, SpecialOrderLocations, ExcludeGingerIsland, Mods +from ..options import Craftsanity, SpecialOrderLocations, ExcludeGingerIsland from ..stardew_rule import StardewRule, True_, False_, And from ..strings.region_names import Region -class CraftingLogic: - craftsanity_option: Craftsanity - exclude_ginger_island: ExcludeGingerIsland - mods: Mods - festivals_option: FestivalLocations - special_orders_option: SpecialOrderLocations - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - time: TimeLogicMixin - money: MoneyLogicMixin - relationship: RelationshipLogicMixin - skill: SkillLogic - special_orders: SpecialOrderLogic +class CraftingLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.crafting = CraftingLogic(*args, **kwargs) - def __init__(self, player: int, craftsanity_option: Craftsanity, exclude_ginger_island: ExcludeGingerIsland, mods: Mods, - festivals_option: FestivalLocations, special_orders_option: SpecialOrderLocations, received: ReceivedLogicMixin, has: HasLogicMixin, - region: RegionLogicMixin, - time: TimeLogicMixin, money: MoneyLogicMixin, relationship: RelationshipLogicMixin, skill: SkillLogic, special_orders: SpecialOrderLogic): - self.player = player - self.craftsanity_option = craftsanity_option - self.exclude_ginger_island = exclude_ginger_island - self.mods = mods - self.festivals_option = festivals_option - self.special_orders_option = special_orders_option - self.received = received - self.has = has - self.region = region - self.time = time - self.money = money - self.relationship = relationship - self.skill = skill - self.special_orders = special_orders +class CraftingLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, RelationshipLogicMixin, +SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin]]): @cache_self1 def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: if recipe is None: return True_() - learn_rule = self.knows_recipe(recipe) - ingredients_rule = And(*(self.has(ingredient) for ingredient in recipe.ingredients)) + learn_rule = self.logic.crafting.knows_recipe(recipe) + ingredients_rule = And(*(self.logic.has(ingredient) for ingredient in recipe.ingredients)) return learn_rule & ingredients_rule @cache_self1 def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, ArchipelagoSource): - return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) + return self.logic.received(recipe.source.ap_item, len(recipe.source.ap_item)) if isinstance(recipe.source, FestivalShopSource): - if self.festivals_option == options.FestivalLocations.option_disabled: - return self.can_learn_recipe(recipe) + if self.options.festival_locations == options.FestivalLocations.option_disabled: + return self.logic.crafting.can_learn_recipe(recipe) else: - return self.received_recipe(recipe.item) - if self.craftsanity_option == Craftsanity.option_none: - return self.can_learn_recipe(recipe) + return self.logic.crafting.received_recipe(recipe.item) + if self.options.craftsanity == Craftsanity.option_none: + return self.logic.crafting.can_learn_recipe(recipe) if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance( recipe.source, ShopSource): - return self.received_recipe(recipe.item) - if isinstance(recipe.source, - SpecialOrderSource) and self.special_orders_option != SpecialOrderLocations.option_disabled: - return self.received_recipe(recipe.item) - return self.can_learn_recipe(recipe) + return self.logic.crafting.received_recipe(recipe.item) + if isinstance(recipe.source, SpecialOrderSource) and self.options.special_order_locations != SpecialOrderLocations.option_disabled: + return self.logic.crafting.received_recipe(recipe.item) + return self.logic.crafting.can_learn_recipe(recipe) @cache_self1 def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, StarterSource): return True_() if isinstance(recipe.source, ArchipelagoSource): - return self.received(recipe.source.ap_item, len(recipe.source.ap_item)) + return self.logic.received(recipe.source.ap_item, len(recipe.source.ap_item)) if isinstance(recipe.source, ShopTradeSource): - return self.money.can_trade_at(recipe.source.region, recipe.source.currency, recipe.source.price) + return self.logic.money.can_trade_at(recipe.source.region, recipe.source.currency, recipe.source.price) if isinstance(recipe.source, ShopSource): - return self.money.can_spend_at(recipe.source.region, recipe.source.price) + return self.logic.money.can_spend_at(recipe.source.region, recipe.source.price) if isinstance(recipe.source, SkillSource): - return self.skill.has_level(recipe.source.skill, recipe.source.level) + return self.logic.skill.has_level(recipe.source.skill, recipe.source.level) if isinstance(recipe.source, CutsceneSource): - return self.region.can_reach(recipe.source.region) & self.relationship.has_hearts(recipe.source.friend, - recipe.source.hearts) + return self.logic.region.can_reach(recipe.source.region) & self.logic.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) if isinstance(recipe.source, FriendshipSource): - return self.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) + return self.logic.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) if isinstance(recipe.source, SpecialOrderSource): - if self.special_orders_option == SpecialOrderLocations.option_disabled: - return self.special_orders.can_complete_special_order(recipe.source.special_order) - return self.received_recipe(recipe.item) + if self.options.special_order_locations == SpecialOrderLocations.option_disabled: + return self.logic.special_order.can_complete_special_order(recipe.source.special_order) + return self.logic.crafting.received_recipe(recipe.item) if isinstance(recipe.source, LogicSource): if recipe.source.logic_rule == "Cellar": - return self.region.can_reach(Region.cellar) + return self.logic.region.can_reach(Region.cellar) return False_() @cache_self1 def received_recipe(self, item_name: str): - return self.received(f"{item_name} Recipe") + return self.logic.received(f"{item_name} Recipe") @cached_property def can_craft_everything(self) -> StardewRule: craftsanity_prefix = "Craft " all_recipes_names = [] - exclude_island = self.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true for location in locations_by_tag[LocationTags.CRAFTSANITY]: if not location.name.startswith(craftsanity_prefix): continue if exclude_island and LocationTags.GINGER_ISLAND in location.tags: continue - if location.mod_name and location.mod_name not in self.mods: + if location.mod_name and location.mod_name not in self.options.mods: continue all_recipes_names.append(location.name[len(craftsanity_prefix):]) all_recipes = [all_crafting_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] - return And(*(self.can_craft(recipe) for recipe in all_recipes)) + return And(*(self.logic.crafting.can_craft(recipe) for recipe in all_recipes)) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 4d73aa6f4079..3d13c3ee62ad 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -12,7 +12,7 @@ from .bundle_logic import BundleLogicMixin from .combat_logic import CombatLogicMixin from .cooking_logic import CookingLogicMixin -from .crafting_logic import CraftingLogic +from .crafting_logic import CraftingLogicMixin from .crop_logic import CropLogicMixin from .farming_logic import FarmingLogicMixin from .fishing_logic import FishingLogicMixin @@ -23,14 +23,14 @@ from .monster_logic import MonsterLogicMixin from .museum_logic import MuseumLogicMixin from .pet_logic import PetLogicMixin -from .quest_logic import QuestLogic +from .quest_logic import QuestLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogicMixin from .skill_logic import SkillLogicMixin -from .special_order_logic import SpecialOrderLogic +from .special_order_logic import SpecialOrderLogicMixin from .time_logic import TimeLogicMixin from .tool_logic import ToolLogicMixin from .traveling_merchant_logic import TravelingMerchantLogicMixin @@ -90,7 +90,8 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, - SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin): + SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin, + SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin): player: int options: StardewValleyOptions @@ -119,13 +120,6 @@ def __init__(self, player: int, options: StardewValleyOptions): special_order_locations = self.options.special_order_locations mods_option = self.options.mods exclude_ginger_island = self.options.exclude_ginger_island - self.special_order = SpecialOrderLogic(self.player, self.received, self.has, self.region, self.season, self.time, self.money, self.shipping, - self.arcade, self.artisan, self.relationship, self.tool, self.skill, self.mine, self.cooking, self.ability) - self.quest = QuestLogic(self.player, self.skill, self.received, self.has, self.mine, self.region, self.action, self.relationship, self.buildings, - self.time, self.tool, self.fishing, self.cooking, self.money, self.combat, self.season, self.wallet, mods_option) - self.crafting = CraftingLogic(self.player, self.options.craftsanity, exclude_ginger_island, mods_option, - self.options.festival_locations, special_order_locations, self.received, self.has, self.region, self.time, self.money, - self.relationship, self.skill, self.special_order) self.mod = ModLogic(self.player, self.registry, self.options, self, skill_option, elevator_option, mods_option, self.skill, self.fishing, self.cooking, self.mine, self.ability, self.quest, self.crafting) @@ -206,10 +200,10 @@ def __init__(self, player: int, options: StardewValleyOptions): # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)), Animal.chicken: self.can_buy_animal(Animal.chicken), Animal.cow: self.can_buy_animal(Animal.cow), - Animal.dinosaur: self.buildings.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), + Animal.dinosaur: self.building.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), Animal.duck: self.can_buy_animal(Animal.duck), Animal.goat: self.can_buy_animal(Animal.goat), - Animal.ostrich: self.buildings.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), + Animal.ostrich: self.building.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), Animal.pig: self.can_buy_animal(Animal.pig), Animal.rabbit: self.can_buy_animal(Animal.rabbit), Animal.sheep: self.can_buy_animal(Animal.sheep), @@ -229,17 +223,17 @@ def __init__(self, player: int, options: StardewValleyOptions): AnimalProduct.milk: self.has_animal(Animal.cow), AnimalProduct.ostrich_egg: self.tool.can_forage(Generic.any, Region.island_north, True), AnimalProduct.rabbit_foot: self.has_happy_animal(Animal.rabbit), - AnimalProduct.roe: self.skill.can_fish() & self.buildings.has_building(Building.fish_pond), - AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.squid)), - AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.buildings.has_building(Building.fish_pond), + AnimalProduct.roe: self.skill.can_fish() & self.building.has_building(Building.fish_pond), + AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.building.has_building(Building.fish_pond) & self.has(Fish.squid)), + AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.building.has_building(Building.fish_pond), AnimalProduct.truffle: self.has_animal(Animal.pig) & self.season.has_any_not_winter(), - AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.buildings.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), + AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.building.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), AnimalProduct.slime_egg_green: self.has(Machine.slime_egg_press) & self.has(Loot.slime), AnimalProduct.slime_egg_blue: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(3), AnimalProduct.slime_egg_red: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(6), AnimalProduct.slime_egg_purple: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(9), - AnimalProduct.slime_egg_tiger: self.has(Fish.lionfish) & self.buildings.has_building(Building.fish_pond), + AnimalProduct.slime_egg_tiger: self.has(Fish.lionfish) & self.building.has_building(Building.fish_pond), ArtisanGood.aged_roe: self.artisan.can_preserves_jar(AnimalProduct.roe), ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.season.has_any_not_winter()) | self.has(Machine.solar_panel), ArtisanGood.caviar: self.artisan.can_preserves_jar(AnimalProduct.sturgeon_roe), @@ -296,7 +290,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Forageable.dragon_tooth: self.tool.can_forage(Generic.any, Region.volcano_floor_10), Forageable.fiddlehead_fern: self.tool.can_forage(Season.summer, Region.secret_woods), Forageable.ginger: self.tool.can_forage(Generic.any, Region.island_west, True), - Forageable.hay: self.buildings.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), + Forageable.hay: self.building.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), Forageable.hazelnut: self.tool.can_forage(Season.fall), Forageable.holly: self.tool.can_forage(Season.winter), Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), @@ -329,29 +323,29 @@ def __init__(self, player: int, options: StardewValleyOptions): Geode.frozen: self.mine.can_mine_in_the_mines_floor_41_80(), Geode.geode: self.mine.can_mine_in_the_mines_floor_1_40(), Geode.golden_coconut: self.region.can_reach(Region.island_north), - Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.buildings.has_building(Building.fish_pond)), - Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_pan() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.buildings.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), + Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.building.has_building(Building.fish_pond)), + Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.action.can_pan() | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.building.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10), Gift.bouquet: self.relationship.has_hearts(Generic.bachelor, 8) & self.money.can_spend_at(Region.pierre_store, 100), Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove), - Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.buildings.has_house(1) & self.has(Consumable.rain_totem), + Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts(Generic.bachelor, 10) & self.building.has_house(1) & self.has(Consumable.rain_totem), Gift.movie_ticket: self.money.can_spend_at(Region.movie_ticket_stand, 1000), - Gift.pearl: (self.has(Fish.blobfish) & self.buildings.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), + Gift.pearl: (self.has(Fish.blobfish) & self.building.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months, Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200), Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), Ingredient.qi_seasoning: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 10), - Ingredient.rice: self.money.can_spend_at(Region.pierre_store, 200) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), - Ingredient.sugar: self.money.can_spend_at(Region.pierre_store, 100) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.beet)), + Ingredient.rice: self.money.can_spend_at(Region.pierre_store, 200) | (self.building.has_building(Building.mill) & self.has(Vegetable.unmilled_rice)), + Ingredient.sugar: self.money.can_spend_at(Region.pierre_store, 100) | (self.building.has_building(Building.mill) & self.has(Vegetable.beet)), Ingredient.vinegar: self.money.can_spend_at(Region.pierre_store, 200), - Ingredient.wheat_flour: self.money.can_spend_at(Region.pierre_store, 100) | (self.buildings.has_building(Building.mill) & self.has(Vegetable.wheat)), + Ingredient.wheat_flour: self.money.can_spend_at(Region.pierre_store, 100) | (self.building.has_building(Building.mill) & self.has(Vegetable.wheat)), Loot.bat_wing: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), Loot.bug_meat: self.mine.can_mine_in_the_mines_floor_1_40(), Loot.slime: self.mine.can_mine_in_the_mines_floor_1_40(), Loot.solar_essence: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern(), Loot.void_essence: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern(), Machine.bee_house: self.skill.has_farming_level(3) & self.has(MetalBar.iron) & self.has(ArtisanGood.maple_syrup) & self.has(Material.coal) & self.has(Material.wood), - Machine.cask: self.buildings.has_house(3) & self.region.can_reach(Region.cellar) & self.has(Material.wood) & self.has(Material.hardwood), + Machine.cask: self.building.has_house(3) & self.region.can_reach(Region.cellar) & self.has(Material.wood) & self.has(Material.hardwood), Machine.cheese_press: self.skill.has_farming_level(6) & self.has(Material.wood) & self.has(Material.stone) & self.has(Material.hardwood) & self.has(MetalBar.copper), Machine.coffee_maker: self.received(Machine.coffee_maker), Machine.crab_pot: self.skill.has_level(Skill.fishing, 3) & (self.money.can_spend_at(Region.fish_shop, 1500) | (self.has(MetalBar.iron) & self.has(Material.wood))), @@ -438,8 +432,8 @@ def __init__(self, player: int, options: StardewValleyOptions): obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() self.item_rules[recipe] = obtention_rule | crafting_rule - self.buildings.initialize_rules() - self.buildings.update_rules(self.mod.buildings.get_modded_building_rules()) + self.building.initialize_rules() + self.building.update_rules(self.mod.buildings.get_modded_building_rules()) self.quest.initialize_rules() self.quest.update_rules(self.mod.quests.get_modded_quest_rules()) @@ -483,7 +477,7 @@ def __init__(self, player: int, options: StardewValleyOptions): }) self.special_order.initialize_rules() - self.special_order.update_rules(self.mod.special_orders.get_modded_special_orders_rules(self.special_order.special_order_rules)) + self.special_order.update_rules(self.mod.special_orders.get_modded_special_orders_rules(self.registry.special_order_rules)) def can_buy_sapling(self, fruit: str) -> StardewRule: sapling_prices = {Fruit.apple: 4000, Fruit.apricot: 2000, Fruit.cherry: 3400, Fruit.orange: 4000, @@ -544,7 +538,7 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: self.museum.can_complete_museum(), # Completing the museum for a point # Catching every fish not expected # Shipping every item not expected - self.relationship.can_get_married() & self.buildings.has_house(2), + self.relationship.can_get_married() & self.building.has_house(2), self.relationship.has_hearts("5", 8), # 5 Friends self.relationship.has_hearts("10", 8), # 10 friends self.pet.has_hearts(5), # Max Pet @@ -636,7 +630,7 @@ def can_buy_animal(self, animal: str) -> StardewRule: building = Building.deluxe_barn else: return True_() - return self.money.can_spend_at(Region.ranch, price) & self.buildings.has_building(building) + return self.money.can_spend_at(Region.ranch, price) & self.building.has_building(building) def has_animal(self, animal: str) -> StardewRule: if animal == Generic.any: diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index c5b6c496bdeb..223384fe97cc 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -1,22 +1,21 @@ -from typing import Dict +from typing import Dict, Union -from .action_logic import ActionLogicMixin +from .base_logic import BaseLogicMixin, BaseLogic from .building_logic import BuildingLogicMixin -from .combat_logic import CombatLogic -from .cooking_logic import CookingLogic -from .fishing_logic import FishingLogic +from .combat_logic import CombatLogicMixin +from .cooking_logic import CookingLogicMixin +from .fishing_logic import FishingLogicMixin from .has_logic import HasLogicMixin -from .mine_logic import MineLogic +from .mine_logic import MineLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin -from .skill_logic import SkillLogic +from .skill_logic import SkillLogicMixin from .time_logic import TimeLogicMixin -from .tool_logic import ToolLogic +from .tool_logic import ToolLogicMixin from .wallet_logic import WalletLogicMixin -from ..options import Mods from ..stardew_rule import StardewRule, Has, True_ from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building @@ -37,109 +36,78 @@ from ..strings.wallet_item_names import Wallet -class QuestLogic: - player: int - received: ReceivedLogicMixin - has: HasLogicMixin - mine: MineLogic - region: RegionLogicMixin - relationship: RelationshipLogicMixin - tool: ToolLogic - fishing: FishingLogic - cooking: CookingLogic - mods_option: Mods - money: MoneyLogicMixin - combat: CombatLogic - season: SeasonLogicMixin - skill: SkillLogic - wallet: WalletLogicMixin - quest_rules: Dict[str, StardewRule] +class QuestLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.quest = QuestLogic(*args, **kwargs) - def __init__(self, player: int, skill: SkillLogic, received: ReceivedLogicMixin, has: HasLogicMixin, mine: MineLogic, region: RegionLogicMixin, - action: ActionLogicMixin, - relationship: RelationshipLogicMixin, building: BuildingLogicMixin, time: TimeLogicMixin, tool: ToolLogic, fishing: FishingLogic, - cooking: CookingLogic, - money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, wallet: WalletLogicMixin, mods_option: Mods): - self.player = player - self.skill = skill - self.received = received - self.has = has - self.mine = mine - self.region = region - self.action = action - self.relationship = relationship - self.building = building - self.time = time - self.tool = tool - self.fishing = fishing - self.cooking = cooking - self.mods_option = mods_option - self.money = money - self.combat = combat - self.season = season - self.wallet = wallet - self.quest_rules = dict() + +class QuestLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, MoneyLogicMixin, MineLogicMixin, RegionLogicMixin, RelationshipLogicMixin, ToolLogicMixin, +FishingLogicMixin, CookingLogicMixin, CombatLogicMixin, SeasonLogicMixin, SkillLogicMixin, WalletLogicMixin, QuestLogicMixin, BuildingLogicMixin, TimeLogicMixin]]): def initialize_rules(self): - self.quest_rules.update({ + self.update_rules({ Quest.introductions: True_(), - Quest.how_to_win_friends: self.can_complete_quest(Quest.introductions), - Quest.getting_started: self.has(Vegetable.parsnip), - Quest.to_the_beach: self.region.can_reach(Region.beach), - Quest.raising_animals: self.can_complete_quest(Quest.getting_started) & self.building.has_building(Building.coop), - Quest.advancement: self.can_complete_quest(Quest.getting_started) & self.has(Craftable.scarecrow), - Quest.archaeology: self.tool.has_tool(Tool.hoe) | self.mine.can_mine_in_the_mines_floor_1_40() | self.skill.can_fish(), - Quest.rat_problem: self.region.can_reach_all((Region.town, Region.community_center)), - Quest.meet_the_wizard: self.can_complete_quest(Quest.rat_problem), - Quest.forging_ahead: self.has(Ore.copper) & self.has(Machine.furnace), - Quest.smelting: self.has(MetalBar.copper), - Quest.initiation: self.mine.can_mine_in_the_mines_floor_1_40(), - Quest.robins_lost_axe: self.season.has(Season.spring) & self.relationship.can_meet(NPC.robin), - Quest.jodis_request: self.season.has(Season.spring) & self.has(Vegetable.cauliflower) & self.relationship.can_meet(NPC.jodi), - Quest.mayors_shorts: self.season.has(Season.summer) & self.relationship.has_hearts(NPC.marnie, 2) & self.relationship.can_meet(NPC.lewis), - Quest.blackberry_basket: self.season.has(Season.fall) & self.relationship.can_meet(NPC.linus), - Quest.marnies_request: self.relationship.has_hearts(NPC.marnie, 3) & self.has(Forageable.cave_carrot), - Quest.pam_is_thirsty: self.season.has(Season.summer) & self.has(ArtisanGood.pale_ale) & self.relationship.can_meet(NPC.pam), - Quest.a_dark_reagent: self.season.has(Season.winter) & self.has(Loot.void_essence) & self.relationship.can_meet(NPC.wizard), - Quest.cows_delight: self.season.has(Season.fall) & self.has(Vegetable.amaranth) & self.relationship.can_meet(NPC.marnie), - Quest.the_skull_key: self.received(Wallet.skull_key), - Quest.crop_research: self.season.has(Season.summer) & self.has(Fruit.melon) & self.relationship.can_meet(NPC.demetrius), - Quest.knee_therapy: self.season.has(Season.summer) & self.has(Fruit.hot_pepper) & self.relationship.can_meet(NPC.george), - Quest.robins_request: self.season.has(Season.winter) & self.has(Material.hardwood) & self.relationship.can_meet(NPC.robin), + Quest.how_to_win_friends: self.logic.quest.can_complete_quest(Quest.introductions), + Quest.getting_started: self.logic.has(Vegetable.parsnip), + Quest.to_the_beach: self.logic.region.can_reach(Region.beach), + Quest.raising_animals: self.logic.quest.can_complete_quest(Quest.getting_started) & self.logic.building.has_building(Building.coop), + Quest.advancement: self.logic.quest.can_complete_quest(Quest.getting_started) & self.logic.has(Craftable.scarecrow), + Quest.archaeology: self.logic.tool.has_tool(Tool.hoe) | self.logic.mine.can_mine_in_the_mines_floor_1_40() | self.logic.skill.can_fish(), + Quest.rat_problem: self.logic.region.can_reach_all((Region.town, Region.community_center)), + Quest.meet_the_wizard: self.logic.quest.can_complete_quest(Quest.rat_problem), + Quest.forging_ahead: self.logic.has(Ore.copper) & self.logic.has(Machine.furnace), + Quest.smelting: self.logic.has(MetalBar.copper), + Quest.initiation: self.logic.mine.can_mine_in_the_mines_floor_1_40(), + Quest.robins_lost_axe: self.logic.season.has(Season.spring) & self.logic.relationship.can_meet(NPC.robin), + Quest.jodis_request: self.logic.season.has(Season.spring) & self.logic.has(Vegetable.cauliflower) & self.logic.relationship.can_meet(NPC.jodi), + Quest.mayors_shorts: self.logic.season.has(Season.summer) & self.logic.relationship.has_hearts(NPC.marnie, 2) & + self.logic.relationship.can_meet(NPC.lewis), + Quest.blackberry_basket: self.logic.season.has(Season.fall) & self.logic.relationship.can_meet(NPC.linus), + Quest.marnies_request: self.logic.relationship.has_hearts(NPC.marnie, 3) & self.logic.has(Forageable.cave_carrot), + Quest.pam_is_thirsty: self.logic.season.has(Season.summer) & self.logic.has(ArtisanGood.pale_ale) & self.logic.relationship.can_meet(NPC.pam), + Quest.a_dark_reagent: self.logic.season.has(Season.winter) & self.logic.has(Loot.void_essence) & self.logic.relationship.can_meet(NPC.wizard), + Quest.cows_delight: self.logic.season.has(Season.fall) & self.logic.has(Vegetable.amaranth) & self.logic.relationship.can_meet(NPC.marnie), + Quest.the_skull_key: self.logic.received(Wallet.skull_key), + Quest.crop_research: self.logic.season.has(Season.summer) & self.logic.has(Fruit.melon) & self.logic.relationship.can_meet(NPC.demetrius), + Quest.knee_therapy: self.logic.season.has(Season.summer) & self.logic.has(Fruit.hot_pepper) & self.logic.relationship.can_meet(NPC.george), + Quest.robins_request: self.logic.season.has(Season.winter) & self.logic.has(Material.hardwood) & self.logic.relationship.can_meet(NPC.robin), Quest.qis_challenge: True_(), # The skull cavern floor 25 already has rules - Quest.the_mysterious_qi: self.region.can_reach_all((Region.bus_tunnel, Region.railroad, Region.mayor_house)) & - self.has(ArtisanGood.battery_pack) & self.has(Forageable.rainbow_shell) & - self.has(Vegetable.beet) & self.has(Loot.solar_essence), - Quest.carving_pumpkins: self.season.has(Season.fall) & self.has(Vegetable.pumpkin) & self.relationship.can_meet(NPC.caroline), - Quest.a_winter_mystery: self.season.has(Season.winter), - Quest.strange_note: self.has(Forageable.secret_note) & self.has(ArtisanGood.maple_syrup), - Quest.cryptic_note: self.has(Forageable.secret_note), - Quest.fresh_fruit: self.season.has(Season.spring) & self.has(Fruit.apricot) & self.relationship.can_meet(NPC.emily), - Quest.aquatic_research: self.season.has(Season.summer) & self.has(Fish.pufferfish) & self.relationship.can_meet(NPC.demetrius), - Quest.a_soldiers_star: self.season.has(Season.summer) & self.time.has_year_two & self.has(Fruit.starfruit) & self.relationship.can_meet(NPC.kent), - Quest.mayors_need: self.season.has(Season.summer) & self.has(ArtisanGood.truffle_oil) & self.relationship.can_meet(NPC.lewis), - Quest.wanted_lobster: self.season.has(Season.fall) & self.season.has(Season.fall) & self.has(Fish.lobster) & self.relationship.can_meet(NPC.gus), - Quest.pam_needs_juice: self.season.has(Season.fall) & self.has(ArtisanGood.battery_pack) & self.relationship.can_meet(NPC.pam), - Quest.fish_casserole: self.relationship.has_hearts(NPC.jodi, 4) & self.has(Fish.largemouth_bass), - Quest.catch_a_squid: self.season.has(Season.winter) & self.has(Fish.squid) & self.relationship.can_meet(NPC.willy), - Quest.fish_stew: self.season.has(Season.winter) & self.has(Fish.albacore) & self.relationship.can_meet(NPC.gus), - Quest.pierres_notice: self.season.has(Season.spring) & self.has(Meal.sashimi) & self.relationship.can_meet(NPC.pierre), - Quest.clints_attempt: self.season.has(Season.winter) & self.has(Mineral.amethyst) & self.relationship.can_meet(NPC.emily), - Quest.a_favor_for_clint: self.season.has(Season.winter) & self.has(MetalBar.iron) & self.relationship.can_meet(NPC.clint), - Quest.staff_of_power: self.season.has(Season.winter) & self.has(MetalBar.iridium) & self.relationship.can_meet(NPC.wizard), - Quest.grannys_gift: self.season.has(Season.spring) & self.has(Forageable.leek) & self.relationship.can_meet(NPC.evelyn), - Quest.exotic_spirits: self.season.has(Season.winter) & self.has(Forageable.coconut) & self.relationship.can_meet(NPC.gus), - Quest.catch_a_lingcod: self.season.has(Season.winter) & self.has(Fish.lingcod) & self.relationship.can_meet(NPC.willy), - Quest.dark_talisman: self.region.can_reach(Region.railroad) & self.wallet.has_rusty_key & self.relationship.can_meet(NPC.krobus), - Quest.goblin_problem: self.region.can_reach(Region.witch_swamp), - Quest.magic_ink: self.relationship.can_meet(NPC.wizard), - Quest.the_pirates_wife: self.relationship.can_meet(NPC.kent) & self.relationship.can_meet(NPC.gus) & - self.relationship.can_meet(NPC.sandy) & self.relationship.can_meet(NPC.george) & - self.relationship.can_meet(NPC.wizard) & self.relationship.can_meet(NPC.willy), + Quest.the_mysterious_qi: self.logic.region.can_reach_all((Region.bus_tunnel, Region.railroad, Region.mayor_house)) & + self.logic.has(ArtisanGood.battery_pack) & self.logic.has(Forageable.rainbow_shell) & + self.logic.has(Vegetable.beet) & self.logic.has(Loot.solar_essence), + Quest.carving_pumpkins: self.logic.season.has(Season.fall) & self.logic.has(Vegetable.pumpkin) & self.logic.relationship.can_meet(NPC.caroline), + Quest.a_winter_mystery: self.logic.season.has(Season.winter), + Quest.strange_note: self.logic.has(Forageable.secret_note) & self.logic.has(ArtisanGood.maple_syrup), + Quest.cryptic_note: self.logic.has(Forageable.secret_note), + Quest.fresh_fruit: self.logic.season.has(Season.spring) & self.logic.has(Fruit.apricot) & self.logic.relationship.can_meet(NPC.emily), + Quest.aquatic_research: self.logic.season.has(Season.summer) & self.logic.has(Fish.pufferfish) & self.logic.relationship.can_meet(NPC.demetrius), + Quest.a_soldiers_star: self.logic.season.has(Season.summer) & self.logic.time.has_year_two & self.logic.has(Fruit.starfruit) & + self.logic.relationship.can_meet(NPC.kent), + Quest.mayors_need: self.logic.season.has(Season.summer) & self.logic.has(ArtisanGood.truffle_oil) & self.logic.relationship.can_meet(NPC.lewis), + Quest.wanted_lobster: self.logic.season.has(Season.fall) & self.logic.season.has(Season.fall) & self.logic.has(Fish.lobster) & + self.logic.relationship.can_meet(NPC.gus), + Quest.pam_needs_juice: self.logic.season.has(Season.fall) & self.logic.has(ArtisanGood.battery_pack) & self.logic.relationship.can_meet(NPC.pam), + Quest.fish_casserole: self.logic.relationship.has_hearts(NPC.jodi, 4) & self.logic.has(Fish.largemouth_bass), + Quest.catch_a_squid: self.logic.season.has(Season.winter) & self.logic.has(Fish.squid) & self.logic.relationship.can_meet(NPC.willy), + Quest.fish_stew: self.logic.season.has(Season.winter) & self.logic.has(Fish.albacore) & self.logic.relationship.can_meet(NPC.gus), + Quest.pierres_notice: self.logic.season.has(Season.spring) & self.logic.has(Meal.sashimi) & self.logic.relationship.can_meet(NPC.pierre), + Quest.clints_attempt: self.logic.season.has(Season.winter) & self.logic.has(Mineral.amethyst) & self.logic.relationship.can_meet(NPC.emily), + Quest.a_favor_for_clint: self.logic.season.has(Season.winter) & self.logic.has(MetalBar.iron) & self.logic.relationship.can_meet(NPC.clint), + Quest.staff_of_power: self.logic.season.has(Season.winter) & self.logic.has(MetalBar.iridium) & self.logic.relationship.can_meet(NPC.wizard), + Quest.grannys_gift: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek) & self.logic.relationship.can_meet(NPC.evelyn), + Quest.exotic_spirits: self.logic.season.has(Season.winter) & self.logic.has(Forageable.coconut) & self.logic.relationship.can_meet(NPC.gus), + Quest.catch_a_lingcod: self.logic.season.has(Season.winter) & self.logic.has(Fish.lingcod) & self.logic.relationship.can_meet(NPC.willy), + Quest.dark_talisman: self.logic.region.can_reach(Region.railroad) & self.logic.wallet.has_rusty_key & self.logic.relationship.can_meet(NPC.krobus), + Quest.goblin_problem: self.logic.region.can_reach(Region.witch_swamp), + Quest.magic_ink: self.logic.relationship.can_meet(NPC.wizard), + Quest.the_pirates_wife: self.logic.relationship.can_meet(NPC.kent) & self.logic.relationship.can_meet(NPC.gus) & + self.logic.relationship.can_meet(NPC.sandy) & self.logic.relationship.can_meet(NPC.george) & + self.logic.relationship.can_meet(NPC.wizard) & self.logic.relationship.can_meet(NPC.willy), }) def update_rules(self, new_rules: Dict[str, StardewRule]): - self.quest_rules.update(new_rules) + self.registry.quest_rules.update(new_rules) def can_complete_quest(self, quest: str) -> StardewRule: - return Has(quest, self.quest_rules) + return Has(quest, self.registry.quest_rules) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 0021efc0feb3..7f60ea914505 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -44,12 +44,12 @@ def has_children(self, number_children: int) -> StardewRule: return True_() if self.options.friendsanity == Friendsanity.option_none: return self.logic.relationship.can_reproduce(number_children) - return self.logic.received(possible_kids, number_children) & self.logic.buildings.has_house(2) + return self.logic.received(possible_kids, number_children) & self.logic.building.has_house(2) def can_reproduce(self, number_children: int = 1) -> StardewRule: if number_children <= 0: return True_() - baby_rules = [self.logic.relationship.can_get_married(), self.logic.buildings.has_house(2), self.logic.relationship.has_hearts(Generic.bachelor, 12), + baby_rules = [self.logic.relationship.can_get_married(), self.logic.building.has_house(2), self.logic.relationship.has_hearts(Generic.bachelor, 12), self.logic.relationship.has_children(number_children - 1)] return And(*baby_rules) diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index d293738c4504..6b5fbb1bbd96 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -24,7 +24,7 @@ class ShippingLogic(BaseLogic[Union[ShippingLogicMixin, BuildingLogicMixin, Regi @cached_property def can_use_shipping_bin(self) -> StardewRule: - return self.logic.buildings.has_building(Building.shipping_bin) + return self.logic.building.has_building(Building.shipping_bin) @cache_self1 def can_ship(self, item: str) -> StardewRule: @@ -48,4 +48,4 @@ def can_ship_everything(self) -> StardewRule: if location.mod_name and location.mod_name not in mod_list: continue all_items_to_ship.append(location.name[len(shipsanity_prefix):]) - return self.logic.buildings.has_building(Building.shipping_bin) & And(*(self.logic.has(item) for item in all_items_to_ship)) + return self.logic.building.has_building(Building.shipping_bin) & And(*(self.logic.has(item) for item in all_items_to_ship)) diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 504cafce8ef0..8ad27f9997fc 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -1,20 +1,21 @@ -from typing import Dict +from typing import Dict, Union -from .ability_logic import AbilityLogic +from .ability_logic import AbilityLogicMixin from .arcade_logic import ArcadeLogicMixin from .artisan_logic import ArtisanLogicMixin -from .cooking_logic import CookingLogic +from .base_logic import BaseLogicMixin, BaseLogic +from .cooking_logic import CookingLogicMixin from .has_logic import HasLogicMixin -from .mine_logic import MineLogic +from .mine_logic import MineLogicMixin from .money_logic import MoneyLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .shipping_logic import ShippingLogicMixin -from .skill_logic import SkillLogic +from .skill_logic import SkillLogicMixin from .time_logic import TimeLogicMixin -from .tool_logic import ToolLogic +from .tool_logic import ToolLogicMixin from ..stardew_rule import StardewRule, Has from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.transport_names import Transportation @@ -34,101 +35,72 @@ from ..strings.villager_names import NPC -class SpecialOrderLogic: - player: int - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - season: SeasonLogicMixin - time: TimeLogicMixin - money: MoneyLogicMixin - shipping: ShippingLogicMixin - arcade: ArcadeLogicMixin - artisan: ArtisanLogicMixin - relationship: RelationshipLogicMixin - tool: ToolLogic - skill: SkillLogic - mine: MineLogic - cooking: CookingLogic - ability: AbilityLogic - special_order_rules: Dict[str, StardewRule] +class SpecialOrderLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.special_order = SpecialOrderLogic(*args, **kwargs) - def __init__(self, player: int, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, season: SeasonLogicMixin, time: TimeLogicMixin, - money: MoneyLogicMixin, - shipping: ShippingLogicMixin, arcade: ArcadeLogicMixin, artisan: ArtisanLogicMixin, relationship: RelationshipLogicMixin, tool: ToolLogic, - skill: SkillLogic, - mine: MineLogic, cooking: CookingLogic, ability: AbilityLogic): - self.player = player - self.received = received - self.has = has - self.region = region - self.season = season - self.time = time - self.money = money - self.shipping = shipping - self.arcade = arcade - self.artisan = artisan - self.relationship = relationship - self.tool = tool - self.skill = skill - self.mine = mine - self.cooking = cooking - self.ability = ability - self.special_order_rules = dict() + +class SpecialOrderLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, MoneyLogicMixin, +ShippingLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, RelationshipLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, CookingLogicMixin, +AbilityLogicMixin, SpecialOrderLogicMixin]]): def initialize_rules(self): - self.special_order_rules.update({ - SpecialOrder.island_ingredients: self.relationship.can_meet(NPC.caroline) & self.has_island_transport() & self.ability.can_farm_perfectly() & - self.shipping.can_ship(Vegetable.taro_root) & self.shipping.can_ship(Fruit.pineapple) & self.shipping.can_ship( - Forageable.ginger), - SpecialOrder.cave_patrol: self.relationship.can_meet(NPC.clint), - SpecialOrder.aquatic_overpopulation: self.relationship.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), - SpecialOrder.biome_balance: self.relationship.can_meet(NPC.demetrius) & self.ability.can_fish_perfectly(), - SpecialOrder.rock_rejuivenation: self.relationship.has_hearts(NPC.emily, 4) & self.has(Mineral.ruby) & self.has(Mineral.topaz) & - self.has(Mineral.emerald) & self.has(Mineral.jade) & self.has(Mineral.amethyst) & self.has(ArtisanGood.cloth), - SpecialOrder.gifts_for_george: self.season.has(Season.spring) & self.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), - SpecialOrder.gus_famous_omelet: self.has(AnimalProduct.any_egg), - SpecialOrder.crop_order: self.ability.can_farm_perfectly() & self.shipping.can_ship_items, - SpecialOrder.community_cleanup: self.skill.can_crab_pot, - SpecialOrder.the_strong_stuff: self.artisan.can_keg(Vegetable.potato), - SpecialOrder.pierres_prime_produce: self.ability.can_farm_perfectly(), - SpecialOrder.robins_project: self.relationship.can_meet(NPC.robin) & self.ability.can_chop_perfectly() & self.has(Material.hardwood), - SpecialOrder.robins_resource_rush: self.relationship.can_meet(NPC.robin) & self.ability.can_chop_perfectly() & - self.has(Fertilizer.tree) & self.ability.can_mine_perfectly(), - SpecialOrder.juicy_bugs_wanted: self.has(Loot.bug_meat), - SpecialOrder.tropical_fish: self.relationship.can_meet(NPC.willy) & self.received("Island Resort") & self.has_island_transport() & - self.has(Fish.stingray) & self.has(Fish.blue_discus) & self.has(Fish.lionfish), - SpecialOrder.a_curious_substance: self.region.can_reach(Region.wizard_tower), - SpecialOrder.prismatic_jelly: self.region.can_reach(Region.wizard_tower), - SpecialOrder.qis_crop: self.ability.can_farm_perfectly() & self.region.can_reach(Region.greenhouse) & - self.region.can_reach(Region.island_west) & self.skill.has_total_level(50) & - self.has(Machine.seed_maker) & self.shipping.can_ship_items, - SpecialOrder.lets_play_a_game: self.arcade.has_junimo_kart_max_level(), - SpecialOrder.four_precious_stones: self.time.has_lived_max_months & self.has("Prismatic Shard") & - self.ability.can_mine_perfectly_in_the_skull_cavern(), - SpecialOrder.qis_hungry_challenge: self.ability.can_mine_perfectly_in_the_skull_cavern() & self.ability.has_max_buffs(), - SpecialOrder.qis_cuisine: self.cooking.can_cook() & self.shipping.can_ship_items & - (self.money.can_spend_at(Region.saloon, 205000) | self.money.can_spend_at(Region.pierre_store, 170000)), - SpecialOrder.qis_kindness: self.relationship.can_give_loved_gifts_to_everyone(), - SpecialOrder.extended_family: self.ability.can_fish_perfectly() & self.has(Fish.angler) & self.has(Fish.glacierfish) & - self.has(Fish.crimsonfish) & self.has(Fish.mutant_carp) & self.has(Fish.legend), - SpecialOrder.danger_in_the_deep: self.ability.can_mine_perfectly() & self.mine.has_mine_elevator_to_floor(120), - SpecialOrder.skull_cavern_invasion: self.ability.can_mine_perfectly_in_the_skull_cavern() & self.ability.has_max_buffs(), - SpecialOrder.qis_prismatic_grange: self.has(Loot.bug_meat) & # 100 Bug Meat - self.money.can_spend_at(Region.saloon, 24000) & # 100 Spaghetti - self.money.can_spend_at(Region.blacksmith, 15000) & # 100 Copper Ore - self.money.can_spend_at(Region.ranch, 5000) & # 100 Hay - self.money.can_spend_at(Region.saloon, 22000) & # 100 Salads - self.money.can_spend_at(Region.saloon, 7500) & # 100 Joja Cola - self.money.can_spend(80000), # I need this extra rule because money rules aren't additive... + self.update_rules({ + SpecialOrder.island_ingredients: self.logic.relationship.can_meet(NPC.caroline) & self.logic.special_order.has_island_transport() & + self.logic.ability.can_farm_perfectly() & self.logic.shipping.can_ship(Vegetable.taro_root) & + self.logic.shipping.can_ship(Fruit.pineapple) & self.logic.shipping.can_ship(Forageable.ginger), + SpecialOrder.cave_patrol: self.logic.relationship.can_meet(NPC.clint), + SpecialOrder.aquatic_overpopulation: self.logic.relationship.can_meet(NPC.demetrius) & self.logic.ability.can_fish_perfectly(), + SpecialOrder.biome_balance: self.logic.relationship.can_meet(NPC.demetrius) & self.logic.ability.can_fish_perfectly(), + SpecialOrder.rock_rejuivenation: self.logic.relationship.has_hearts(NPC.emily, 4) & self.logic.has(Mineral.ruby) & self.logic.has(Mineral.topaz) & + self.logic.has(Mineral.emerald) & self.logic.has(Mineral.jade) & self.logic.has(Mineral.amethyst) & + self.logic.has(ArtisanGood.cloth), + SpecialOrder.gifts_for_george: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek), + SpecialOrder.fragments_of_the_past: self.logic.region.can_reach(Region.dig_site) & self.logic.tool.has_tool(Tool.pickaxe), + SpecialOrder.gus_famous_omelet: self.logic.has(AnimalProduct.any_egg), + SpecialOrder.crop_order: self.logic.ability.can_farm_perfectly() & self.logic.shipping.can_ship_items, + SpecialOrder.community_cleanup: self.logic.skill.can_crab_pot, + SpecialOrder.the_strong_stuff: self.logic.artisan.can_keg(Vegetable.potato), + SpecialOrder.pierres_prime_produce: self.logic.ability.can_farm_perfectly(), + SpecialOrder.robins_project: self.logic.relationship.can_meet(NPC.robin) & self.logic.ability.can_chop_perfectly() & + self.logic.has(Material.hardwood), + SpecialOrder.robins_resource_rush: self.logic.relationship.can_meet(NPC.robin) & self.logic.ability.can_chop_perfectly() & + self.logic.has(Fertilizer.tree) & self.logic.ability.can_mine_perfectly(), + SpecialOrder.juicy_bugs_wanted: self.logic.has(Loot.bug_meat), + SpecialOrder.tropical_fish: self.logic.relationship.can_meet(NPC.willy) & self.logic.received("Island Resort") & + self.logic.special_order.has_island_transport() & + self.logic.has(Fish.stingray) & self.logic.has(Fish.blue_discus) & self.logic.has(Fish.lionfish), + SpecialOrder.a_curious_substance: self.logic.region.can_reach(Region.wizard_tower), + SpecialOrder.prismatic_jelly: self.logic.region.can_reach(Region.wizard_tower), + SpecialOrder.qis_crop: self.logic.ability.can_farm_perfectly() & self.logic.region.can_reach(Region.greenhouse) & + self.logic.region.can_reach(Region.island_west) & self.logic.skill.has_total_level(50) & + self.logic.has(Machine.seed_maker) & self.logic.shipping.can_ship_items, + SpecialOrder.lets_play_a_game: self.logic.arcade.has_junimo_kart_max_level(), + SpecialOrder.four_precious_stones: self.logic.time.has_lived_max_months & self.logic.has("Prismatic Shard") & + self.logic.ability.can_mine_perfectly_in_the_skull_cavern(), + SpecialOrder.qis_hungry_challenge: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.ability.has_max_buffs(), + SpecialOrder.qis_cuisine: self.logic.cooking.can_cook() & self.logic.shipping.can_ship_items & + (self.logic.money.can_spend_at(Region.saloon, 205000) | self.logic.money.can_spend_at(Region.pierre_store, 170000)), + SpecialOrder.qis_kindness: self.logic.relationship.can_give_loved_gifts_to_everyone(), + SpecialOrder.extended_family: self.logic.ability.can_fish_perfectly() & self.logic.has(Fish.angler) & self.logic.has(Fish.glacierfish) & + self.logic.has(Fish.crimsonfish) & self.logic.has(Fish.mutant_carp) & self.logic.has(Fish.legend), + SpecialOrder.danger_in_the_deep: self.logic.ability.can_mine_perfectly() & self.logic.mine.has_mine_elevator_to_floor(120), + SpecialOrder.skull_cavern_invasion: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.ability.has_max_buffs(), + SpecialOrder.qis_prismatic_grange: self.logic.has(Loot.bug_meat) & # 100 Bug Meat + self.logic.money.can_spend_at(Region.saloon, 24000) & # 100 Spaghetti + self.logic.money.can_spend_at(Region.blacksmith, 15000) & # 100 Copper Ore + self.logic.money.can_spend_at(Region.ranch, 5000) & # 100 Hay + self.logic.money.can_spend_at(Region.saloon, 22000) & # 100 Salads + self.logic.money.can_spend_at(Region.saloon, 7500) & # 100 Joja Cola + self.logic.money.can_spend(80000), # I need this extra rule because money rules aren't additive... }) def update_rules(self, new_rules: Dict[str, StardewRule]): - self.special_order_rules.update(new_rules) + self.registry.special_order_rules.update(new_rules) def can_complete_special_order(self, special_order: str) -> StardewRule: - return Has(special_order, self.special_order_rules) + return Has(special_order, self.registry.special_order_rules) def has_island_transport(self) -> StardewRule: - return self.received(Transportation.island_obelisk) | self.received(Transportation.boat_repair) + return self.logic.received(Transportation.island_obelisk) | self.logic.received(Transportation.boat_repair) diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index 48b7185367a1..cb405fc6148d 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -44,5 +44,5 @@ def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_o self.special_orders = ModSpecialOrderLogic(player, logic.action, logic.artisan, crafting, logic.crop, logic.has, logic.region, logic.relationship, logic.season, logic.wallet, mods) self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, logic.received, logic.has, logic.combat, logic.tool, skill, cooking) - self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.buildings, logic.tool, + self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.building, logic.tool, fishing, cooking, logic.money, logic.combat, logic.season, logic.time) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 6d08dc522417..13c3f8633c32 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -88,7 +88,7 @@ def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: def can_earn_cooking_skill_level(self, level: int) -> StardewRule: if level >= 6: return self.logic.cooking.can_cook() & self.logic.region.can_reach(Region.saloon) & \ - self.logic.buildings.has_building(Building.coop) & self.logic.buildings.has_building(Building.barn) + self.logic.building.has_building(Building.coop) & self.logic.building.has_building(Building.barn) else: return self.logic.cooking.can_cook() diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 831d8952b199..3a4c51cad4e5 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -268,10 +268,10 @@ def set_farm_buildings_entrance_rules(logic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_coop, player), logic.buildings.has_building(Building.coop)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_barn, player), logic.buildings.has_building(Building.barn)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_shed, player), logic.buildings.has_building(Building.shed)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_slime_hutch, player), logic.buildings.has_building(Building.slime_hutch)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_coop, player), logic.building.has_building(Building.coop)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_barn, player), logic.building.has_building(Building.barn)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_shed, player), logic.building.has_building(Building.shed)) + MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_slime_hutch, player), logic.building.has_building(Building.slime_hutch)) def set_bedroom_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): @@ -463,7 +463,7 @@ def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, m for quest in locations.locations_by_tag[LocationTags.QUEST]: if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options.mods): MultiWorldRules.set_rule(multiworld.get_location(quest.name, player), - logic.quest.quest_rules[quest.name]) + logic.registry.quest_rules[quest.name]) def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, @@ -473,7 +473,7 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, board_rule = logic.received("Special Order Board") & logic.time.has_lived_months(4) for board_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD]: if board_order.name in all_location_names: - order_rule = board_rule & logic.special_order.special_order_rules[board_order.name] + order_rule = board_rule & logic.registry.special_order_rules[board_order.name] MultiWorldRules.set_rule(multiworld.get_location(board_order.name, player), order_rule) if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: @@ -483,7 +483,7 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, qi_rule = logic.region.can_reach(Region.qi_walnut_room) & logic.time.has_lived_months(8) for qi_order in locations.locations_by_tag[LocationTags.SPECIAL_ORDER_QI]: if qi_order.name in all_location_names: - order_rule = qi_rule & logic.special_order.special_order_rules[qi_order.name] + order_rule = qi_rule & logic.registry.special_order_rules[qi_order.name] MultiWorldRules.set_rule(multiworld.get_location(qi_order.name, player), order_rule) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index e99b9c026958..1fd5e48bd119 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -38,16 +38,16 @@ def test_given_building_rule_then_can_be_resolved(self): self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve building rule for {building} {rule}") def test_given_quest_rule_then_can_be_resolved(self): - for quest in logic.quest.quest_rules.keys(): + for quest in logic.registry.quest_rules.keys(): with self.subTest(msg=quest): - rule = logic.quest.quest_rules[quest] + rule = logic.registry.quest_rules[quest] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve quest rule for {quest} {rule}") def test_given_special_order_rule_then_can_be_resolved(self): - for special_order in logic.special_order.special_order_rules.keys(): + for special_order in logic.registry.special_order_rules.keys(): with self.subTest(msg=special_order): - rule = logic.special_order.special_order_rules[special_order] + rule = logic.registry.special_order_rules[special_order] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve special order rule for {special_order} {rule}") From 9a58671df2f718fda35d26049959aea249f48778 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 21 Nov 2023 01:09:28 -0500 Subject: [PATCH 198/482] finish mod logic rewrite, put everything in registry --- worlds/stardew_valley/bundles.py | 4 +- worlds/stardew_valley/logic/base_logic.py | 2 + worlds/stardew_valley/logic/logic.py | 104 +++++------ .../mods/logic/buildings_logic.py | 14 +- .../mods/logic/deepwoods_logic.py | 58 +++---- .../stardew_valley/mods/logic/item_logic.py | 161 ++++++++---------- worlds/stardew_valley/mods/logic/mod_logic.py | 49 ++---- .../stardew_valley/mods/logic/quests_logic.py | 62 +++---- .../mods/logic/special_orders_logic.py | 83 ++++----- worlds/stardew_valley/mods/logic/sve_logic.py | 85 +++------ worlds/stardew_valley/rules.py | 6 +- worlds/stardew_valley/test/TestLogic.py | 30 ++-- 12 files changed, 260 insertions(+), 398 deletions(-) diff --git a/worlds/stardew_valley/bundles.py b/worlds/stardew_valley/bundles.py index d8eca75f5832..b2ff503f6e1d 100644 --- a/worlds/stardew_valley/bundles.py +++ b/worlds/stardew_valley/bundles.py @@ -1,8 +1,8 @@ from random import Random from typing import List, Dict, Union -from .logic.logic import StardewLogic from .data.bundle_data import * +from .logic.logic import StardewLogic from .options import BundleRandomization, BundlePrice vanilla_bundles = { @@ -188,7 +188,7 @@ def shuffle_bundles_completely(random: Random, logic: StardewLogic, bundles: Dic random.sample(quality_crops_items, 10) choices = random.sample(all_bundle_items_without_quality_and_money, total_required_item_number - 4) - items_sorted = sorted(choices, key=lambda x: logic.item_rules[x.item.name].get_difficulty()) + items_sorted = sorted(choices, key=lambda x: logic.registry.item_rules[x.item.name].get_difficulty()) keys = sorted(bundles.keys()) random.shuffle(keys) diff --git a/worlds/stardew_valley/logic/base_logic.py b/worlds/stardew_valley/logic/base_logic.py index ea4f90798418..2ff35f08e7d1 100644 --- a/worlds/stardew_valley/logic/base_logic.py +++ b/worlds/stardew_valley/logic/base_logic.py @@ -23,6 +23,8 @@ def __init__(self): self.building_rules: Dict[str, StardewRule] = {} self.special_order_rules: Dict[str, StardewRule] = {} + self.sve_location_rules: Dict[str, StardewRule] = {} + class BaseLogicMixin: def __init__(self, *args, **kwargs): diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 3d13c3ee62ad..76ed7686b1e7 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -43,7 +43,7 @@ from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..mods.logic.magic_logic import MagicLogicMixin -from ..mods.logic.mod_logic import ModLogic +from ..mods.logic.mod_logic import ModLogicMixin from ..mods.mod_data import ModNames from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity, StardewValleyOptions from ..stardew_rule import False_, Or, True_, Count, And, StardewRule @@ -91,7 +91,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin, - SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin): + SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin): player: int options: StardewValleyOptions @@ -99,50 +99,26 @@ def __init__(self, player: int, options: StardewValleyOptions): self.registry = LogicRegistry() super().__init__(player, self.registry, options, self) - self.item_rules = self.registry.item_rules - self.sapling_rules = self.registry.sapling_rules - self.tree_fruit_rules = self.registry.tree_fruit_rules - self.seed_rules = self.registry.seed_rules - self.cooking_rules = self.registry.cooking_rules - self.crafting_rules = self.registry.crafting_rules - self.crop_rules = self.registry.crop_rules - self.fish_rules = self.registry.fish_rules - self.museum_rules = self.registry.museum_rules - self.festival_rules = self.registry.festival_rules - self.quest_rules = self.registry.quest_rules - self.building_rules = self.registry.building_rules - - tool_option = self.options.tool_progression - skill_option = self.options.skill_progression - elevator_option = self.options.elevator_progression - friendsanity_option = self.options.friendsanity - heart_size_option = self.options.friendsanity_heart_size - special_order_locations = self.options.special_order_locations - mods_option = self.options.mods - exclude_ginger_island = self.options.exclude_ginger_island - self.mod = ModLogic(self.player, self.registry, self.options, self, skill_option, elevator_option, mods_option, self.skill, - self.fishing, self.cooking, self.mine, self.ability, self.quest, self.crafting) - - self.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) - self.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) + self.registry.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) + self.registry.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) for recipe in all_cooking_recipes: - if recipe.mod_name and recipe.mod_name not in mods_option: + if recipe.mod_name and recipe.mod_name not in self.options.mods: continue can_cook_rule = self.cooking.can_cook(recipe) - if recipe.meal in self.cooking_rules: - can_cook_rule = can_cook_rule | self.cooking_rules[recipe.meal] - self.cooking_rules[recipe.meal] = can_cook_rule + if recipe.meal in self.registry.cooking_rules: + can_cook_rule = can_cook_rule | self.registry.cooking_rules[recipe.meal] + self.registry.cooking_rules[recipe.meal] = can_cook_rule for recipe in all_crafting_recipes: - if recipe.mod_name and recipe.mod_name not in mods_option: + if recipe.mod_name and recipe.mod_name not in self.options.mods: continue can_craft_rule = self.crafting.can_craft(recipe) - if recipe.item in self.crafting_rules: - can_craft_rule = can_craft_rule | self.crafting_rules[recipe.item] - self.crafting_rules[recipe.item] = can_craft_rule + if recipe.item in self.registry.crafting_rules: + can_craft_rule = can_craft_rule | self.registry.crafting_rules[recipe.item] + self.registry.crafting_rules[recipe.item] = can_craft_rule - self.sapling_rules.update({ + self.registry.sapling_rules.update({ Sapling.apple: self.can_buy_sapling(Fruit.apple), Sapling.apricot: self.can_buy_sapling(Fruit.apricot), Sapling.cherry: self.can_buy_sapling(Fruit.cherry), @@ -153,7 +129,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Sapling.mango: self.can_buy_sapling(Fruit.mango), }) - self.tree_fruit_rules.update({ + self.registry.tree_fruit_rules.update({ Fruit.apple: self.crop.can_plant_and_grow_item(Season.fall), Fruit.apricot: self.crop.can_plant_and_grow_item(Season.spring), Fruit.cherry: self.crop.can_plant_and_grow_item(Season.spring), @@ -164,21 +140,21 @@ def __init__(self, player: int, options: StardewValleyOptions): Fruit.mango: self.crop.can_plant_and_grow_item(Season.summer), }) - for tree_fruit in self.tree_fruit_rules: - existing_rules = self.tree_fruit_rules[tree_fruit] + for tree_fruit in self.registry.tree_fruit_rules: + existing_rules = self.registry.tree_fruit_rules[tree_fruit] sapling = f"{tree_fruit} Sapling" - self.tree_fruit_rules[tree_fruit] = existing_rules & self.has(sapling) & self.time.has_lived_months(1) + self.registry.tree_fruit_rules[tree_fruit] = existing_rules & self.has(sapling) & self.time.has_lived_months(1) - self.seed_rules.update({seed.name: self.crop.can_buy_seed(seed) for seed in all_purchasable_seeds}) - self.crop_rules.update({crop.name: self.crop.can_grow(crop) for crop in all_crops}) - self.crop_rules.update({ + self.registry.seed_rules.update({seed.name: self.crop.can_buy_seed(seed) for seed in all_purchasable_seeds}) + self.registry.crop_rules.update({crop.name: self.crop.can_grow(crop) for crop in all_crops}) + self.registry.crop_rules.update({ Seed.coffee: (self.season.has(Season.spring) | self.season.has(Season.summer)) & self.crop.can_buy_seed(crops_by_name[Seed.coffee].seed), Fruit.ancient_fruit: (self.received("Ancient Seeds") | self.received("Ancient Seeds Recipe")) & self.region.can_reach(Region.greenhouse) & self.has(Machine.seed_maker), }) # @formatter:off - self.item_rules.update({ + self.registry.item_rules.update({ "Energy Tonic": self.money.can_spend_at(Region.hospital, 1000), WaterChest.fishing_chest: self.fishing.can_fish_chests(), WaterChest.treasure: self.fishing.can_fish_chests(), @@ -412,33 +388,33 @@ def __init__(self, player: int, options: StardewValleyOptions): WaterItem.white_algae: self.skill.can_fish(Region.mines_floor_20), }) # @formatter:on - self.item_rules.update(self.fish_rules) - self.item_rules.update(self.museum_rules) - self.item_rules.update(self.sapling_rules) - self.item_rules.update(self.tree_fruit_rules) - self.item_rules.update(self.seed_rules) - self.item_rules.update(self.crop_rules) - self.item_rules.update(self.mod.item.get_modded_item_rules()) + self.registry.item_rules.update(self.registry.fish_rules) + self.registry.item_rules.update(self.registry.museum_rules) + self.registry.item_rules.update(self.registry.sapling_rules) + self.registry.item_rules.update(self.registry.tree_fruit_rules) + self.registry.item_rules.update(self.registry.seed_rules) + self.registry.item_rules.update(self.registry.crop_rules) + self.registry.item_rules.update(self.mod.item.get_modded_item_rules()) # For some recipes, the cooked item can be obtained directly, so we either cook it or get it - for recipe in self.cooking_rules: - cooking_rule = self.cooking_rules[recipe] - obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() - self.item_rules[recipe] = obtention_rule | cooking_rule + for recipe in self.registry.cooking_rules: + cooking_rule = self.registry.cooking_rules[recipe] + obtention_rule = self.registry.item_rules[recipe] if recipe in self.registry.item_rules else False_() + self.registry.item_rules[recipe] = obtention_rule | cooking_rule # For some recipes, the crafted item can be obtained directly, so we either craft it or get it - for recipe in self.crafting_rules: - crafting_rule = self.crafting_rules[recipe] - obtention_rule = self.item_rules[recipe] if recipe in self.item_rules else False_() - self.item_rules[recipe] = obtention_rule | crafting_rule + for recipe in self.registry.crafting_rules: + crafting_rule = self.registry.crafting_rules[recipe] + obtention_rule = self.registry.item_rules[recipe] if recipe in self.registry.item_rules else False_() + self.registry.item_rules[recipe] = obtention_rule | crafting_rule self.building.initialize_rules() - self.building.update_rules(self.mod.buildings.get_modded_building_rules()) + self.building.update_rules(self.mod.building.get_modded_building_rules()) self.quest.initialize_rules() - self.quest.update_rules(self.mod.quests.get_modded_quest_rules()) + self.quest.update_rules(self.mod.quest.get_modded_quest_rules()) - self.festival_rules.update({ + self.registry.festival_rules.update({ FestivalCheck.egg_hunt: self.can_win_egg_hunt(), FestivalCheck.strawberry_seeds: self.money.can_spend(1000), FestivalCheck.dance: self.relationship.has_hearts(Generic.bachelor, 4), @@ -477,7 +453,7 @@ def __init__(self, player: int, options: StardewValleyOptions): }) self.special_order.initialize_rules() - self.special_order.update_rules(self.mod.special_orders.get_modded_special_orders_rules(self.registry.special_order_rules)) + self.special_order.update_rules(self.mod.special_order.get_modded_special_orders_rules()) def can_buy_sapling(self, fruit: str) -> StardewRule: sapling_prices = {Fruit.apple: 4000, Fruit.apricot: 2000, Fruit.cherry: 3400, Fruit.orange: 4000, diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index 459d8734070b..d95a90230e84 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -1,6 +1,7 @@ -from typing import Dict +from typing import Dict, Union from ..mod_data import ModNames +from ...logic.base_logic import BaseLogicMixin, BaseLogic from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin from ...stardew_rule import StardewRule @@ -10,15 +11,18 @@ from ...strings.region_names import Region -class ModBuildingLogic(MoneyLogicMixin, HasLogicMixin): +class ModBuildingLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.buildings = self + self.building = ModBuildingLogic(*args, **kwargs) + + +class ModBuildingLogic(BaseLogic[Union[MoneyLogicMixin, HasLogicMixin]]): def get_modded_building_rules(self) -> Dict[str, StardewRule]: buildings = dict() if ModNames.tractor in self.options.mods: - tractor_rule = self.money.can_spend_at(Region.carpenter, 150000) & self.has(MetalBar.iron) & self.has(MetalBar.iridium) & self.has( - ArtisanGood.battery_pack) + tractor_rule = (self.logic.money.can_spend_at(Region.carpenter, 150000) & self.logic.has(MetalBar.iron) & + self.logic.has(MetalBar.iridium) & self.logic.has(ArtisanGood.battery_pack)) buildings.update({ModBuilding.tractor_garage: tractor_rule}) return buildings diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index e65b5573322e..ca3ff8002b0f 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -1,9 +1,12 @@ -from ...logic.combat_logic import CombatLogic -from ...logic.cooking_logic import CookingLogic +from typing import Union + +from ...logic.base_logic import BaseLogicMixin, BaseLogic +from ...logic.combat_logic import CombatLogicMixin +from ...logic.cooking_logic import CookingLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.received_logic import ReceivedLogicMixin -from ...logic.skill_logic import SkillLogic -from ...logic.tool_logic import ToolLogic +from ...logic.skill_logic import SkillLogicMixin +from ...logic.tool_logic import ToolLogicMixin from ...options import SkillProgression, ElevatorProgression from ...stardew_rule import StardewRule, True_, And from ...strings.ap_names.transport_names import ModTransportation @@ -13,49 +16,34 @@ from ...strings.tool_names import Tool, ToolMaterial -class DeepWoodsLogic: - player: int - skill_option: SkillProgression - elevator_option: ElevatorProgression - received: ReceivedLogicMixin - has: HasLogicMixin - combat: CombatLogic - tool: ToolLogic - skill: SkillLogic - cooking: CookingLogic - - def __init__(self, player: int, skill_option: SkillProgression, elevator_option: ElevatorProgression, received: ReceivedLogicMixin, has: HasLogicMixin, - combat: CombatLogic, tool: ToolLogic, - skill: SkillLogic, cooking: CookingLogic): - self.player = player - self.skill_option = skill_option - self.elevator_option = elevator_option - self.received = received - self.has = has - self.combat = combat - self.tool = tool - self.skill = skill - self.cooking = cooking +class DeepWoodsLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.deepwoods = DeepWoodsLogic(*args, **kwargs) + + +class DeepWoodsLogic(BaseLogic[Union[SkillLogicMixin, ReceivedLogicMixin, HasLogicMixin, CombatLogicMixin, ToolLogicMixin, SkillLogicMixin, +CookingLogicMixin]]): def can_reach_woods_depth(self, depth: int) -> StardewRule: tier = int(depth / 25) + 1 rules = [] if depth > 10: - rules.append(self.has(Bomb.bomb) | self.tool.has_tool(Tool.axe, ToolMaterial.iridium)) + rules.append(self.logic.has(Bomb.bomb) | self.logic.tool.has_tool(Tool.axe, ToolMaterial.iridium)) if depth > 30: - rules.append(self.received(ModTransportation.woods_obelisk)) + rules.append(self.logic.received(ModTransportation.woods_obelisk)) if depth > 50: - rules.append(self.combat.can_fight_at_level(Performance.great) & self.cooking.can_cook() & - self.received(ModTransportation.woods_obelisk)) - if self.skill_option == SkillProgression.option_progressive: + rules.append(self.logic.combat.can_fight_at_level(Performance.great) & self.logic.cooking.can_cook() & + self.logic.received(ModTransportation.woods_obelisk)) + if self.options.skill_progression == SkillProgression.option_progressive: combat_tier = min(10, max(0, tier + 5)) - rules.append(self.skill.has_level(Skill.combat, combat_tier)) + rules.append(self.logic.skill.has_level(Skill.combat, combat_tier)) return And(*rules) def has_woods_rune_to_depth(self, floor: int) -> StardewRule: - if self.elevator_option == ElevatorProgression.option_vanilla: + if self.options.skill_progression == ElevatorProgression.option_vanilla: return True_() - return self.received("Progressive Woods Obelisk Sigils", int(floor / 10)) + return self.logic.received("Progressive Woods Obelisk Sigils", int(floor / 10)) def can_chop_to_depth(self, floor: int) -> StardewRule: previous_elevator = max(floor - 10, 0) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 98eb01ba207f..6b8bbad72a4f 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -1,20 +1,20 @@ -from typing import Dict +from typing import Dict, Union from ..mod_data import ModNames from ...data.craftable_data import all_crafting_recipes_by_name -from ...logic.combat_logic import CombatLogic -from ...logic.cooking_logic import CookingLogic -from ...logic.crafting_logic import CraftingLogic -from ...logic.crop_logic import CropLogic +from ...logic.base_logic import BaseLogicMixin, BaseLogic +from ...logic.combat_logic import CombatLogicMixin +from ...logic.cooking_logic import CookingLogicMixin +from ...logic.crafting_logic import CraftingLogicMixin +from ...logic.crop_logic import CropLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin -from ...logic.museum_logic import MuseumLogic +from ...logic.museum_logic import MuseumLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin -from ...logic.tool_logic import ToolLogic -from ...options import Mods +from ...logic.tool_logic import ToolLogicMixin from ...stardew_rule import StardewRule from ...strings.craftable_names import ModCraftable, ModEdible, ModMachine from ...strings.crop_names import SVEVegetable, SVEFruit @@ -33,104 +33,85 @@ display_items = all_artifacts + all_fossils -class ModItemLogic: - mods: Mods - combat: CombatLogic - crop: CropLogic - cooking: CookingLogic - has: HasLogicMixin - money: MoneyLogicMixin - region: RegionLogicMixin - season: SeasonLogicMixin - relationship: RelationshipLogicMixin - museum: MuseumLogic - received: ReceivedLogicMixin - tool: ToolLogic - crafting: CraftingLogic +class ModItemLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.item = ModItemLogic(*args, **kwargs) - def __init__(self, mods: Mods, combat: CombatLogic, crop: CropLogic, cooking: CookingLogic, has: HasLogicMixin, money: MoneyLogicMixin, - region: RegionLogicMixin, - season: SeasonLogicMixin, relationship: RelationshipLogicMixin, museum: MuseumLogic, tool: ToolLogic, crafting: CraftingLogic): - self.combat = combat - self.crop = crop - self.cooking = cooking - self.mods = mods - self.has = has - self.money = money - self.region = region - self.season = season - self.relationship = relationship - self.museum = museum - self.tool = tool - self.crafting = crafting + +class ModItemLogic(BaseLogic[Union[CombatLogicMixin, ReceivedLogicMixin, CropLogicMixin, CookingLogicMixin, HasLogicMixin, MoneyLogicMixin, RegionLogicMixin, +SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin]]): def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() - if ModNames.sve in self.mods: + if ModNames.sve in self.options.mods: items.update(self.get_sve_item_rules()) - if ModNames.archaeology in self.mods: + if ModNames.archaeology in self.options.mods: items.update(self.get_archaeology_item_rules()) return items def get_sve_item_rules(self): - return {SVEGift.aged_blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 28000), - SVEGift.blue_moon_wine: self.money.can_spend_at(SVERegion.sophias_house, 3000), - SVESeed.fungus_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon, - ModLoot.green_mushroom: self.region.can_reach(SVERegion.highlands) & self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.monster_fruit: self.season.has(Season.summer) & self.has(SVESeed.stalk_seed), - SVEVegetable.monster_mushroom: self.season.has(Season.fall) & self.has(SVESeed.fungus_seed), - SVEForage.ornate_treasure_chest: self.region.can_reach(SVERegion.highlands) & self.combat.has_galaxy_weapon & - self.tool.has_tool(Tool.axe, ToolMaterial.iron), - SVEFruit.slime_berry: self.season.has(Season.spring) & self.has(SVESeed.slime_seed), - SVESeed.slime_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon, - SVESeed.stalk_seed: self.region.can_reach(SVERegion.highlands) & self.combat.has_good_weapon, - SVEForage.swirl_stone: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, - SVEVegetable.void_root: self.season.has(Season.winter) & self.has(SVESeed.void_seed), - SVESeed.void_seed: self.region.can_reach(SVERegion.highlands_cavern) & self.combat.has_good_weapon, - SVEForage.void_soul: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_good_weapon & self.cooking.can_cook(), - SVEForage.winter_star_rose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.winter), - SVEForage.bearberrys: self.region.can_reach(Region.secret_woods) & self.season.has(Season.winter), - SVEForage.poison_mushroom: self.region.can_reach(Region.secret_woods) & self.season.has_any([Season.summer, Season.fall]), - SVEForage.red_baneberry: self.region.can_reach(Region.secret_woods) & self.season.has(Season.summer), - SVEForage.ferngill_primrose: self.region.can_reach(SVERegion.summit) & self.season.has(Season.spring), - SVEForage.goldenrod: self.region.can_reach(SVERegion.summit) & (self.season.has(Season.summer) | self.season.has(Season.fall)), - SVESeed.shrub_seed: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.hoe, ToolMaterial.basic), - SVEFruit.salal_berry: self.crop.can_plant_and_grow_item([Season.spring, Season.summer]) & self.has(SVESeed.shrub_seed), - ModEdible.aegis_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 28000), - ModEdible.lightning_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 12000), - ModEdible.barbarian_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 22000), - ModEdible.gravity_elixir: self.money.can_spend_at(SVERegion.galmoran_outpost, 4000), - SVESeed.ancient_ferns_seed: self.region.can_reach(Region.secret_woods) & self.tool.has_tool(Tool.hoe, ToolMaterial.basic), - SVEVegetable.ancient_fiber: self.crop.can_plant_and_grow_item(Season.summer) & self.has(SVESeed.ancient_ferns_seed), - SVEForage.big_conch: self.region.can_reach_any((Region.beach, SVERegion.fable_reef)), - SVEForage.dewdrop_berry: self.region.can_reach(SVERegion.enchanted_grove), - SVEForage.dried_sand_dollar: self.region.can_reach(SVERegion.fable_reef) | (self.region.can_reach(Region.beach) & - self.season.has_any([Season.summer, Season.fall])), - "Galdoran Gem": self.museum.can_complete_museum() & self.relationship.has_hearts(ModNPC.marlon, 8), - SVEForage.golden_ocean_flower: self.region.can_reach(SVERegion.fable_reef), - SVEMeal.grampleton_orange_chicken: self.money.can_spend_at(Region.saloon, 650), - ModEdible.hero_elixir: self.money.can_spend_at(SVERegion.issac_shop, 8000), - SVEForage.lucky_four_leaf_clover: self.region.can_reach_any((Region.secret_woods, SVERegion.forest_west)) & - self.season.has_any([Season.spring, Season.summer]), - SVEForage.mushroom_colony: self.region.can_reach_any((Region.secret_woods, SVERegion.junimo_woods, SVERegion.forest_west)) & - self.season.has(Season.fall), - SVEForage.rusty_blade: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, - SVEForage.smelly_rafflesia: self.region.can_reach(Region.secret_woods), - SVEBeverage.sports_drink: self.money.can_spend_at(Region.hospital, 750), - "Stamina Capsule": self.money.can_spend_at(Region.hospital, 4000), - SVEForage.thistle: self.region.can_reach(SVERegion.summit), - SVEForage.void_pebble: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_great_weapon, - ModLoot.void_shard: self.region.can_reach(SVERegion.crimson_badlands) & self.combat.has_galaxy_weapon + return {SVEGift.aged_blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 28000), + SVEGift.blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 3000), + SVESeed.fungus_seed: self.logic.region.can_reach(SVERegion.highlands_cavern) & self.logic.combat.has_good_weapon, + ModLoot.green_mushroom: self.logic.region.can_reach(SVERegion.highlands) & self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.monster_fruit: self.logic.season.has(Season.summer) & self.logic.has(SVESeed.stalk_seed), + SVEVegetable.monster_mushroom: self.logic.season.has(Season.fall) & self.logic.has(SVESeed.fungus_seed), + SVEForage.ornate_treasure_chest: self.logic.region.can_reach(SVERegion.highlands) & self.logic.combat.has_galaxy_weapon & + self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron), + SVEFruit.slime_berry: self.logic.season.has(Season.spring) & self.logic.has(SVESeed.slime_seed), + SVESeed.slime_seed: self.logic.region.can_reach(SVERegion.highlands) & self.logic.combat.has_good_weapon, + SVESeed.stalk_seed: self.logic.region.can_reach(SVERegion.highlands) & self.logic.combat.has_good_weapon, + SVEForage.swirl_stone: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_great_weapon, + SVEVegetable.void_root: self.logic.season.has(Season.winter) & self.logic.has(SVESeed.void_seed), + SVESeed.void_seed: self.logic.region.can_reach(SVERegion.highlands_cavern) & self.logic.combat.has_good_weapon, + SVEForage.void_soul: self.logic.region.can_reach( + SVERegion.crimson_badlands) & self.logic.combat.has_good_weapon & self.logic.cooking.can_cook(), + SVEForage.winter_star_rose: self.logic.region.can_reach(SVERegion.summit) & self.logic.season.has(Season.winter), + SVEForage.bearberrys: self.logic.region.can_reach(Region.secret_woods) & self.logic.season.has(Season.winter), + SVEForage.poison_mushroom: self.logic.region.can_reach(Region.secret_woods) & self.logic.season.has_any([Season.summer, Season.fall]), + SVEForage.red_baneberry: self.logic.region.can_reach(Region.secret_woods) & self.logic.season.has(Season.summer), + SVEForage.ferngill_primrose: self.logic.region.can_reach(SVERegion.summit) & self.logic.season.has(Season.spring), + SVEForage.goldenrod: self.logic.region.can_reach(SVERegion.summit) & ( + self.logic.season.has(Season.summer) | self.logic.season.has(Season.fall)), + SVESeed.shrub_seed: self.logic.region.can_reach(Region.secret_woods) & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic), + SVEFruit.salal_berry: self.logic.crop.can_plant_and_grow_item([Season.spring, Season.summer]) & self.logic.has(SVESeed.shrub_seed), + ModEdible.aegis_elixir: self.logic.money.can_spend_at(SVERegion.galmoran_outpost, 28000), + ModEdible.lightning_elixir: self.logic.money.can_spend_at(SVERegion.galmoran_outpost, 12000), + ModEdible.barbarian_elixir: self.logic.money.can_spend_at(SVERegion.galmoran_outpost, 22000), + ModEdible.gravity_elixir: self.logic.money.can_spend_at(SVERegion.galmoran_outpost, 4000), + SVESeed.ancient_ferns_seed: self.logic.region.can_reach(Region.secret_woods) & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic), + SVEVegetable.ancient_fiber: self.logic.crop.can_plant_and_grow_item(Season.summer) & self.logic.has(SVESeed.ancient_ferns_seed), + SVEForage.big_conch: self.logic.region.can_reach_any((Region.beach, SVERegion.fable_reef)), + SVEForage.dewdrop_berry: self.logic.region.can_reach(SVERegion.enchanted_grove), + SVEForage.dried_sand_dollar: self.logic.region.can_reach(SVERegion.fable_reef) | (self.logic.region.can_reach(Region.beach) & + self.logic.season.has_any([Season.summer, Season.fall])), + "Galdoran Gem": self.logic.museum.can_complete_museum() & self.logic.relationship.has_hearts(ModNPC.marlon, 8), + SVEForage.golden_ocean_flower: self.logic.region.can_reach(SVERegion.fable_reef), + SVEMeal.grampleton_orange_chicken: self.logic.money.can_spend_at(Region.saloon, 650), + ModEdible.hero_elixir: self.logic.money.can_spend_at(SVERegion.issac_shop, 8000), + SVEForage.lucky_four_leaf_clover: self.logic.region.can_reach_any((Region.secret_woods, SVERegion.forest_west)) & + self.logic.season.has_any([Season.spring, Season.summer]), + SVEForage.mushroom_colony: self.logic.region.can_reach_any((Region.secret_woods, SVERegion.junimo_woods, SVERegion.forest_west)) & + self.logic.season.has(Season.fall), + SVEForage.rusty_blade: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_great_weapon, + SVEForage.smelly_rafflesia: self.logic.region.can_reach(Region.secret_woods), + SVEBeverage.sports_drink: self.logic.money.can_spend_at(Region.hospital, 750), + "Stamina Capsule": self.logic.money.can_spend_at(Region.hospital, 4000), + SVEForage.thistle: self.logic.region.can_reach(SVERegion.summit), + SVEForage.void_pebble: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_great_weapon, + ModLoot.void_shard: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_galaxy_weapon } + # @formatter:on def get_archaeology_item_rules(self): archaeology_item_rules = {} - preservation_chamber_rule = self.has(ModMachine.preservation_chamber) - hardwood_preservation_chamber_rule = self.has(ModMachine.hardwood_preservation_chamber) + preservation_chamber_rule = self.logic.has(ModMachine.preservation_chamber) + hardwood_preservation_chamber_rule = self.logic.has(ModMachine.hardwood_preservation_chamber) for item in display_items: for display_type in display_types: location_name = f"{display_type}: {item}" - display_item_rule = self.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.has(item) + display_item_rule = self.logic.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.logic.has(item) if "Wooden" in display_type: archaeology_item_rules[location_name] = display_item_rule & preservation_chamber_rule else: diff --git a/worlds/stardew_valley/mods/logic/mod_logic.py b/worlds/stardew_valley/mods/logic/mod_logic.py index cb405fc6148d..37c17183dbb0 100644 --- a/worlds/stardew_valley/mods/logic/mod_logic.py +++ b/worlds/stardew_valley/mods/logic/mod_logic.py @@ -1,48 +1,21 @@ -from .buildings_logic import ModBuildingLogic -from .deepwoods_logic import DeepWoodsLogic +from .buildings_logic import ModBuildingLogicMixin +from .deepwoods_logic import DeepWoodsLogicMixin from .elevator_logic import ModElevatorLogicMixin -from .item_logic import ModItemLogic +from .item_logic import ModItemLogicMixin from .magic_logic import MagicLogicMixin -from .quests_logic import ModQuestLogic +from .quests_logic import ModQuestLogicMixin from .skills_logic import ModSkillLogicMixin -from .special_orders_logic import ModSpecialOrderLogic -from .sve_logic import SVELogic -from ...logic.ability_logic import AbilityLogic -from ...logic.base_logic import LogicRegistry, BaseLogicMixin -from ...logic.cooking_logic import CookingLogic -from ...logic.crafting_logic import CraftingLogic -from ...logic.fishing_logic import FishingLogic -from ...logic.mine_logic import MineLogic -from ...logic.quest_logic import QuestLogic -from ...logic.region_logic import RegionLogicMixin -from ...logic.skill_logic import SkillLogic -from ...options import SkillProgression, ElevatorProgression, Mods +from .special_orders_logic import ModSpecialOrderLogicMixin +from .sve_logic import SVELogicMixin +from ...logic.base_logic import BaseLogicMixin class ModLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.mod = None + self.mod = ModLogic(*args, **kwargs) -class ModLogic(ModElevatorLogicMixin, MagicLogicMixin, ModSkillLogicMixin): - items: ModItemLogic - quests: ModQuestLogic - region: RegionLogicMixin - buildings: ModBuildingLogic - special_orders: ModSpecialOrderLogic - deepwoods: DeepWoodsLogic - sve: SVELogic - - def __init__(self, player: int, registry: LogicRegistry, options, logic, skill_option: SkillProgression, elevator_option: ElevatorProgression, mods: Mods, - skill: SkillLogic, fishing: FishingLogic, cooking: CookingLogic, mine: MineLogic, ability: AbilityLogic, - quest: QuestLogic, crafting: CraftingLogic): - super().__init__(player, registry, options, logic) - self.item = ModItemLogic(mods, logic.combat, logic.crop, cooking, logic.has, logic.money, logic.region, logic.season, logic.relationship, logic.museum, logic.tool, crafting) - self.quests = ModQuestLogic(mods, logic.received, logic.has, logic.region, logic.time, logic.season, logic.relationship) - self.buildings = ModBuildingLogic(player, registry, options, logic) - self.special_orders = ModSpecialOrderLogic(player, logic.action, logic.artisan, crafting, logic.crop, logic.has, logic.region, logic.relationship, - logic.season, logic.wallet, mods) - self.deepwoods = DeepWoodsLogic(player, skill_option, elevator_option, logic.received, logic.has, logic.combat, logic.tool, skill, cooking) - self.sve = SVELogic(player, skill_option, logic.received, logic.has, quest, logic.region, logic.action, logic.relationship, logic.building, logic.tool, - fishing, cooking, logic.money, logic.combat, logic.season, logic.time) +class ModLogic(ModElevatorLogicMixin, MagicLogicMixin, ModSkillLogicMixin, ModItemLogicMixin, ModQuestLogicMixin, ModBuildingLogicMixin, + ModSpecialOrderLogicMixin, DeepWoodsLogicMixin, SVELogicMixin): + pass diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 98874b1f5459..c41c4cb46409 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -1,13 +1,13 @@ -from typing import Dict +from typing import Dict, Union from ..mod_data import ModNames +from ...logic.base_logic import BaseLogic, BaseLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin -from ...options import Mods from ...stardew_rule import StardewRule from ...strings.artisan_good_names import ArtisanGood from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable @@ -23,25 +23,13 @@ from ...strings.wallet_item_names import Wallet -class ModQuestLogic: - mods: Mods - received: ReceivedLogicMixin - has: HasLogicMixin - region: RegionLogicMixin - time: TimeLogicMixin - season: SeasonLogicMixin - relationship: RelationshipLogicMixin +class ModQuestLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.quest = ModQuestLogic(*args, **kwargs) - def __init__(self, mods: Mods, received: ReceivedLogicMixin, has: HasLogicMixin, region: RegionLogicMixin, time: TimeLogicMixin, season: SeasonLogicMixin, - relationship: RelationshipLogicMixin, ): - self.mods = mods - self.received = received - self.has = has - self.region = region - self.time = time - self.season = season - self.relationship = relationship +class ModQuestLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin]]): def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = dict() quests.update(self._get_juna_quest_rules()) @@ -51,43 +39,43 @@ def get_modded_quest_rules(self) -> Dict[str, StardewRule]: return quests def _get_juna_quest_rules(self): - if ModNames.juna not in self.mods: + if ModNames.juna not in self.options.mods: return {} return { - ModQuest.JunaCola: self.relationship.has_hearts(ModNPC.juna, 3) & self.has(Beverage.joja_cola), - ModQuest.JunaSpaghetti: self.relationship.has_hearts(ModNPC.juna, 6) & self.has(Meal.spaghetti) + ModQuest.JunaCola: self.logic.relationship.has_hearts(ModNPC.juna, 3) & self.logic.has(Beverage.joja_cola), + ModQuest.JunaSpaghetti: self.logic.relationship.has_hearts(ModNPC.juna, 6) & self.logic.has(Meal.spaghetti) } def _get_mr_ginger_quest_rules(self): - if ModNames.ginger not in self.mods: + if ModNames.ginger not in self.options.mods: return {} return { - ModQuest.MrGinger: self.relationship.has_hearts(ModNPC.mr_ginger, 6) & self.has(Loot.void_essence) + ModQuest.MrGinger: self.logic.relationship.has_hearts(ModNPC.mr_ginger, 6) & self.logic.has(Loot.void_essence) } def _get_ayeisha_quest_rules(self): - if ModNames.ayeisha not in self.mods: + if ModNames.ayeisha not in self.options.mods: return {} return { - ModQuest.AyeishaEnvelope: (self.season.has(Season.spring) | self.season.has(Season.fall)), - ModQuest.AyeishaRing: self.season.has(Season.winter) + ModQuest.AyeishaEnvelope: (self.logic.season.has(Season.spring) | self.logic.season.has(Season.fall)), + ModQuest.AyeishaRing: self.logic.season.has(Season.winter) } def _get_sve_quest_rules(self): - if ModNames.sve not in self.mods: + if ModNames.sve not in self.options.mods: return {} return { - ModQuest.RailroadBoulder: self.received(Wallet.skull_key) & self.has((Ore.iridium, Material.coal)) & - self.region.can_reach(Region.blacksmith) & self.region.can_reach(Region.railroad), - ModQuest.GrandpasShed: self.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & - self.region.can_reach(SVERegion.grandpas_shed_interior), - ModQuest.MarlonsBoat: self.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & - self.relationship.can_meet(ModNPC.lance) & self.region.can_reach(SVERegion.guild_summit), - ModQuest.AuroraVineyard: self.has(Fruit.starfruit) & self.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), - ModQuest.VoidSoul: self.region.can_reach(Region.sewer) & self.has(SVEForage.void_soul), + ModQuest.RailroadBoulder: self.logic.received(Wallet.skull_key) & self.logic.has((Ore.iridium, Material.coal)) & + self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad), + ModQuest.GrandpasShed: self.logic.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & + self.logic.region.can_reach(SVERegion.grandpas_shed_interior), + ModQuest.MarlonsBoat: self.logic.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & + self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), + ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), + ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), + ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul), } diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index 253e3813ae27..f06489aee7ed 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -1,14 +1,16 @@ +from typing import Union + from ..mod_data import ModNames from ...logic.action_logic import ActionLogicMixin from ...logic.artisan_logic import ArtisanLogicMixin -from ...logic.crafting_logic import CraftingLogic -from ...logic.crop_logic import CropLogic +from ...logic.base_logic import BaseLogicMixin, BaseLogic +from ...logic.crafting_logic import CraftingLogicMixin +from ...logic.crop_logic import CropLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.wallet_logic import WalletLogicMixin -from ...options import Mods from ...strings.artisan_good_names import ArtisanGood from ...strings.craftable_names import Consumable, Edible, Bomb from ...strings.crop_names import Fruit @@ -23,59 +25,40 @@ from ...strings.villager_names import ModNPC -class ModSpecialOrderLogic: - player: int - action: ActionLogicMixin - artisan: ArtisanLogicMixin - crafting: CraftingLogic - crop: CropLogic - has: HasLogicMixin - region: RegionLogicMixin - relationship: RelationshipLogicMixin - season: SeasonLogicMixin - wallet: WalletLogicMixin - mods_option: Mods +class ModSpecialOrderLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.special_order = ModSpecialOrderLogic(*args, **kwargs) - def __init__(self, player: int, action: ActionLogicMixin, artisan: ArtisanLogicMixin, crafting: CraftingLogic, crop: CropLogic, has: HasLogicMixin, - region: RegionLogicMixin, relationship: RelationshipLogicMixin, - season: SeasonLogicMixin, wallet: WalletLogicMixin, mods_option: Mods): - self.player = player - self.action = action - self.artisan = artisan - self.crafting = crafting - self.crop = crop - self.has = has - self.region = region - self.relationship = relationship - self.season = season - self.wallet = wallet - self.mods_option = mods_option - def get_modded_special_orders_rules(self, vanilla_rules): +class ModSpecialOrderLogic(BaseLogic[Union[ActionLogicMixin, ArtisanLogicMixin, CraftingLogicMixin, CropLogicMixin, HasLogicMixin, RegionLogicMixin, +RelationshipLogicMixin, SeasonLogicMixin, WalletLogicMixin]]): + def get_modded_special_orders_rules(self): special_orders = {} - if ModNames.juna in self.mods_option: + if ModNames.juna in self.options.mods: special_orders.update({ - ModSpecialOrder.junas_monster_mash: self.relationship.has_hearts(ModNPC.juna, 4) & - vanilla_rules[SpecialOrder.a_curious_substance] & - self.wallet.has_rusty_key & - self.region.can_reach(Region.forest) & self.has(Consumable.monster_musk) & - self.has("Energy Tonic") & self.has(Material.sap) & self.has(Loot.bug_meat) & - self.has(Edible.oil_of_garlic) & self.has(Meal.strange_bun) + ModSpecialOrder.junas_monster_mash: self.logic.relationship.has_hearts(ModNPC.juna, 4) & + self.registry.special_order_rules[SpecialOrder.a_curious_substance] & + self.logic.wallet.has_rusty_key & + self.logic.region.can_reach(Region.forest) & self.logic.has(Consumable.monster_musk) & + self.logic.has("Energy Tonic") & self.logic.has(Material.sap) & self.logic.has(Loot.bug_meat) & + self.logic.has(Edible.oil_of_garlic) & self.logic.has(Meal.strange_bun) }) - if ModNames.sve in self.mods_option: + if ModNames.sve in self.options.mods: special_orders.update({ - ModSpecialOrder.andys_cellar: self.has(Material.stone) & self.has(Material.wood) & self.has(Material.hardwood) & self.has(MetalBar.iron) & - self.region.can_reach(SVERegion.fairhaven_farm), - ModSpecialOrder.a_mysterious_venture: self.has(Bomb.cherry_bomb) & self.has(Bomb.bomb) & self.has(Bomb.mega_bomb) & - self.region.can_reach(Region.adventurer_guild), - ModSpecialOrder.an_elegant_reception: self.artisan.can_keg(Fruit.starfruit) & self.has(ArtisanGood.cheese) & - self.has(ArtisanGood.goat_cheese) & self.season.has_any_not_winter() & self.region.can_reach( - SVERegion.jenkins_cellar), - ModSpecialOrder.fairy_garden: self.has(Consumable.fairy_dust) & - self.region.can_reach(Region.island_south) & ( - self.action.can_open_geode(Geode.frozen) | self.action.can_open_geode(Geode.omni)) & - self.region.can_reach(SVERegion.blue_moon_vineyard), - ModSpecialOrder.homemade_fertilizer: self.has(Fertilizer.quality) & self.region.can_reach(SVERegion.susans_house) + ModSpecialOrder.andys_cellar: self.logic.has(Material.stone) & self.logic.has(Material.wood) & self.logic.has(Material.hardwood) & + self.logic.has(MetalBar.iron) & + self.logic.region.can_reach(SVERegion.fairhaven_farm), + ModSpecialOrder.a_mysterious_venture: self.logic.has(Bomb.cherry_bomb) & self.logic.has(Bomb.bomb) & self.logic.has(Bomb.mega_bomb) & + self.logic.region.can_reach(Region.adventurer_guild), + ModSpecialOrder.an_elegant_reception: self.logic.artisan.can_keg(Fruit.starfruit) & self.logic.has(ArtisanGood.cheese) & + self.logic.has(ArtisanGood.goat_cheese) & self.logic.season.has_any_not_winter() & + self.logic.region.can_reach(SVERegion.jenkins_cellar), + ModSpecialOrder.fairy_garden: self.logic.has(Consumable.fairy_dust) & + self.logic.region.can_reach(Region.island_south) & ( + self.logic.action.can_open_geode(Geode.frozen) | self.logic.action.can_open_geode(Geode.omni)) & + self.logic.region.can_reach(SVERegion.blue_moon_vineyard), + ModSpecialOrder.homemade_fertilizer: self.logic.has(Fertilizer.quality) & self.logic.region.can_reach(SVERegion.susans_house) }) return special_orders diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 0ea922f717fe..0e8bdf7dafce 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -1,79 +1,46 @@ -from typing import Dict +from typing import Union from ..mod_regions import SVERegion -from ...logic.action_logic import ActionLogicMixin -from ...logic.building_logic import BuildingLogicMixin -from ...logic.combat_logic import CombatLogic -from ...logic.cooking_logic import CookingLogic -from ...logic.fishing_logic import FishingLogic +from ...logic.base_logic import BaseLogicMixin, BaseLogic +from ...logic.combat_logic import CombatLogicMixin +from ...logic.cooking_logic import CookingLogicMixin +from ...logic.fishing_logic import FishingLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin -from ...logic.quest_logic import QuestLogic +from ...logic.quest_logic import QuestLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin -from ...logic.tool_logic import ToolLogic -from ...options import SkillProgression -from ...stardew_rule import StardewRule, Or +from ...logic.tool_logic import ToolLogicMixin +from ...stardew_rule import Or -class SVELogic: - player: int - received: ReceivedLogicMixin - has: HasLogicMixin - quest: QuestLogic - region: RegionLogicMixin - relationship: RelationshipLogicMixin - time: TimeLogicMixin - tool: ToolLogic - fishing: FishingLogic - cooking: CookingLogic - money: MoneyLogicMixin - combat: CombatLogic - season: SeasonLogicMixin - sve_location_rules: Dict[str, StardewRule] +class SVELogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sve = SVELogic(*args, **kwargs) - def __init__(self, player: int, skill_option: SkillProgression, received: ReceivedLogicMixin, has: HasLogicMixin, quest: QuestLogic, - region: RegionLogicMixin, - action: ActionLogicMixin, - relationship: RelationshipLogicMixin, building: BuildingLogicMixin, tool: ToolLogic, fishing: FishingLogic, cooking: CookingLogic, - money: MoneyLogicMixin, combat: CombatLogic, season: SeasonLogicMixin, time: TimeLogicMixin): - self.player = player - self.skill_option = skill_option - self.received = received - self.has = has - self.quest = quest - self.region = region - self.action = action - self.relationship = relationship - self.building = building - self.tool = tool - self.fishing = fishing - self.cooking = cooking - self.time = time - self.money = money - self.combat = combat - self.season = season - self.sve_location_rules = dict() +class SVELogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, QuestLogicMixin, RegionLogicMixin, RelationshipLogicMixin, TimeLogicMixin, ToolLogicMixin, +FishingLogicMixin, CookingLogicMixin, MoneyLogicMixin, CombatLogicMixin, SeasonLogicMixin]]): def initialize_rules(self): - self.sve_location_rules.update({ - "Alesia: Tempered Galaxy Dagger": self.region.can_reach( - SVERegion.alesia_shop) & self.combat.has_galaxy_weapon() & - self.money.can_spend(350000) & self.time.has_lived_months(3), - "Issac: Tempered Galaxy Sword": self.region.can_reach( - SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & - self.money.can_spend(600000), - "Issac: Tempered Galaxy Hammer": self.region.can_reach( - SVERegion.issac_shop) & self.combat.has_galaxy_weapon() & - self.money.can_spend(400000), - "Lance's Diamond Wand": self.quest.can_complete_quest("Monster Crops") & self.region.can_reach( + self.registry.sve_location_rules.update({ + "Alesia: Tempered Galaxy Dagger": self.logic.region.can_reach( + SVERegion.alesia_shop) & self.logic.combat.has_galaxy_weapon() & + self.logic.money.can_spend(350000) & self.logic.time.has_lived_months(3), + "Issac: Tempered Galaxy Sword": self.logic.region.can_reach( + SVERegion.issac_shop) & self.logic.combat.has_galaxy_weapon() & + self.logic.money.can_spend(600000), + "Issac: Tempered Galaxy Hammer": self.logic.region.can_reach( + SVERegion.issac_shop) & self.logic.combat.has_galaxy_weapon() & + self.logic.money.can_spend(400000), + "Lance's Diamond Wand": self.logic.quest.can_complete_quest("Monster Crops") & self.logic.region.can_reach( SVERegion.lances_house), }) def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", "Nexus: Outpost Runes"] - return Or(*(self.received(rune) for rune in rune_list)) + return Or(*(self.logic.received(rune) for rune in rune_list)) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 3a4c51cad4e5..432535a09b1a 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -623,7 +623,7 @@ def set_festival_rules(all_location_names: List[str], logic: StardewLogic, multi for festival in festival_locations: if festival.name in all_location_names: MultiWorldRules.set_rule(multiworld.get_location(festival.name, player), - logic.festival_rules[festival.name]) + logic.registry.festival_rules[festival.name]) monster_eradication_prefix = "Monster Eradication: " @@ -940,9 +940,9 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) - for location in logic.mod.sve.sve_location_rules: + for location in logic.registry.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), - logic.mod.sve.sve_location_rules[location]) + logic.registry.sve_location_rules[location]) set_sve_ginger_island_rules(logic, multiworld, player, world_options) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 1fd5e48bd119..2384bf2bc7dd 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -21,12 +21,12 @@ class TestLogic(unittest.TestCase): def test_given_bundle_item_then_is_available_in_logic(self): for bundle_item in all_bundle_items_except_money: with self.subTest(msg=bundle_item.item.name): - self.assertIn(bundle_item.item.name, logic.item_rules) + self.assertIn(bundle_item.item.name, logic.registry.item_rules) def test_given_item_rule_then_can_be_resolved(self): - for item in logic.item_rules.keys(): + for item in logic.registry.item_rules.keys(): with self.subTest(msg=item): - rule = logic.item_rules[item] + rule = logic.registry.item_rules[item] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve item rule for {item} {rule}") @@ -52,45 +52,45 @@ def test_given_special_order_rule_then_can_be_resolved(self): self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve special order rule for {special_order} {rule}") def test_given_tree_fruit_rule_then_can_be_resolved(self): - for tree_fruit in logic.tree_fruit_rules.keys(): + for tree_fruit in logic.registry.tree_fruit_rules.keys(): with self.subTest(msg=tree_fruit): - rule = logic.tree_fruit_rules[tree_fruit] + rule = logic.registry.tree_fruit_rules[tree_fruit] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve tree fruit rule for {tree_fruit} {rule}") def test_given_seed_rule_then_can_be_resolved(self): - for seed in logic.seed_rules.keys(): + for seed in logic.registry.seed_rules.keys(): with self.subTest(msg=seed): - rule = logic.seed_rules[seed] + rule = logic.registry.seed_rules[seed] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve seed rule for {seed} {rule}") def test_given_crop_rule_then_can_be_resolved(self): - for crop in logic.crop_rules.keys(): + for crop in logic.registry.crop_rules.keys(): with self.subTest(msg=crop): - rule = logic.crop_rules[crop] + rule = logic.registry.crop_rules[crop] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve crop rule for {crop} {rule}") def test_given_fish_rule_then_can_be_resolved(self): - for fish in logic.fish_rules.keys(): + for fish in logic.registry.fish_rules.keys(): with self.subTest(msg=fish): - rule = logic.fish_rules[fish] + rule = logic.registry.fish_rules[fish] self.assertNotIn(MISSING_ITEM, repr(rule)) rule_result = rule(multi_world.state) self.assertTrue(rule == False_() or rule_result, f"Could not resolve fish rule for {fish} {rule}") def test_given_museum_rule_then_can_be_resolved(self): - for donation in logic.museum_rules.keys(): + for donation in logic.registry.museum_rules.keys(): with self.subTest(msg=donation): - rule = logic.museum_rules[donation] + rule = logic.registry.museum_rules[donation] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve museum rule for {donation} {rule}") def test_given_cooking_rule_then_can_be_resolved(self): - for cooking_rule in logic.cooking_rules.keys(): + for cooking_rule in logic.registry.cooking_rules.keys(): with self.subTest(msg=cooking_rule): - rule = logic.cooking_rules[cooking_rule] + rule = logic.registry.cooking_rules[cooking_rule] self.assertNotIn(MISSING_ITEM, repr(rule)) self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve cooking rule for {cooking_rule} {rule}") From 656bcc2076792584503e21a2734f306e9caf7dae Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 21 Nov 2023 23:58:12 -0500 Subject: [PATCH 199/482] fix options craps --- worlds/stardew_valley/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index c533d9162ed7..560f93c4f278 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -230,35 +230,35 @@ def setup_victory(self): self.create_event_location(location_table[GoalName.greatest_walnut_hunter], self.logic.has_walnut(130), Event.victory) - elif self.options.goal == options.Goal.option_protector_of_the_valley: + elif self.options.goal == Goal.option_protector_of_the_valley: self.create_event_location(location_table[GoalName.protector_of_the_valley], self.logic.can_complete_all_monster_slaying_goals(), Event.victory) - elif self.options.goal == options.Goal.option_full_shipment: + elif self.options.goal == Goal.option_full_shipment: self.create_event_location(location_table[GoalName.full_shipment], self.logic.shipping.can_ship_everything(), Event.victory) - elif self.options.goal == options.Goal.option_gourmet_chef: + elif self.options.goal == Goal.option_gourmet_chef: self.create_event_location(location_table[GoalName.gourmet_chef], self.logic.cooking.can_cook_everything, Event.victory) - elif self.options.goal == options.Goal.option_craft_master: + elif self.options.goal == Goal.option_craft_master: self.create_event_location(location_table[GoalName.craft_master], self.logic.crafting.can_craft_everything, Event.victory) - elif self.options.goal == options.Goal.option_legend: + elif self.options.goal == Goal.option_legend: self.create_event_location(location_table[GoalName.legend], self.logic.money.can_have_earned_total(10_000_000), Event.victory) - elif self.options.goal == options.Goal.option_mystery_of_the_stardrops: + elif self.options.goal == Goal.option_mystery_of_the_stardrops: self.create_event_location(location_table[GoalName.mystery_of_the_stardrops], self.logic.has_all_stardrops(), Event.victory) - elif self.options.goal == options.Goal.option_allsanity: + elif self.options.goal == Goal.option_allsanity: self.create_event_location(location_table[GoalName.allsanity], CountPercent(self.player, 100), Event.victory) - elif self.options.goal == options.Goal.option_perfection: + elif self.options.goal == Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], CountPercent(self.player, 100), Event.victory) From c4c495955eef012fd5a164355d5fc171ec79fc95 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 22:47:49 -0500 Subject: [PATCH 200/482] - WIP - bundles rework --- worlds/stardew_valley/bundles.py | 259 ------- worlds/stardew_valley/bundles/__init__.py | 0 worlds/stardew_valley/bundles/bundle.py | 109 +++ worlds/stardew_valley/bundles/bundle_item.py | 52 ++ worlds/stardew_valley/bundles/bundles.py | 113 +++ worlds/stardew_valley/data/bundle_data.py | 730 +++++++++--------- worlds/stardew_valley/data/common_data.py | 6 - worlds/stardew_valley/data/fish_data.py | 216 +++--- worlds/stardew_valley/data/game_item.py | 13 - worlds/stardew_valley/logic/bundle_logic.py | 6 +- worlds/stardew_valley/rules.py | 3 +- worlds/stardew_valley/strings/crop_names.py | 1 + worlds/stardew_valley/strings/flower_names.py | 6 +- .../stardew_valley/strings/quality_names.py | 15 + worlds/stardew_valley/test/TestBundles.py | 3 +- 15 files changed, 795 insertions(+), 737 deletions(-) delete mode 100644 worlds/stardew_valley/bundles.py create mode 100644 worlds/stardew_valley/bundles/__init__.py create mode 100644 worlds/stardew_valley/bundles/bundle.py create mode 100644 worlds/stardew_valley/bundles/bundle_item.py create mode 100644 worlds/stardew_valley/bundles/bundles.py delete mode 100644 worlds/stardew_valley/data/common_data.py delete mode 100644 worlds/stardew_valley/data/game_item.py create mode 100644 worlds/stardew_valley/strings/quality_names.py diff --git a/worlds/stardew_valley/bundles.py b/worlds/stardew_valley/bundles.py deleted file mode 100644 index b2ff503f6e1d..000000000000 --- a/worlds/stardew_valley/bundles.py +++ /dev/null @@ -1,259 +0,0 @@ -from random import Random -from typing import List, Dict, Union - -from .data.bundle_data import * -from .logic.logic import StardewLogic -from .options import BundleRandomization, BundlePrice - -vanilla_bundles = { - "Pantry/0": "Spring Crops/O 465 20/24 1 0 188 1 0 190 1 0 192 1 0/0", - "Pantry/1": "Summer Crops/O 621 1/256 1 0 260 1 0 258 1 0 254 1 0/3", - "Pantry/2": "Fall Crops/BO 10 1/270 1 0 272 1 0 276 1 0 280 1 0/2", - "Pantry/3": "Quality Crops/BO 15 1/24 5 2 254 5 2 276 5 2 270 5 2/6/3", - "Pantry/4": "Animal/BO 16 1/186 1 0 182 1 0 174 1 0 438 1 0 440 1 0 442 1 0/4/5", - # 639 1 0 640 1 0 641 1 0 642 1 0 643 1 0 - "Pantry/5": "Artisan/BO 12 1/432 1 0 428 1 0 426 1 0 424 1 0 340 1 0 344 1 0 613 1 0 634 1 0 635 1 0 636 1 0 637 1 0 638 1 0/1/6", - "Crafts Room/13": "Spring Foraging/O 495 30/16 1 0 18 1 0 20 1 0 22 1 0/0", - "Crafts Room/14": "Summer Foraging/O 496 30/396 1 0 398 1 0 402 1 0/3", - "Crafts Room/15": "Fall Foraging/O 497 30/404 1 0 406 1 0 408 1 0 410 1 0/2", - "Crafts Room/16": "Winter Foraging/O 498 30/412 1 0 414 1 0 416 1 0 418 1 0/6", - "Crafts Room/17": "Construction/BO 114 1/388 99 0 388 99 0 390 99 0 709 10 0/4", - "Crafts Room/19": "Exotic Foraging/O 235 5/88 1 0 90 1 0 78 1 0 420 1 0 422 1 0 724 1 0 725 1 0 726 1 0 257 1 0/1/5", - "Fish Tank/6": "River Fish/O 685 30/145 1 0 143 1 0 706 1 0 699 1 0/6", - "Fish Tank/7": "Lake Fish/O 687 1/136 1 0 142 1 0 700 1 0 698 1 0/0", - "Fish Tank/8": "Ocean Fish/O 690 5/131 1 0 130 1 0 150 1 0 701 1 0/5", - "Fish Tank/9": "Night Fishing/R 516 1/140 1 0 132 1 0 148 1 0/1", - "Fish Tank/10": "Specialty Fish/O 242 5/128 1 0 156 1 0 164 1 0 734 1 0/4", - "Fish Tank/11": "Crab Pot/O 710 3/715 1 0 716 1 0 717 1 0 718 1 0 719 1 0 720 1 0 721 1 0 722 1 0 723 1 0 372 1 0/1/5", - "Boiler Room/20": "Blacksmith's/BO 13 1/334 1 0 335 1 0 336 1 0/2", - "Boiler Room/21": "Geologist's/O 749 5/80 1 0 86 1 0 84 1 0 82 1 0/1", - "Boiler Room/22": "Adventurer's/R 518 1/766 99 0 767 10 0 768 1 0 769 1 0/1/2", - "Vault/23": "2,500g/O 220 3/-1 2500 2500/4", - "Vault/24": "5,000g/O 369 30/-1 5000 5000/2", - "Vault/25": "10,000g/BO 9 1/-1 10000 10000/3", - "Vault/26": "25,000g/BO 21 1/-1 25000 25000/1", - "Bulletin Board/31": "Chef's/O 221 3/724 1 0 259 1 0 430 1 0 376 1 0 228 1 0 194 1 0/4", - "Bulletin Board/32": "Field Research/BO 20 1/422 1 0 392 1 0 702 1 0 536 1 0/5", - "Bulletin Board/33": "Enchanter's/O 336 5/725 1 0 348 1 0 446 1 0 637 1 0/1", - "Bulletin Board/34": "Dye/BO 25 1/420 1 0 397 1 0 421 1 0 444 1 0 62 1 0 266 1 0/6", - "Bulletin Board/35": "Fodder/BO 104 1/262 10 0 178 10 0 613 3 0/3", - "Abandoned Joja Mart/36": "The Missing//348 1 1 807 1 0 74 1 0 454 5 2 795 1 2 445 1 0/1/5" -} - - -class Bundle: - room: str - sprite: str - original_name: str - name: str - rewards: List[str] - requirements: List[BundleItem] - color: str - number_required: int - - def __init__(self, key: str, value: str): - key_parts = key.split("/") - self.room = key_parts[0] - self.sprite = key_parts[1] - - value_parts = value.split("/") - self.original_name = value_parts[0] - self.name = value_parts[0] - self.rewards = self.parse_stardew_objects(value_parts[1]) - self.requirements = self.parse_stardew_bundle_items(value_parts[2]) - self.color = value_parts[3] - if len(value_parts) > 4: - self.number_required = int(value_parts[4]) - else: - self.number_required = len(self.requirements) - - def __repr__(self): - return f"{self.original_name} -> {repr(self.requirements)}" - - def get_name_with_bundle(self) -> str: - return f"{self.original_name} Bundle" - - def to_pair(self) -> (str, str): - key = f"{self.room}/{self.sprite}" - str_rewards = "" - for reward in self.rewards: - str_rewards += f" {reward}" - str_rewards = str_rewards.strip() - str_requirements = "" - for requirement in self.requirements: - str_requirements += f" {requirement.item.item_id} {requirement.amount} {requirement.quality}" - str_requirements = str_requirements.strip() - value = f"{self.name}/{str_rewards}/{str_requirements}/{self.color}/{self.number_required}" - return key, value - - def remove_rewards(self): - self.rewards = [] - - def change_number_required(self, difference: int): - self.number_required = min(len(self.requirements), max(1, self.number_required + difference)) - if len(self.requirements) == 1 and self.requirements[0].item.item_id == -1: - one_fifth = self.requirements[0].amount / 5 - new_amount = int(self.requirements[0].amount + (difference * one_fifth)) - self.requirements[0] = BundleItem.money_bundle(new_amount) - thousand_amount = int(new_amount / 1000) - dollar_amount = str(new_amount % 1000) - while len(dollar_amount) < 3: - dollar_amount = f"0{dollar_amount}" - self.name = f"{thousand_amount},{dollar_amount}g" - - def randomize_requirements(self, random: Random, - potential_requirements: Union[List[BundleItem], List[List[BundleItem]]]): - if not potential_requirements: - return - - number_to_generate = len(self.requirements) - self.requirements.clear() - if number_to_generate > len(potential_requirements): - choices: Union[BundleItem, List[BundleItem]] = random.choices(potential_requirements, k=number_to_generate) - else: - choices: Union[BundleItem, List[BundleItem]] = random.sample(potential_requirements, number_to_generate) - for choice in choices: - if isinstance(choice, BundleItem): - self.requirements.append(choice) - else: - self.requirements.append(random.choice(choice)) - - def assign_requirements(self, new_requirements: List[BundleItem]) -> List[BundleItem]: - number_to_generate = len(self.requirements) - self.requirements.clear() - for requirement in new_requirements: - self.requirements.append(requirement) - if len(self.requirements) >= number_to_generate: - return new_requirements[number_to_generate:] - - @staticmethod - def parse_stardew_objects(string_objects: str) -> List[str]: - objects = [] - if len(string_objects) < 5: - return objects - rewards_parts = string_objects.split(" ") - for index in range(0, len(rewards_parts), 3): - objects.append(f"{rewards_parts[index]} {rewards_parts[index + 1]} {rewards_parts[index + 2]}") - return objects - - @staticmethod - def parse_stardew_bundle_items(string_objects: str) -> List[BundleItem]: - bundle_items = [] - parts = string_objects.split(" ") - for index in range(0, len(parts), 3): - item_id = int(parts[index]) - bundle_item = BundleItem(all_bundle_items_by_id[item_id].item, - int(parts[index + 1]), - int(parts[index + 2])) - bundle_items.append(bundle_item) - return bundle_items - - # Shuffling the Vault doesn't really work with the stardew system in place - # shuffle_vault_amongst_themselves(random, bundles) - - -def get_all_bundles(random: Random, logic: StardewLogic, randomization: BundleRandomization, price: BundlePrice) -> Dict[str, Bundle]: - bundles = {} - for bundle_key in vanilla_bundles: - bundle_value = vanilla_bundles[bundle_key] - bundle = Bundle(bundle_key, bundle_value) - bundles[bundle.get_name_with_bundle()] = bundle - - if randomization == BundleRandomization.option_thematic: - shuffle_bundles_thematically(random, bundles) - elif randomization == BundleRandomization.option_shuffled: - shuffle_bundles_completely(random, logic, bundles) - - price_difference = 0 - if price == BundlePrice.option_very_cheap: - price_difference = -2 - elif price == BundlePrice.option_cheap: - price_difference = -1 - elif price == BundlePrice.option_expensive: - price_difference = 1 - - for bundle_key in bundles: - bundles[bundle_key].remove_rewards() - bundles[bundle_key].change_number_required(price_difference) - - return bundles - - -def shuffle_bundles_completely(random: Random, logic: StardewLogic, bundles: Dict[str, Bundle]): - total_required_item_number = sum(len(bundle.requirements) for bundle in bundles.values()) - quality_crops_items_set = set(quality_crops_items) - all_bundle_items_without_quality_and_money = [item - for item in all_bundle_items_except_money - if item not in quality_crops_items_set] + \ - random.sample(quality_crops_items, 10) - choices = random.sample(all_bundle_items_without_quality_and_money, total_required_item_number - 4) - - items_sorted = sorted(choices, key=lambda x: logic.registry.item_rules[x.item.name].get_difficulty()) - - keys = sorted(bundles.keys()) - random.shuffle(keys) - - for key in keys: - if not bundles[key].original_name.endswith("00g"): - items_sorted = bundles[key].assign_requirements(items_sorted) - - -def shuffle_bundles_thematically(random: Random, bundles: Dict[str, Bundle]): - shuffle_crafts_room_bundle_thematically(random, bundles) - shuffle_pantry_bundle_thematically(random, bundles) - shuffle_fish_tank_thematically(random, bundles) - shuffle_boiler_room_thematically(random, bundles) - shuffle_bulletin_board_thematically(random, bundles) - shuffle_abandoned_jojamart_thematically(random, bundles) - - -def shuffle_crafts_room_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Spring Foraging Bundle"].randomize_requirements(random, spring_foraging_items) - bundles["Summer Foraging Bundle"].randomize_requirements(random, summer_foraging_items) - bundles["Fall Foraging Bundle"].randomize_requirements(random, fall_foraging_items) - bundles["Winter Foraging Bundle"].randomize_requirements(random, winter_foraging_items) - bundles["Exotic Foraging Bundle"].randomize_requirements(random, exotic_foraging_items) - bundles["Construction Bundle"].randomize_requirements(random, construction_items) - - -def shuffle_pantry_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Spring Crops Bundle"].randomize_requirements(random, spring_crop_items) - bundles["Summer Crops Bundle"].randomize_requirements(random, summer_crops_items) - bundles["Fall Crops Bundle"].randomize_requirements(random, fall_crops_items) - bundles["Quality Crops Bundle"].randomize_requirements(random, quality_crops_items) - bundles["Animal Bundle"].randomize_requirements(random, animal_product_items) - bundles["Artisan Bundle"].randomize_requirements(random, artisan_goods_items) - - -def shuffle_fish_tank_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["River Fish Bundle"].randomize_requirements(random, river_fish_items) - bundles["Lake Fish Bundle"].randomize_requirements(random, lake_fish_items) - bundles["Ocean Fish Bundle"].randomize_requirements(random, ocean_fish_items) - bundles["Night Fishing Bundle"].randomize_requirements(random, night_fish_items) - bundles["Crab Pot Bundle"].randomize_requirements(random, crab_pot_items) - bundles["Specialty Fish Bundle"].randomize_requirements(random, specialty_fish_items) - - -def shuffle_boiler_room_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Blacksmith's Bundle"].randomize_requirements(random, blacksmith_items) - bundles["Geologist's Bundle"].randomize_requirements(random, geologist_items) - bundles["Adventurer's Bundle"].randomize_requirements(random, adventurer_items) - - -def shuffle_bulletin_board_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Chef's Bundle"].randomize_requirements(random, chef_items) - bundles["Dye Bundle"].randomize_requirements(random, dye_items) - bundles["Field Research Bundle"].randomize_requirements(random, field_research_items) - bundles["Fodder Bundle"].randomize_requirements(random, fodder_items) - bundles["Enchanter's Bundle"].randomize_requirements(random, enchanter_items) - - -def shuffle_abandoned_jojamart_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["The Missing Bundle"].randomize_requirements(random, missing_bundle_items) - - -def shuffle_vault_amongst_themselves(random: Random, bundles: Dict[str, Bundle]): - bundles["2,500g Bundle"].randomize_requirements(random, vault_bundle_items) - bundles["5,000g Bundle"].randomize_requirements(random, vault_bundle_items) - bundles["10,000g Bundle"].randomize_requirements(random, vault_bundle_items) - bundles["25,000g Bundle"].randomize_requirements(random, vault_bundle_items) diff --git a/worlds/stardew_valley/bundles/__init__.py b/worlds/stardew_valley/bundles/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py new file mode 100644 index 000000000000..2eb1570c9a27 --- /dev/null +++ b/worlds/stardew_valley/bundles/bundle.py @@ -0,0 +1,109 @@ +class Bundle: + room: str + sprite: str + original_name: str + name: str + rewards: List[str] + requirements: List[BundleItem] + color: str + number_required: int + + def __init__(self, key: str, value: str): + key_parts = key.split("/") + self.room = key_parts[0] + self.sprite = key_parts[1] + + value_parts = value.split("/") + self.original_name = value_parts[0] + self.name = value_parts[0] + self.rewards = self.parse_stardew_objects(value_parts[1]) + self.requirements = self.parse_stardew_bundle_items(value_parts[2]) + self.color = value_parts[3] + if len(value_parts) > 4: + self.number_required = int(value_parts[4]) + else: + self.number_required = len(self.requirements) + + def __repr__(self): + return f"{self.original_name} -> {repr(self.requirements)}" + + def get_name_with_bundle(self) -> str: + return f"{self.original_name} Bundle" + + def to_pair(self) -> (str, str): + key = f"{self.room}/{self.sprite}" + str_rewards = "" + for reward in self.rewards: + str_rewards += f" {reward}" + str_rewards = str_rewards.strip() + str_requirements = "" + for requirement in self.requirements: + str_requirements += f" {requirement.item.item_id} {requirement.amount} {requirement.quality}" + str_requirements = str_requirements.strip() + value = f"{self.name}/{str_rewards}/{str_requirements}/{self.color}/{self.number_required}" + return key, value + + def remove_rewards(self): + self.rewards = [] + + def change_number_required(self, difference: int): + self.number_required = min(len(self.requirements), max(1, self.number_required + difference)) + if len(self.requirements) == 1 and self.requirements[0].item.item_id == -1: + one_fifth = self.requirements[0].amount / 5 + new_amount = int(self.requirements[0].amount + (difference * one_fifth)) + self.requirements[0] = BundleItem.money_bundle(new_amount) + thousand_amount = int(new_amount / 1000) + dollar_amount = str(new_amount % 1000) + while len(dollar_amount) < 3: + dollar_amount = f"0{dollar_amount}" + self.name = f"{thousand_amount},{dollar_amount}g" + + def randomize_requirements(self, random: Random, + potential_requirements: Union[List[BundleItem], List[List[BundleItem]]]): + if not potential_requirements: + return + + number_to_generate = len(self.requirements) + self.requirements.clear() + if number_to_generate > len(potential_requirements): + choices: Union[BundleItem, List[BundleItem]] = random.choices(potential_requirements, k=number_to_generate) + else: + choices: Union[BundleItem, List[BundleItem]] = random.sample(potential_requirements, number_to_generate) + for choice in choices: + if isinstance(choice, BundleItem): + self.requirements.append(choice) + else: + self.requirements.append(random.choice(choice)) + + def assign_requirements(self, new_requirements: List[BundleItem]) -> List[BundleItem]: + number_to_generate = len(self.requirements) + self.requirements.clear() + for requirement in new_requirements: + self.requirements.append(requirement) + if len(self.requirements) >= number_to_generate: + return new_requirements[number_to_generate:] + + @staticmethod + def parse_stardew_objects(string_objects: str) -> List[str]: + objects = [] + if len(string_objects) < 5: + return objects + rewards_parts = string_objects.split(" ") + for index in range(0, len(rewards_parts), 3): + objects.append(f"{rewards_parts[index]} {rewards_parts[index + 1]} {rewards_parts[index + 2]}") + return objects + + @staticmethod + def parse_stardew_bundle_items(string_objects: str) -> List[BundleItem]: + bundle_items = [] + parts = string_objects.split(" ") + for index in range(0, len(parts), 3): + item_id = int(parts[index]) + bundle_item = BundleItem(all_bundle_items_by_id[item_id].item, + int(parts[index + 1]), + int(parts[index + 2])) + bundle_items.append(bundle_item) + return bundle_items + + # Shuffling the Vault doesn't really work with the stardew system in place + # shuffle_vault_amongst_themselves(random, bundles) \ No newline at end of file diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py new file mode 100644 index 000000000000..3e49d35095ed --- /dev/null +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -0,0 +1,52 @@ +from dataclasses import dataclass + +from ..strings.crop_names import Fruit +from ..strings.quality_names import Quality + + +@dataclass(frozen=True) +class BundleItem: + item: str + amount: int = 1 + quality: str = Quality.basic + + @staticmethod + def money_bundle(amount: int): + return BundleItem("Money", amount) + + def as_amount(self, amount: int): + return BundleItem(self.item, amount, self.quality) + + def as_quality(self, quality: str): + return BundleItem(self.item, self.amount, quality) + + def as_silver_quality(self): + return self.as_quality(Quality.silver) + + def as_gold_quality(self): + return self.as_quality(Quality.gold) + + def as_quality_crop(self): + amount = 5 + difficult_crops = [Fruit.sweet_gem_berry, Fruit.ancient_fruit] + if self.item in difficult_crops: + amount = 1 + return self.as_gold_quality().as_amount(amount) + + def is_gold_quality(self) -> bool: + return self.quality == Quality.gold or self.quality == Quality.iridium + + def __repr__(self): + quality = "" if self.quality == Quality.basic else self.quality + return f"{self.amount} {quality} {self.item}" + + @property + def requires_island(self) -> bool: + return False + + +class IslandBundleItem(BundleItem): + + @property + def requires_island(self) -> bool: + return True diff --git a/worlds/stardew_valley/bundles/bundles.py b/worlds/stardew_valley/bundles/bundles.py new file mode 100644 index 000000000000..aac518f21579 --- /dev/null +++ b/worlds/stardew_valley/bundles/bundles.py @@ -0,0 +1,113 @@ +from random import Random +from typing import List, Dict, Union + +from worlds.stardew_valley.logic.logic import StardewLogic +from worlds.stardew_valley.data.bundle_data import * +from worlds.stardew_valley.options import BundleRandomization, BundlePrice + + +def get_all_bundles(random: Random, logic: StardewLogic, randomization: BundleRandomization, price: BundlePrice) -> Dict[str, Bundle]: + bundles = {} + for bundle_key in vanilla_bundles: + bundle_value = vanilla_bundles[bundle_key] + bundle = Bundle(bundle_key, bundle_value) + bundles[bundle.get_name_with_bundle()] = bundle + + if randomization == BundleRandomization.option_thematic: + shuffle_bundles_thematically(random, bundles) + elif randomization == BundleRandomization.option_shuffled: + shuffle_bundles_completely(random, logic, bundles) + + price_difference = 0 + if price == BundlePrice.option_very_cheap: + price_difference = -2 + elif price == BundlePrice.option_cheap: + price_difference = -1 + elif price == BundlePrice.option_expensive: + price_difference = 1 + + for bundle_key in bundles: + bundles[bundle_key].remove_rewards() + bundles[bundle_key].change_number_required(price_difference) + + return bundles + + +def shuffle_bundles_completely(random: Random, logic: StardewLogic, bundles: Dict[str, Bundle]): + total_required_item_number = sum(len(bundle.requirements) for bundle in bundles.values()) + quality_crops_items_set = set(quality_crops_items) + all_bundle_items_without_quality_and_money = [item + for item in all_bundle_items_except_money + if item not in quality_crops_items_set] + \ + random.sample(quality_crops_items, 10) + choices = random.sample(all_bundle_items_without_quality_and_money, total_required_item_number - 4) + + items_sorted = sorted(choices, key=lambda x: logic.item_rules[x.item.name].get_difficulty()) + + keys = sorted(bundles.keys()) + random.shuffle(keys) + + for key in keys: + if not bundles[key].original_name.endswith("00g"): + items_sorted = bundles[key].assign_requirements(items_sorted) + + +def shuffle_bundles_thematically(random: Random, bundles: Dict[str, Bundle]): + shuffle_crafts_room_bundle_thematically(random, bundles) + shuffle_pantry_bundle_thematically(random, bundles) + shuffle_fish_tank_thematically(random, bundles) + shuffle_boiler_room_thematically(random, bundles) + shuffle_bulletin_board_thematically(random, bundles) + shuffle_abandoned_jojamart_thematically(random, bundles) + + +def shuffle_crafts_room_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["Spring Foraging Bundle"].randomize_requirements(random, spring_foraging_items) + bundles["Summer Foraging Bundle"].randomize_requirements(random, summer_foraging_items) + bundles["Fall Foraging Bundle"].randomize_requirements(random, fall_foraging_items) + bundles["Winter Foraging Bundle"].randomize_requirements(random, winter_foraging_items) + bundles["Exotic Foraging Bundle"].randomize_requirements(random, exotic_foraging_items) + bundles["Construction Bundle"].randomize_requirements(random, construction_items) + + +def shuffle_pantry_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["Spring Crops Bundle"].randomize_requirements(random, spring_crop_items) + bundles["Summer Crops Bundle"].randomize_requirements(random, summer_crops_items) + bundles["Fall Crops Bundle"].randomize_requirements(random, fall_crops_items) + bundles["Quality Crops Bundle"].randomize_requirements(random, quality_crops_items) + bundles["Animal Bundle"].randomize_requirements(random, animal_product_items) + bundles["Artisan Bundle"].randomize_requirements(random, artisan_goods_items) + + +def shuffle_fish_tank_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["River Fish Bundle"].randomize_requirements(random, river_fish_items) + bundles["Lake Fish Bundle"].randomize_requirements(random, lake_fish_items) + bundles["Ocean Fish Bundle"].randomize_requirements(random, ocean_fish_items) + bundles["Night Fishing Bundle"].randomize_requirements(random, night_fish_items) + bundles["Crab Pot Bundle"].randomize_requirements(random, crab_pot_items) + bundles["Specialty Fish Bundle"].randomize_requirements(random, specialty_fish_items) + + +def shuffle_boiler_room_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["Blacksmith's Bundle"].randomize_requirements(random, blacksmith_items) + bundles["Geologist's Bundle"].randomize_requirements(random, geologist_items) + bundles["Adventurer's Bundle"].randomize_requirements(random, adventurer_items) + + +def shuffle_bulletin_board_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["Chef's Bundle"].randomize_requirements(random, chef_items) + bundles["Dye Bundle"].randomize_requirements(random, dye_items) + bundles["Field Research Bundle"].randomize_requirements(random, field_research_items) + bundles["Fodder Bundle"].randomize_requirements(random, fodder_items) + bundles["Enchanter's Bundle"].randomize_requirements(random, enchanter_items) + + +def shuffle_abandoned_jojamart_thematically(random: Random, bundles: Dict[str, Bundle]): + bundles["The Missing Bundle"].randomize_requirements(random, missing_bundle_items) + + +def shuffle_vault_amongst_themselves(random: Random, bundles: Dict[str, Bundle]): + bundles["2,500g Bundle"].randomize_requirements(random, vault_bundle_items) + bundles["5,000g Bundle"].randomize_requirements(random, vault_bundle_items) + bundles["10,000g Bundle"].randomize_requirements(random, vault_bundle_items) + bundles["25,000g Bundle"].randomize_requirements(random, vault_bundle_items) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 03910b836c9c..d5493dc1ec18 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -1,372 +1,414 @@ -from dataclasses import dataclass - from . import fish_data -from .common_data import quality_dict -from .game_item import GameItem from .museum_data import Mineral +from ..bundles.bundle_item import BundleItem, IslandBundleItem +from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.crop_names import Fruit, Vegetable -from ..strings.fish_names import Fish -from ..strings.food_names import Beverage +from ..strings.fish_names import Fish, WaterItem, Trash +from ..strings.flower_names import Flower +from ..strings.food_names import Beverage, Meal +from ..strings.forageable_names import Forageable +from ..strings.geode_names import Geode +from ..strings.gift_names import Gift +from ..strings.material_names import Material +from ..strings.metal_names import MetalBar, Artifact, Fossil +from ..strings.monster_drop_names import Loot from ..strings.seed_names import Seed +wild_horseradish = BundleItem(Forageable.wild_horseradish) +daffodil = BundleItem(Forageable.daffodil) +leek = BundleItem(Forageable.leek) +dandelion = BundleItem(Forageable.dandelion) +morel = BundleItem(Forageable.morel) +common_mushroom = BundleItem(Forageable.common_mushroom) +salmonberry = BundleItem(Forageable.salmonberry) +spring_onion = BundleItem(Forageable.spring_onion) + +grape = BundleItem(Fruit.grape) +spice_berry = BundleItem(Forageable.spice_berry) +sweet_pea = BundleItem(Forageable.sweet_pea) +red_mushroom = BundleItem(Forageable.red_mushroom) +fiddlehead_fern = BundleItem(Forageable.fiddlehead_fern) + +wild_plum = BundleItem(Forageable.wild_plum) +hazelnut = BundleItem(Forageable.hazelnut) +blackberry = BundleItem(Forageable.blackberry) +chanterelle = BundleItem(Forageable.chanterelle) + +winter_root = BundleItem(Forageable.winter_root) +crystal_fruit = BundleItem(Forageable.crystal_fruit) +snow_yam = BundleItem(Forageable.snow_yam) +crocus = BundleItem(Forageable.crocus) +holly = BundleItem(Forageable.holly) + +coconut = BundleItem(Forageable.coconut) +cactus_fruit = BundleItem(Forageable.cactus_fruit) +cave_carrot = BundleItem(Forageable.cave_carrot) +purple_mushroom = BundleItem(Forageable.purple_mushroom) +maple_syrup = BundleItem(ArtisanGood.maple_syrup) +oak_resin = BundleItem(ArtisanGood.oak_resin) +pine_tar = BundleItem(ArtisanGood.pine_tar) +nautilus_shell = BundleItem(WaterItem.nautilus_shell) +coral = BundleItem(WaterItem.coral) +sea_urchin = BundleItem(WaterItem.sea_urchin) +rainbow_shell = BundleItem(Forageable.rainbow_shell) +clam = BundleItem(fish_data.clam) +cockle = BundleItem(fish_data.cockle) +mussel = BundleItem(fish_data.mussel) +oyster = BundleItem(fish_data.oyster) +seaweed = BundleItem(WaterItem.seaweed) + +wood = BundleItem(Material.wood, 99) +stone = BundleItem(Material.stone, 99) +hardwood = BundleItem(Material.hardwood, 10) +clay = BundleItem(Material.clay, 10) +fiber = BundleItem(Material.fiber, 99) + +blue_jazz = BundleItem(Flower.blue_jazz) +cauliflower = BundleItem(Vegetable.cauliflower) +green_bean = BundleItem(Vegetable.green_bean) +kale = BundleItem(Vegetable.kale) +parsnip = BundleItem(Vegetable.parsnip) +potato = BundleItem(Vegetable.potato) +strawberry = BundleItem(Fruit.strawberry) +tulip = BundleItem(Flower.tulip) +unmilled_rice = BundleItem(Vegetable.unmilled_rice) +coffee_bean = BundleItem(Seed.coffee) +garlic = BundleItem(Vegetable.garlic) +blueberry = BundleItem(Fruit.blueberry) +corn = BundleItem(Vegetable.corn) +hops = BundleItem(Vegetable.hops) +hot_pepper = BundleItem(Fruit.hot_pepper) +melon = BundleItem(Fruit.melon) +poppy = BundleItem(Flower.poppy) +radish = BundleItem(Vegetable.radish) +summer_spangle = BundleItem(Flower.summer_spangle) +sunflower = BundleItem(Flower.sunflower) +tomato = BundleItem(Vegetable.tomato) +wheat = BundleItem(Vegetable.wheat) +hay = BundleItem(Forageable.hay) +amaranth = BundleItem(Vegetable.amaranth) +bok_choy = BundleItem(Vegetable.bok_choy) +cranberries = BundleItem(Fruit.cranberries) +eggplant = BundleItem(Vegetable.eggplant) +fairy_rose = BundleItem(Flower.fairy_rose) +pumpkin = BundleItem(Vegetable.pumpkin) +yam = BundleItem(Vegetable.yam) +sweet_gem_berry = BundleItem(Fruit.sweet_gem_berry) +rhubarb = BundleItem(Fruit.rhubarb) +beet = BundleItem(Vegetable.beet) +red_cabbage = BundleItem(Vegetable.red_cabbage) +starfruit = BundleItem(Fruit.starfruit) +artichoke = BundleItem(Vegetable.artichoke) + +egg = BundleItem(AnimalProduct.egg) +large_egg = BundleItem(AnimalProduct.large_egg) +brown_egg = BundleItem(AnimalProduct.brown_egg) +large_brown_egg = BundleItem(AnimalProduct.large_brown_egg) +wool = BundleItem(AnimalProduct.wool) +milk = BundleItem(AnimalProduct.milk) +large_milk = BundleItem(AnimalProduct.large_milk) +goat_milk = BundleItem(AnimalProduct.goat_milk) +large_goat_milk = BundleItem(AnimalProduct.large_goat_milk) +truffle = BundleItem(AnimalProduct.truffle) +duck_feather = BundleItem(AnimalProduct.duck_feather) +duck_egg = BundleItem(AnimalProduct.duck_egg) +rabbit_foot = BundleItem(AnimalProduct.rabbit_foot) + +truffle_oil = BundleItem(ArtisanGood.truffle_oil) +cloth = BundleItem(ArtisanGood.cloth) +goat_cheese = BundleItem(ArtisanGood.goat_cheese) +cheese = BundleItem(ArtisanGood.cheese) +honey = BundleItem(ArtisanGood.honey) +beer = BundleItem(Beverage.beer) +juice = BundleItem(ArtisanGood.juice) +mead = BundleItem(ArtisanGood.mead) +pale_ale = BundleItem(ArtisanGood.pale_ale) +wine = BundleItem(ArtisanGood.wine) +jelly = BundleItem(ArtisanGood.jelly) +pickles = BundleItem(ArtisanGood.pickles) +caviar = BundleItem(ArtisanGood.caviar) +aged_roe = BundleItem(ArtisanGood.aged_roe) +coffee = BundleItem(Beverage.coffee) +green_tea = BundleItem(ArtisanGood.green_tea) +apple = BundleItem(Fruit.apple) +apricot = BundleItem(Fruit.apricot) +orange = BundleItem(Fruit.orange) +peach = BundleItem(Fruit.peach) +pomegranate = BundleItem(Fruit.pomegranate) +cherry = BundleItem(Fruit.cherry) +lobster = BundleItem(fish_data.lobster) +crab = BundleItem(fish_data.crab) +shrimp = BundleItem(fish_data.shrimp) +crayfish = BundleItem(fish_data.crayfish) +snail = BundleItem(fish_data.snail) +periwinkle = BundleItem(fish_data.periwinkle) +trash = BundleItem(Trash.trash) +driftwood = BundleItem(Trash.driftwood) +soggy_newspaper = BundleItem(Trash.soggy_newspaper) +broken_cd = BundleItem(Trash.broken_cd) +broken_glasses = BundleItem(Trash.broken_glasses) + +chub = BundleItem(fish_data.chub) +catfish = BundleItem(fish_data.catfish) +rainbow_trout = BundleItem(fish_data.rainbow_trout) +lingcod = BundleItem(fish_data.lingcod) +walleye = BundleItem(fish_data.walleye) +perch = BundleItem(fish_data.perch) +pike = BundleItem(fish_data.pike) +bream = BundleItem(fish_data.bream) +salmon = BundleItem(fish_data.salmon) +sunfish = BundleItem(fish_data.sunfish) +tiger_trout = BundleItem(fish_data.tiger_trout) +shad = BundleItem(fish_data.shad) +smallmouth_bass = BundleItem(fish_data.smallmouth_bass) +dorado = BundleItem(fish_data.dorado) +carp = BundleItem(fish_data.carp) +midnight_carp = BundleItem(fish_data.midnight_carp) +largemouth_bass = BundleItem(fish_data.largemouth_bass) +sturgeon = BundleItem(fish_data.sturgeon) +bullhead = BundleItem(fish_data.bullhead) +tilapia = BundleItem(fish_data.tilapia) +pufferfish = BundleItem(fish_data.pufferfish) +tuna = BundleItem(fish_data.tuna) +super_cucumber = BundleItem(fish_data.super_cucumber) +flounder = BundleItem(fish_data.flounder) +anchovy = BundleItem(fish_data.anchovy) +sardine = BundleItem(fish_data.sardine) +red_mullet = BundleItem(fish_data.red_mullet) +herring = BundleItem(fish_data.herring) +eel = BundleItem(fish_data.eel) +octopus = BundleItem(fish_data.octopus) +red_snapper = BundleItem(fish_data.red_snapper) +squid = BundleItem(fish_data.squid) +sea_cucumber = BundleItem(fish_data.sea_cucumber) +albacore = BundleItem(fish_data.albacore) +halibut = BundleItem(fish_data.halibut) +scorpion_carp = BundleItem(fish_data.scorpion_carp) +sandfish = BundleItem(fish_data.sandfish) +woodskip = BundleItem(fish_data.woodskip) +lava_eel = BundleItem(fish_data.lava_eel) +ice_pip = BundleItem(fish_data.ice_pip) +stonefish = BundleItem(fish_data.stonefish) +ghostfish = BundleItem(fish_data.ghostfish) + +wilted_bouquet = BundleItem(Gift.wilted_bouquet) +copper_bar = BundleItem(MetalBar.copper) +iron_Bar = BundleItem(MetalBar.iron) +gold_bar = BundleItem(MetalBar.gold) +iridium_bar = BundleItem(MetalBar.iridium) +refined_quartz = BundleItem(MetalBar.quartz) +coal = BundleItem(Material.coal, 5) + +quartz = BundleItem(Mineral.quartz) +fire_quartz = BundleItem(Mineral.fire_quartz) +frozen_tear = BundleItem(Mineral.frozen_tear) +earth_crystal = BundleItem(Mineral.earth_crystal) +emerald = BundleItem(Mineral.emerald) +aquamarine = BundleItem(Mineral.aquamarine) +ruby = BundleItem(Mineral.ruby) +amethyst = BundleItem(Mineral.amethyst) +topaz = BundleItem(Mineral.topaz) +jade = BundleItem(Mineral.jade) + +slime = BundleItem(Loot.slime, 99) +bug_meat = BundleItem(Loot.bug_meat, 10) +bat_wing = BundleItem(Loot.bat_wing, 10) +solar_essence = BundleItem(Loot.solar_essence) +void_essence = BundleItem(Loot.void_essence) + +maki_roll = BundleItem(Meal.maki_roll) +fried_egg = BundleItem(Meal.fried_egg) +omelet = BundleItem(Meal.omelet) +pizza = BundleItem(Meal.pizza) +hashbrowns = BundleItem(Meal.hashbrowns) +pancakes = BundleItem(Meal.pancakes) +bread = BundleItem(Meal.bread) +tortilla = BundleItem(Meal.tortilla) +triple_shot_espresso = BundleItem(Beverage.triple_shot_espresso) +farmer_s_lunch = BundleItem(Meal.farmer_lunch) +survival_burger = BundleItem(Meal.survival_burger) +dish_o_the_sea = BundleItem(Meal.dish_o_the_sea) +miner_s_treat = BundleItem(Meal.miners_treat) +roots_platter = BundleItem(Meal.roots_platter) +salad = BundleItem(Meal.salad) +cheese_cauliflower = BundleItem(Meal.cheese_cauliflower) +parsnip_soup = BundleItem(Meal.parsnip_soup) +fried_mushroom = BundleItem(Meal.fried_mushroom) +salmon_dinner = BundleItem(Meal.salmon_dinner) +pepper_poppers = BundleItem(Meal.pepper_poppers) +spaghetti = BundleItem(Meal.spaghetti) +sashimi = BundleItem(Meal.sashimi) +blueberry_tart = BundleItem(Meal.blueberry_tart) +algae_soup = BundleItem(Meal.algae_soup) +pale_broth = BundleItem(Meal.pale_broth) +chowder = BundleItem(Meal.chowder) +green_algae = BundleItem(WaterItem.green_algae) +white_algae = BundleItem(WaterItem.white_algae) +geode = BundleItem(Geode.geode) +frozen_geode = BundleItem(Geode.frozen) +magma_geode = BundleItem(Geode.magma) +omni_geode = BundleItem(Geode.omni) +sap = BundleItem(Material.sap) + +dwarf_scroll_1 = BundleItem(Artifact.dwarf_scroll_i) +dwarf_scroll_2 = BundleItem(Artifact.dwarf_scroll_ii) +dwarf_scroll_3 = BundleItem(Artifact.dwarf_scroll_iii) +dwarf_scroll_4 = BundleItem(Artifact.dwarf_scroll_iv) +elvish_jewelry = BundleItem(Artifact.elvish_jewelry) +ancient_drum = BundleItem(Artifact.ancient_drum) +dried_starfish = BundleItem(Fossil.dried_starfish) + +dinosaur_mayo = BundleItem(ArtisanGood.dinosaur_mayonnaise) +void_mayo = BundleItem(ArtisanGood.void_mayonnaise) +prismatic_shard = BundleItem(Mineral.prismatic_shard) +diamond = BundleItem(Mineral.diamond) +ancient_fruit = BundleItem(Fruit.ancient_fruit) +void_salmon = BundleItem(Fish.void_salmon) +tea_leaves = BundleItem(Vegetable.tea_leaves) +blobfish = BundleItem(Fish.blobfish) + +ginger = IslandBundleItem(Forageable.ginger) +magma_cap = IslandBundleItem(Forageable.magma_cap) + +spring_foraging_items_vanilla = [wild_horseradish, daffodil, leek, dandelion] +spring_foraging_items_thematic = [*spring_foraging_items_vanilla, spring_onion, salmonberry, morel] +spring_foraging_bundle_vanilla = Bundle() + +summer_foraging_items_vanilla = [grape, spice_berry, sweet_pea] +summer_foraging_items_thematic = [*summer_foraging_items_vanilla, fiddlehead_fern, red_mushroom, rainbow_shell] + +fall_foraging_items_vanilla = [common_mushroom, wild_plum, hazelnut, blackberry] +fall_foraging_items_thematic = [*fall_foraging_items_vanilla, chanterelle] + +winter_foraging_items_vanilla = [winter_root, crystal_fruit, snow_yam, crocus] +winter_foraging_items_thematic = [*winter_foraging_items_vanilla, holly, nautilus_shell] + +construction_items_vanilla = [wood, stone, hardwood] +construction_items_thematic = [*construction_items_vanilla, clay, fiber, sap.as_amount(50)] + +exotic_foraging_items_vanilla = [coconut, cactus_fruit, cave_carrot, red_mushroom, purple_mushroom, maple_syrup, oak_resin, pine_tar, morel] +exotic_foraging_items_thematic = [*exotic_foraging_items_vanilla, coral, sea_urchin, clam, cockle, mussel, oyster, seaweed] + +beach_foraging_items = [nautilus_shell, coral, sea_urchin, rainbow_shell, clam, cockle, mussel, oyster, seaweed] +mines_foraging_items = [quartz, earth_crystal, frozen_tear, fire_quartz, red_mushroom, purple_mushroom, cave_carrot] +desert_foraging_items = [cactus_fruit.as_gold_quality(), cactus_fruit.as_amount(5), coconut.as_gold_quality(), coconut.as_amount(5)] +island_foraging_items = [ginger.as_amount(5), magma_cap.as_gold_quality(), magma_cap.as_amount(5)] +sticky_items = [sap.as_amount(500), sap.as_amount(500)] +wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] +quality_foraging_items = sorted({item.as_gold_quality().as_amount(1) + for item in + [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, + *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, *island_foraging_items]}) + +spring_crop_items_vanilla = [parsnip, green_bean, cauliflower, potato] +spring_crop_items_thematic = [*spring_crop_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice] + +summer_crops_items_vanilla = [tomato, hot_pepper, blueberry, melon] +summer_crops_items_thematic = [*summer_crops_items_vanilla, corn, hops, poppy, radish, red_cabbage, starfruit, summer_spangle, sunflower, wheat] + +fall_crops_items_vanilla = [corn, eggplant, pumpkin, yam] +fall_crops_items_thematic = [*fall_crops_items_vanilla, amaranth, artichoke, beet, bok_choy, cranberries, fairy_rose, grape, sunflower, wheat, sweet_gem_berry] + +all_crops_items = sorted({*spring_crop_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) + +quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]] +quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items] + +animal_product_items_vanilla = [large_milk, large_brown_egg, large_egg, large_goat_milk, wool, duck_egg] +animal_product_items_thematic = [*animal_product_items_vanilla, egg, brown_egg, milk, goat_milk, truffle, duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg] + +artisan_goods_items_vanilla = [truffle_oil, cloth, goat_cheese, cheese, honey, jelly, apple, apricot, orange, peach, pomegranate, cherry] +artisan_goods_items_thematic = [*artisan_goods_items_vanilla, beer, juice, mead, pale_ale, wine, pickles, caviar, aged_roe, coffee, green_tea, banana, mango] + +# Where to put Tea Leaves and Fiber? +rare_crops_items = [ancient_fruit, sweet_gem_berry] +fish_farmer_items = [row.as_amount(15), aged_roe.as_amount(15), squid_ink] +garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose] +brewer_items = [mead, pale_ale, wine, juice, green_tea] +orchard_items = [apple, apricot, orange, peach, pomegranate, cherry, banana, mango] +island_crops_items = [pineapple, taro_root, banana, mango] + + +river_fish_items_vanilla = [sunfish, catfish, shad, tiger_trout] +river_fish_items_thematic = [*river_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, pike, bream, salmon, smallmouth_bass, dorado] + +lake_fish_items_vanilla = [largemouth_bass, carp, bullhead, sturgeon] +lake_fish_items_thematic = [*lake_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, midnight_carp] + +ocean_fish_items_vanilla = [sardine, tuna, red_snapper, tilapia] +ocean_fish_items_thematic = [*ocean_fish_items_vanilla, pufferfish, super_cucumber, flounder, anchovy, red_mullet, herring, eel, octopus, squid, sea_cucumber, albacore, halibut] + +night_fish_items_vanilla = [walleye, bream, eel] +night_fish_items_thematic = [*night_fish_items_vanilla, super_cucumber, squid, midnight_carp] + +specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip] +specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip, stonefish, void_salmon, stingray, spookfish, midnight_squid] + +crab_pot_items_vanilla = [lobster, crayfish, crab, cockle, mussel, shrimp, snail, periwinkle, oyster, clam] +crab_pot_items_thematic = [*crab_pot_items_vanilla, trash, driftwood, soggy_newspaper, broken_cd, broken_glasses] + +quality_fish_items = sorted({item.as_gold_quality() for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]}) +master_fisher_items = [lava_eel, scorpion_carp, octopus, blobfish, lingcod, ice_pip, super_cucumber, stingray, void_salmon, pufferfish] +legendary_fish_items = [angler, legend, mutant carp, crimsonfish, glacierfish] + + +blacksmith_items_vanilla = [copper_bar, iron_Bar, gold_bar] +blacksmith_items_thematic = [*blacksmith_items_vanilla, iridium_bar, refined_quartz.as_amount(3), wilted_bouquet] + +geologist_items_vanilla = [quartz, earth_crystal, frozen_tear, fire_quartz] +geologist_items_thematic = [*geologist_items_vanilla, emerald, aquamarine, ruby, amethyst, topaz, jade, diamond] + +adventurer_items_vanilla = [slime, bat_wing, solar_essence, void_essence] +adventurer_items_thematic = [*adventurer_items_vanilla, bug_meat, coal, bone_fragment.as_amount(10)] -@dataclass(frozen=True) -class BundleItem: - item: GameItem - amount: int - quality: int - - @staticmethod - def item_bundle(name: str, item_id: int, amount: int = 1, quality: int = 0): - return BundleItem(GameItem(name, item_id), amount, quality) - - @staticmethod - def money_bundle(amount: int): - return BundleItem.item_bundle("Money", -1, amount, 0) - - def as_amount(self, amount: int): - return BundleItem.item_bundle(self.item.name, self.item.item_id, amount, self.quality) - - def as_quality(self, quality: int): - return BundleItem.item_bundle(self.item.name, self.item.item_id, self.amount, quality) - - def as_silver_quality(self): - return self.as_quality(1) - - def as_gold_quality(self): - return self.as_quality(2) - - def as_quality_crop(self): - amount = 5 - difficult_crops = ["Sweet Gem Berry", "Ancient Fruit"] - if self.item.name in difficult_crops: - amount = 1 - return self.as_gold_quality().as_amount(amount) - - def is_gold_quality(self) -> bool: - return self.quality >= 2 - - def __repr__(self): - return f"{self.amount} {quality_dict[self.quality]} {self.item.name}" - - def __lt__(self, other): - return self.item < other.item - - -wild_horseradish = BundleItem.item_bundle("Wild Horseradish", 16) -daffodil = BundleItem.item_bundle("Daffodil", 18) -leek = BundleItem.item_bundle("Leek", 20) -dandelion = BundleItem.item_bundle("Dandelion", 22) -morel = BundleItem.item_bundle("Morel", 257) -common_mushroom = BundleItem.item_bundle("Common Mushroom", 404) -salmonberry = BundleItem.item_bundle("Salmonberry", 296) -spring_onion = BundleItem.item_bundle("Spring Onion", 399) - -grape = BundleItem.item_bundle("Grape", 398) -spice_berry = BundleItem.item_bundle("Spice Berry", 396) -sweet_pea = BundleItem.item_bundle("Sweet Pea", 402) -red_mushroom = BundleItem.item_bundle("Red Mushroom", 420) -fiddlehead_fern = BundleItem.item_bundle("Fiddlehead Fern", 259) - -wild_plum = BundleItem.item_bundle("Wild Plum", 406) -hazelnut = BundleItem.item_bundle("Hazelnut", 408) -blackberry = BundleItem.item_bundle("Blackberry", 410) -chanterelle = BundleItem.item_bundle("Chanterelle", 281) - -winter_root = BundleItem.item_bundle("Winter Root", 412) -crystal_fruit = BundleItem.item_bundle("Crystal Fruit", 414) -snow_yam = BundleItem.item_bundle("Snow Yam", 416) -crocus = BundleItem.item_bundle("Crocus", 418) -holly = BundleItem.item_bundle("Holly", 283) - -coconut = BundleItem.item_bundle("Coconut", 88) -cactus_fruit = BundleItem.item_bundle("Cactus Fruit", 90) -cave_carrot = BundleItem.item_bundle("Cave Carrot", 78) -purple_mushroom = BundleItem.item_bundle("Purple Mushroom", 422) -maple_syrup = BundleItem.item_bundle("Maple Syrup", 724) -oak_resin = BundleItem.item_bundle("Oak Resin", 725) -pine_tar = BundleItem.item_bundle("Pine Tar", 726) -nautilus_shell = BundleItem.item_bundle("Nautilus Shell", 392) -coral = BundleItem.item_bundle("Coral", 393) -sea_urchin = BundleItem.item_bundle("Sea Urchin", 397) -rainbow_shell = BundleItem.item_bundle("Rainbow Shell", 394) -clam = BundleItem(fish_data.clam, 1, 0) -cockle = BundleItem(fish_data.cockle, 1, 0) -mussel = BundleItem(fish_data.mussel, 1, 0) -oyster = BundleItem(fish_data.oyster, 1, 0) -seaweed = BundleItem.item_bundle("Seaweed", 152) - -wood = BundleItem.item_bundle("Wood", 388, 99, 0) -stone = BundleItem.item_bundle("Stone", 390, 99, 0) -hardwood = BundleItem.item_bundle("Hardwood", 709, 10, 0) -clay = BundleItem.item_bundle("Clay", 330, 10, 0) -fiber = BundleItem.item_bundle("Fiber", 771, 99, 0) - -blue_jazz = BundleItem.item_bundle("Blue Jazz", 597) -cauliflower = BundleItem.item_bundle("Cauliflower", 190) -green_bean = BundleItem.item_bundle("Green Bean", 188) -kale = BundleItem.item_bundle("Kale", 250) -parsnip = BundleItem.item_bundle("Parsnip", 24) -potato = BundleItem.item_bundle("Potato", 192) -strawberry = BundleItem.item_bundle("Strawberry", 400) -tulip = BundleItem.item_bundle("Tulip", 591) -unmilled_rice = BundleItem.item_bundle("Unmilled Rice", 271) -coffee_bean = BundleItem.item_bundle(Seed.coffee, 433) -garlic = BundleItem.item_bundle(Vegetable.garlic, 248) -blueberry = BundleItem.item_bundle("Blueberry", 258) -corn = BundleItem.item_bundle("Corn", 270) -hops = BundleItem.item_bundle("Hops", 304) -hot_pepper = BundleItem.item_bundle("Hot Pepper", 260) -melon = BundleItem.item_bundle("Melon", 254) -poppy = BundleItem.item_bundle("Poppy", 376) -radish = BundleItem.item_bundle("Radish", 264) -summer_spangle = BundleItem.item_bundle("Summer Spangle", 593) -sunflower = BundleItem.item_bundle("Sunflower", 421) -tomato = BundleItem.item_bundle("Tomato", 256) -wheat = BundleItem.item_bundle("Wheat", 262) -hay = BundleItem.item_bundle("Hay", 178) -amaranth = BundleItem.item_bundle("Amaranth", 300) -bok_choy = BundleItem.item_bundle("Bok Choy", 278) -cranberries = BundleItem.item_bundle("Cranberries", 282) -eggplant = BundleItem.item_bundle("Eggplant", 272) -fairy_rose = BundleItem.item_bundle("Fairy Rose", 595) -pumpkin = BundleItem.item_bundle("Pumpkin", 276) -yam = BundleItem.item_bundle("Yam", 280) -sweet_gem_berry = BundleItem.item_bundle("Sweet Gem Berry", 417) -rhubarb = BundleItem.item_bundle("Rhubarb", 252) -beet = BundleItem.item_bundle("Beet", 284) -red_cabbage = BundleItem.item_bundle("Red Cabbage", 266) -starfruit = BundleItem.item_bundle(Fruit.starfruit, 268) -artichoke = BundleItem.item_bundle("Artichoke", 274) - -egg = BundleItem.item_bundle("Egg", 176) -large_egg = BundleItem.item_bundle("Large Egg", 174) -brown_egg = BundleItem.item_bundle("Egg (Brown)", 180) -large_brown_egg = BundleItem.item_bundle("Large Egg (Brown)", 182) -wool = BundleItem.item_bundle("Wool", 440) -milk = BundleItem.item_bundle("Milk", 184) -large_milk = BundleItem.item_bundle("Large Milk", 186) -goat_milk = BundleItem.item_bundle("Goat Milk", 436) -large_goat_milk = BundleItem.item_bundle("Large Goat Milk", 438) -truffle = BundleItem.item_bundle("Truffle", 430) -duck_feather = BundleItem.item_bundle("Duck Feather", 444) -duck_egg = BundleItem.item_bundle("Duck Egg", 442) -rabbit_foot = BundleItem.item_bundle("Rabbit's Foot", 446) - -truffle_oil = BundleItem.item_bundle("Truffle Oil", 432) -cloth = BundleItem.item_bundle("Cloth", 428) -goat_cheese = BundleItem.item_bundle("Goat Cheese", 426) -cheese = BundleItem.item_bundle("Cheese", 424) -honey = BundleItem.item_bundle("Honey", 340) -beer = BundleItem.item_bundle("Beer", 346) -juice = BundleItem.item_bundle("Juice", 350) -mead = BundleItem.item_bundle("Mead", 459) -pale_ale = BundleItem.item_bundle("Pale Ale", 303) -wine = BundleItem.item_bundle("Wine", 348) -jelly = BundleItem.item_bundle("Jelly", 344) -pickles = BundleItem.item_bundle("Pickles", 342) -caviar = BundleItem.item_bundle("Caviar", 445) -aged_roe = BundleItem.item_bundle("Aged Roe", 447) -coffee = BundleItem.item_bundle(Beverage.coffee, 395) -green_tea = BundleItem.item_bundle(ArtisanGood.green_tea, 614) -apple = BundleItem.item_bundle("Apple", 613) -apricot = BundleItem.item_bundle("Apricot", 634) -orange = BundleItem.item_bundle("Orange", 635) -peach = BundleItem.item_bundle("Peach", 636) -pomegranate = BundleItem.item_bundle("Pomegranate", 637) -cherry = BundleItem.item_bundle("Cherry", 638) -lobster = BundleItem(fish_data.lobster, 1, 0) -crab = BundleItem(fish_data.crab, 1, 0) -shrimp = BundleItem(fish_data.shrimp, 1, 0) -crayfish = BundleItem(fish_data.crayfish, 1, 0) -snail = BundleItem(fish_data.snail, 1, 0) -periwinkle = BundleItem(fish_data.periwinkle, 1, 0) -trash = BundleItem.item_bundle("Trash", 168) -driftwood = BundleItem.item_bundle("Driftwood", 169) -soggy_newspaper = BundleItem.item_bundle("Soggy Newspaper", 172) -broken_cd = BundleItem.item_bundle("Broken CD", 171) -broken_glasses = BundleItem.item_bundle("Broken Glasses", 170) - -chub = BundleItem(fish_data.chub, 1, 0) -catfish = BundleItem(fish_data.catfish, 1, 0) -rainbow_trout = BundleItem(fish_data.rainbow_trout, 1, 0) -lingcod = BundleItem(fish_data.lingcod, 1, 0) -walleye = BundleItem(fish_data.walleye, 1, 0) -perch = BundleItem(fish_data.perch, 1, 0) -pike = BundleItem(fish_data.pike, 1, 0) -bream = BundleItem(fish_data.bream, 1, 0) -salmon = BundleItem(fish_data.salmon, 1, 0) -sunfish = BundleItem(fish_data.sunfish, 1, 0) -tiger_trout = BundleItem(fish_data.tiger_trout, 1, 0) -shad = BundleItem(fish_data.shad, 1, 0) -smallmouth_bass = BundleItem(fish_data.smallmouth_bass, 1, 0) -dorado = BundleItem(fish_data.dorado, 1, 0) -carp = BundleItem(fish_data.carp, 1, 0) -midnight_carp = BundleItem(fish_data.midnight_carp, 1, 0) -largemouth_bass = BundleItem(fish_data.largemouth_bass, 1, 0) -sturgeon = BundleItem(fish_data.sturgeon, 1, 0) -bullhead = BundleItem(fish_data.bullhead, 1, 0) -tilapia = BundleItem(fish_data.tilapia, 1, 0) -pufferfish = BundleItem(fish_data.pufferfish, 1, 0) -tuna = BundleItem(fish_data.tuna, 1, 0) -super_cucumber = BundleItem(fish_data.super_cucumber, 1, 0) -flounder = BundleItem(fish_data.flounder, 1, 0) -anchovy = BundleItem(fish_data.anchovy, 1, 0) -sardine = BundleItem(fish_data.sardine, 1, 0) -red_mullet = BundleItem(fish_data.red_mullet, 1, 0) -herring = BundleItem(fish_data.herring, 1, 0) -eel = BundleItem(fish_data.eel, 1, 0) -octopus = BundleItem(fish_data.octopus, 1, 0) -red_snapper = BundleItem(fish_data.red_snapper, 1, 0) -squid = BundleItem(fish_data.squid, 1, 0) -sea_cucumber = BundleItem(fish_data.sea_cucumber, 1, 0) -albacore = BundleItem(fish_data.albacore, 1, 0) -halibut = BundleItem(fish_data.halibut, 1, 0) -scorpion_carp = BundleItem(fish_data.scorpion_carp, 1, 0) -sandfish = BundleItem(fish_data.sandfish, 1, 0) -woodskip = BundleItem(fish_data.woodskip, 1, 0) -lava_eel = BundleItem(fish_data.lava_eel, 1, 0) -ice_pip = BundleItem(fish_data.ice_pip, 1, 0) -stonefish = BundleItem(fish_data.stonefish, 1, 0) -ghostfish = BundleItem(fish_data.ghostfish, 1, 0) - -wilted_bouquet = BundleItem.item_bundle("Wilted Bouquet", 277) -copper_bar = BundleItem.item_bundle("Copper Bar", 334, 2, 0) -iron_Bar = BundleItem.item_bundle("Iron Bar", 335, 2, 0) -gold_bar = BundleItem.item_bundle("Gold Bar", 336) -iridium_bar = BundleItem.item_bundle("Iridium Bar", 337) -refined_quartz = BundleItem.item_bundle("Refined Quartz", 338, 2, 0) -coal = BundleItem.item_bundle("Coal", 382, 5, 0) - -quartz = BundleItem(Mineral.quartz, 1, 0) -fire_quartz = BundleItem(Mineral.fire_quartz, 1, 0) -frozen_tear = BundleItem(Mineral.frozen_tear, 1, 0) -earth_crystal = BundleItem(Mineral.earth_crystal, 1, 0) -emerald = BundleItem(Mineral.emerald, 1, 0) -aquamarine = BundleItem(Mineral.aquamarine, 1, 0) -ruby = BundleItem(Mineral.ruby, 1, 0) -amethyst = BundleItem(Mineral.amethyst, 1, 0) -topaz = BundleItem(Mineral.topaz, 1, 0) -jade = BundleItem(Mineral.jade, 1, 0) - -slime = BundleItem.item_bundle("Slime", 766, 99, 0) -bug_meat = BundleItem.item_bundle("Bug Meat", 684, 10, 0) -bat_wing = BundleItem.item_bundle("Bat Wing", 767, 10, 0) -solar_essence = BundleItem.item_bundle("Solar Essence", 768) -void_essence = BundleItem.item_bundle("Void Essence", 769) - -maki_roll = BundleItem.item_bundle("Maki Roll", 228) -fried_egg = BundleItem.item_bundle("Fried Egg", 194) -omelet = BundleItem.item_bundle("Omelet", 195) -pizza = BundleItem.item_bundle("Pizza", 206) -hashbrowns = BundleItem.item_bundle("Hashbrowns", 210) -pancakes = BundleItem.item_bundle("Pancakes", 211) -bread = BundleItem.item_bundle("Bread", 216) -tortilla = BundleItem.item_bundle("Tortilla", 229) -triple_shot_espresso = BundleItem.item_bundle("Triple Shot Espresso", 253) -farmer_s_lunch = BundleItem.item_bundle("Farmer's Lunch", 240) -survival_burger = BundleItem.item_bundle("Survival Burger", 241) -dish_o_the_sea = BundleItem.item_bundle("Dish O' The Sea", 242) -miner_s_treat = BundleItem.item_bundle("Miner's Treat", 243) -roots_platter = BundleItem.item_bundle("Roots Platter", 244) -salad = BundleItem.item_bundle("Salad", 196) -cheese_cauliflower = BundleItem.item_bundle("Cheese Cauliflower", 197) -parsnip_soup = BundleItem.item_bundle("Parsnip Soup", 199) -fried_mushroom = BundleItem.item_bundle("Fried Mushroom", 205) -salmon_dinner = BundleItem.item_bundle("Salmon Dinner", 212) -pepper_poppers = BundleItem.item_bundle("Pepper Poppers", 215) -spaghetti = BundleItem.item_bundle("Spaghetti", 224) -sashimi = BundleItem.item_bundle("Sashimi", 227) -blueberry_tart = BundleItem.item_bundle("Blueberry Tart", 234) -algae_soup = BundleItem.item_bundle("Algae Soup", 456) -pale_broth = BundleItem.item_bundle("Pale Broth", 457) -chowder = BundleItem.item_bundle("Chowder", 727) -green_algae = BundleItem.item_bundle("Green Algae", 153) -white_algae = BundleItem.item_bundle("White Algae", 157) -geode = BundleItem.item_bundle("Geode", 535) -frozen_geode = BundleItem.item_bundle("Frozen Geode", 536) -magma_geode = BundleItem.item_bundle("Magma Geode", 537) -omni_geode = BundleItem.item_bundle("Omni Geode", 749) - -spring_foraging_items = [wild_horseradish, daffodil, leek, dandelion, salmonberry, spring_onion] -summer_foraging_items = [grape, spice_berry, sweet_pea, fiddlehead_fern, rainbow_shell] -fall_foraging_items = [common_mushroom, wild_plum, hazelnut, blackberry] -winter_foraging_items = [winter_root, crystal_fruit, snow_yam, crocus, holly, nautilus_shell] -exotic_foraging_items = [coconut, cactus_fruit, cave_carrot, red_mushroom, purple_mushroom, - maple_syrup, oak_resin, pine_tar, morel, coral, - sea_urchin, clam, cockle, mussel, oyster, seaweed] -construction_items = [wood, stone, hardwood, clay, fiber] - -spring_crop_items = [blue_jazz, cauliflower, green_bean, kale, parsnip, potato, strawberry, tulip, unmilled_rice, coffee_bean, garlic, rhubarb] -summer_crops_items = [blueberry, corn, hops, hot_pepper, melon, poppy, - radish, summer_spangle, sunflower, tomato, wheat, red_cabbage, starfruit] -fall_crops_items = [corn, sunflower, wheat, amaranth, bok_choy, cranberries, - eggplant, fairy_rose, grape, pumpkin, yam, sweet_gem_berry, artichoke, beet] -all_crops_items = sorted({*spring_crop_items, *summer_crops_items, *fall_crops_items}) -quality_crops_items = [item.as_quality_crop() for item in all_crops_items] -animal_product_items = [egg, large_egg, brown_egg, large_brown_egg, wool, milk, large_milk, - goat_milk, large_goat_milk, truffle, duck_feather, duck_egg, rabbit_foot] -artisan_goods_items = [truffle_oil, cloth, goat_cheese, cheese, honey, beer, juice, mead, pale_ale, wine, jelly, - pickles, caviar, aged_roe, apple, apricot, orange, peach, pomegranate, cherry, coffee, green_tea] - -river_fish_items = [chub, catfish, rainbow_trout, lingcod, walleye, perch, pike, bream, - salmon, sunfish, tiger_trout, shad, smallmouth_bass, dorado] -lake_fish_items = [chub, rainbow_trout, lingcod, walleye, perch, carp, midnight_carp, largemouth_bass, sturgeon, bullhead] -ocean_fish_items = [tilapia, pufferfish, tuna, super_cucumber, flounder, anchovy, sardine, red_mullet, - herring, eel, octopus, red_snapper, squid, sea_cucumber, albacore, halibut] -night_fish_items = [walleye, bream, super_cucumber, eel, squid, midnight_carp] - -specialty_fish_items = [scorpion_carp, sandfish, woodskip, pufferfish, eel, octopus, - squid, lava_eel, ice_pip, stonefish, ghostfish, dorado] -crab_pot_items = [lobster, clam, crab, cockle, mussel, shrimp, oyster, crayfish, snail, - periwinkle, trash, driftwood, soggy_newspaper, broken_cd, broken_glasses] - -blacksmith_items = [wilted_bouquet, copper_bar, iron_Bar, gold_bar, iridium_bar, refined_quartz, coal] -geologist_items = [quartz, earth_crystal, frozen_tear, fire_quartz, emerald, aquamarine, ruby, amethyst, topaz, jade] -adventurer_items = [slime, bug_meat, bat_wing, solar_essence, void_essence, coal] - -chef_items = [maki_roll, fried_egg, omelet, pizza, hashbrowns, pancakes, bread, tortilla, triple_shot_espresso, +# Where to put radioactive bar? +treasure_hunter_items = [emerald, aquamarine, ruby, amethyst, topaz, jade, diamond] +engineer_items = [iridium_ore.as_amount(5), battery_pack, refined_quartz.as_amount(5), diamond] + +chef_items_vanilla = [maple_syrup, fiddlehead_fern, truffle, poppy, maki_roll, fried_egg] +# More recipes? +chef_items_thematic = [maki_roll, fried_egg, omelet, pizza, hashbrowns, pancakes, bread, tortilla, farmer_s_lunch, survival_burger, dish_o_the_sea, miner_s_treat, roots_platter, salad, cheese_cauliflower, parsnip_soup, fried_mushroom, salmon_dinner, pepper_poppers, spaghetti, sashimi, blueberry_tart, algae_soup, pale_broth, chowder] -dwarf_scroll_1 = BundleItem.item_bundle("Dwarf Scroll I", 96) -dwarf_scroll_2 = BundleItem.item_bundle("Dwarf Scroll II", 97) -dwarf_scroll_3 = BundleItem.item_bundle("Dwarf Scroll III", 98) -dwarf_scroll_4 = BundleItem.item_bundle("Dwarf Scroll IV", 99) -elvish_jewelry = BundleItem.item_bundle("Elvish Jewelry", 104) -ancient_drum = BundleItem.item_bundle("Ancient Drum", 123) -dried_starfish = BundleItem.item_bundle("Dried Starfish", 116) - -dinosaur_mayo = BundleItem.item_bundle(ArtisanGood.dinosaur_mayonnaise, 807) -void_mayo = BundleItem.item_bundle(ArtisanGood.void_mayonnaise, 308) -prismatic_shard = BundleItem(Mineral.prismatic_shard, 1, 0) -diamond = BundleItem(Mineral.diamond, 1, 0) -ancient_fruit = BundleItem.item_bundle(Fruit.ancient_fruit, 454) -void_salmon = BundleItem.item_bundle(Fish.void_salmon, 795) -tea_leaves = BundleItem.item_bundle(Vegetable.tea_leaves, 815) -blobfish = BundleItem.item_bundle(Fish.blobfish, 800) - +dye_items_vanilla = [red_mushroom, sea_urchin, sunflower, duck_feather, aquamarine, red_cabbage] dye_red_items = [cranberries, hot_pepper, radish, rhubarb, spaghetti, strawberry, tomato, tulip] dye_orange_items = [poppy, pumpkin, apricot, orange, spice_berry, winter_root] dye_yellow_items = [corn, parsnip, summer_spangle, sunflower] dye_green_items = [fiddlehead_fern, kale, artichoke, bok_choy, green_bean] dye_blue_items = [blueberry, blue_jazz, blackberry, crystal_fruit] dye_purple_items = [beet, crocus, eggplant, red_cabbage, sweet_pea] -dye_items = [dye_red_items, dye_orange_items, dye_yellow_items, dye_green_items, dye_blue_items, dye_purple_items] -field_research_items = [purple_mushroom, nautilus_shell, chub, geode, frozen_geode, magma_geode, omni_geode, +dye_items_thematic = [dye_red_items, dye_orange_items, dye_yellow_items, dye_green_items, dye_blue_items, dye_purple_items] + +field_research_items_vanilla = [purple_mushroom, nautilus_shell, chub, frozen_geode] +field_research_items_thematic = [*field_research_items_vanilla, geode, magma_geode, omni_geode, rainbow_shell, amethyst, bream, carp] -fodder_items = [wheat.as_amount(10), hay.as_amount(10), apple.as_amount(3), kale.as_amount(3), corn.as_amount(3), - green_bean.as_amount(3), potato.as_amount(3), green_algae.as_amount(5), white_algae.as_amount(3)] -enchanter_items = [oak_resin, wine, rabbit_foot, pomegranate, purple_mushroom, solar_essence, + +fodder_items_vanilla = [wheat.as_amount(10), hay.as_amount(10), apple.as_amount(3)] +fodder_items_thematic = [*fodder_items_vanilla, kale.as_amount(3), corn.as_amount(3), green_bean.as_amount(3), + potato.as_amount(3), green_algae.as_amount(5), white_algae.as_amount(3)] + +enchanter_items_vanilla = [oak_resin, wine, rabbit_foot, pomegranate] +enchanter_items_thematic = [*enchanter_items_vanilla, purple_mushroom, solar_essence, super_cucumber, void_essence, fire_quartz, frozen_tear, jade] + +children_items = [salmonberry.as_amount(10), cookie, ancient_doll, ice_cream, cranberry_candy, ginger_ale, + grape.as_amount(10), pink_cake, snail, fairy_rose, plum_pudding] +forager_items = [salmonberry.as_amount(50), blackberry.as_amount(50), wild_plum.as_amount(20), snow_yam.as_amount(20), + common_mushroom.as_amount(20), grape.as_amount(20), spring_onion.as_amount(20)] +home_cook_items = [egg.as_amount(10), milk.as_amount(10), wheat_flour.as_amount(100), sugar.as_amount(100), vinegar.as_amount(100), + chocolate_cake, pancakes, rhubarb_pie] + + missing_bundle_items = [wine.as_silver_quality(), pale_ale.as_silver_quality(), beer.as_silver_quality(), mead.as_silver_quality(), cheese.as_silver_quality(), goat_cheese.as_silver_quality(), dinosaur_mayo, void_mayo, cloth, green_tea, truffle_oil, caviar, prismatic_shard, diamond, ancient_fruit.as_gold_quality().as_amount(5), sweet_gem_berry.as_gold_quality().as_amount(5), starfruit.as_gold_quality().as_amount(5), tea_leaves.as_amount(5), void_salmon.as_gold_quality(), lava_eel.as_gold_quality(), scorpion_carp.as_gold_quality(), blobfish.as_gold_quality()] +# Make thematic with other currencies vault_2500_items = [BundleItem.money_bundle(2500)] vault_5000_items = [BundleItem.money_bundle(5000)] vault_10000_items = [BundleItem.money_bundle(10000)] diff --git a/worlds/stardew_valley/data/common_data.py b/worlds/stardew_valley/data/common_data.py deleted file mode 100644 index ad34b1ba59e7..000000000000 --- a/worlds/stardew_valley/data/common_data.py +++ /dev/null @@ -1,6 +0,0 @@ -quality_dict = { - 0: "", - 1: "Silver", - 2: "Gold", - 3: "Iridium" -} diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 7fcccbb0e40b..2925fd8d3114 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -2,14 +2,14 @@ from typing import List, Tuple, Union, Optional, Set from . import season_data as season -from .game_item import GameItem from ..strings.fish_names import Fish, SVEFish from ..strings.region_names import Region, SVERegion from ..mods.mod_data import ModNames @dataclass(frozen=True) -class FishItem(GameItem): +class FishItem: + name: str locations: Tuple[str] seasons: Tuple[str] difficulty: int @@ -18,7 +18,7 @@ class FishItem(GameItem): mod_name: Optional[str] = None def __repr__(self): - return f"{self.name} [{self.item_id}] (Locations: {self.locations} |" \ + return f"{self.name} (Locations: {self.locations} |" \ f" Seasons: {self.seasons} |" \ f" Difficulty: {self.difficulty}) |" \ f"Mod: {self.mod_name}" @@ -53,121 +53,121 @@ def __repr__(self): all_fish: List[FishItem] = [] -def create_fish(name: str, item_id: int, locations: Tuple[str, ...], seasons: Union[str, Tuple[str, ...]], +def create_fish(name: str, locations: Tuple[str, ...], seasons: Union[str, Tuple[str, ...]], difficulty: int, legendary: bool = False, extended_family: bool = False, mod_name: Optional[str] = None) -> FishItem: if isinstance(seasons, str): seasons = (seasons,) - fish_item = FishItem(name, item_id, locations, seasons, difficulty, legendary, extended_family, mod_name) + fish_item = FishItem(name, locations, seasons, difficulty, legendary, extended_family, mod_name) all_fish.append(fish_item) return fish_item -albacore = create_fish("Albacore", 705, ocean, (season.fall, season.winter), 60) -anchovy = create_fish("Anchovy", 129, ocean, (season.spring, season.fall), 30) -blue_discus = create_fish("Blue Discus", 838, ginger_island_river, season.all_seasons, 60) -bream = create_fish("Bream", 132, town_river + forest_river, season.all_seasons, 35) -bullhead = create_fish("Bullhead", 700, mountain_lake, season.all_seasons, 46) -carp = create_fish(Fish.carp, 142, mountain_lake + secret_woods + sewers + mutant_bug_lair, season.not_winter, 15) -catfish = create_fish("Catfish", 143, town_river + forest_river + secret_woods, (season.spring, season.fall), 75) -chub = create_fish("Chub", 702, forest_river + mountain_lake, season.all_seasons, 35) -dorado = create_fish("Dorado", 704, forest_river, season.summer, 78) -eel = create_fish("Eel", 148, ocean, (season.spring, season.fall), 70) -flounder = create_fish("Flounder", 267, ocean, (season.spring, season.summer), 50) -ghostfish = create_fish("Ghostfish", 156, mines_floor_20 + mines_floor_60, season.all_seasons, 50) -halibut = create_fish("Halibut", 708, ocean, season.not_fall, 50) -herring = create_fish("Herring", 147, ocean, (season.spring, season.winter), 25) -ice_pip = create_fish("Ice Pip", 161, mines_floor_60, season.all_seasons, 85) -largemouth_bass = create_fish("Largemouth Bass", 136, mountain_lake, season.all_seasons, 50) -lava_eel = create_fish("Lava Eel", 162, mines_floor_100, season.all_seasons, 90) -lingcod = create_fish("Lingcod", 707, town_river + forest_river + mountain_lake, season.winter, 85) -lionfish = create_fish("Lionfish", 837, ginger_island_ocean, season.all_seasons, 50) -midnight_carp = create_fish("Midnight Carp", 269, mountain_lake + forest_pond + ginger_island_river, +albacore = create_fish("Albacore", ocean, (season.fall, season.winter), 60) +anchovy = create_fish("Anchovy", ocean, (season.spring, season.fall), 30) +blue_discus = create_fish("Blue Discus", ginger_island_river, season.all_seasons, 60) +bream = create_fish("Bream", town_river + forest_river, season.all_seasons, 35) +bullhead = create_fish("Bullhead", mountain_lake, season.all_seasons, 46) +carp = create_fish(Fish.carp, mountain_lake + secret_woods + sewers + mutant_bug_lair, season.not_winter, 15) +catfish = create_fish("Catfish", town_river + forest_river + secret_woods, (season.spring, season.fall), 75) +chub = create_fish("Chub", forest_river + mountain_lake, season.all_seasons, 35) +dorado = create_fish("Dorado", forest_river, season.summer, 78) +eel = create_fish("Eel", ocean, (season.spring, season.fall), 70) +flounder = create_fish("Flounder", ocean, (season.spring, season.summer), 50) +ghostfish = create_fish("Ghostfish", mines_floor_20 + mines_floor_60, season.all_seasons, 50) +halibut = create_fish("Halibut", ocean, season.not_fall, 50) +herring = create_fish("Herring", ocean, (season.spring, season.winter), 25) +ice_pip = create_fish("Ice Pip", mines_floor_60, season.all_seasons, 85) +largemouth_bass = create_fish("Largemouth Bass", mountain_lake, season.all_seasons, 50) +lava_eel = create_fish("Lava Eel", mines_floor_100, season.all_seasons, 90) +lingcod = create_fish("Lingcod", town_river + forest_river + mountain_lake, season.winter, 85) +lionfish = create_fish("Lionfish", ginger_island_ocean, season.all_seasons, 50) +midnight_carp = create_fish("Midnight Carp", mountain_lake + forest_pond + ginger_island_river, (season.fall, season.winter), 55) -octopus = create_fish("Octopus", 149, ocean, season.summer, 95) -perch = create_fish("Perch", 141, town_river + forest_river + forest_pond + mountain_lake, season.winter, 35) -pike = create_fish("Pike", 144, town_river + forest_river + forest_pond, (season.summer, season.winter), 60) -pufferfish = create_fish("Pufferfish", 128, ocean + ginger_island_ocean, season.summer, 80) -rainbow_trout = create_fish("Rainbow Trout", 138, town_river + forest_river + mountain_lake, season.summer, 45) -red_mullet = create_fish("Red Mullet", 146, ocean, (season.summer, season.winter), 55) -red_snapper = create_fish("Red Snapper", 150, ocean, (season.summer, season.fall), 40) -salmon = create_fish("Salmon", 139, town_river + forest_river, season.fall, 50) -sandfish = create_fish("Sandfish", 164, desert, season.all_seasons, 65) -sardine = create_fish("Sardine", 131, ocean, (season.spring, season.fall, season.winter), 30) -scorpion_carp = create_fish("Scorpion Carp", 165, desert, season.all_seasons, 90) -sea_cucumber = create_fish("Sea Cucumber", 154, ocean, (season.fall, season.winter), 40) -shad = create_fish("Shad", 706, town_river + forest_river, season.not_winter, 45) -slimejack = create_fish("Slimejack", 796, mutant_bug_lair, season.all_seasons, 55) -smallmouth_bass = create_fish("Smallmouth Bass", 137, town_river + forest_river, (season.spring, season.fall), 28) -squid = create_fish("Squid", 151, ocean, season.winter, 75) -stingray = create_fish("Stingray", 836, pirate_cove, season.all_seasons, 80) -stonefish = create_fish("Stonefish", 158, mines_floor_20, season.all_seasons, 65) -sturgeon = create_fish("Sturgeon", 698, mountain_lake, (season.summer, season.winter), 78) -sunfish = create_fish("Sunfish", 145, town_river + forest_river, (season.spring, season.summer), 30) -super_cucumber = create_fish("Super Cucumber", 155, ocean + ginger_island_ocean, (season.summer, season.fall), 80) -tiger_trout = create_fish("Tiger Trout", 699, town_river + forest_river, (season.fall, season.winter), 60) -tilapia = create_fish("Tilapia", 701, ocean + ginger_island_ocean, (season.summer, season.fall), 50) +octopus = create_fish("Octopus", ocean, season.summer, 95) +perch = create_fish("Perch", town_river + forest_river + forest_pond + mountain_lake, season.winter, 35) +pike = create_fish("Pike", town_river + forest_river + forest_pond, (season.summer, season.winter), 60) +pufferfish = create_fish("Pufferfish", ocean + ginger_island_ocean, season.summer, 80) +rainbow_trout = create_fish("Rainbow Trout", town_river + forest_river + mountain_lake, season.summer, 45) +red_mullet = create_fish("Red Mullet", ocean, (season.summer, season.winter), 55) +red_snapper = create_fish("Red Snapper", ocean, (season.summer, season.fall), 40) +salmon = create_fish("Salmon", town_river + forest_river, season.fall, 50) +sandfish = create_fish("Sandfish", desert, season.all_seasons, 65) +sardine = create_fish("Sardine", ocean, (season.spring, season.fall, season.winter), 30) +scorpion_carp = create_fish("Scorpion Carp", desert, season.all_seasons, 90) +sea_cucumber = create_fish("Sea Cucumber", ocean, (season.fall, season.winter), 40) +shad = create_fish("Shad", town_river + forest_river, season.not_winter, 45) +slimejack = create_fish("Slimejack", mutant_bug_lair, season.all_seasons, 55) +smallmouth_bass = create_fish("Smallmouth Bass", town_river + forest_river, (season.spring, season.fall), 28) +squid = create_fish("Squid", ocean, season.winter, 75) +stingray = create_fish("Stingray", pirate_cove, season.all_seasons, 80) +stonefish = create_fish("Stonefish", mines_floor_20, season.all_seasons, 65) +sturgeon = create_fish("Sturgeon", mountain_lake, (season.summer, season.winter), 78) +sunfish = create_fish("Sunfish", town_river + forest_river, (season.spring, season.summer), 30) +super_cucumber = create_fish("Super Cucumber", ocean + ginger_island_ocean, (season.summer, season.fall), 80) +tiger_trout = create_fish("Tiger Trout", town_river + forest_river, (season.fall, season.winter), 60) +tilapia = create_fish("Tilapia", ocean + ginger_island_ocean, (season.summer, season.fall), 50) # Tuna has different seasons on ginger island. Should be changed when the whole fish thing is refactored -tuna = create_fish("Tuna", 130, ocean + ginger_island_ocean, (season.summer, season.winter), 70) -void_salmon = create_fish("Void Salmon", 795, witch_swamp, season.all_seasons, 80) -walleye = create_fish("Walleye", 140, town_river + forest_river + forest_pond + mountain_lake, season.fall, 45) -woodskip = create_fish("Woodskip", 734, secret_woods, season.all_seasons, 50) - -blob_fish = create_fish("Blobfish", 800, night_market, season.winter, 75) -midnight_squid = create_fish("Midnight Squid", 798, night_market, season.winter, 55) -spook_fish = create_fish("Spook Fish", 799, night_market, season.winter, 60) - -angler = create_fish(Fish.angler, 160, town_river, season.fall, 85, True, False) -crimsonfish = create_fish(Fish.crimsonfish, 159, ocean, season.summer, 95, True, False) -glacierfish = create_fish(Fish.glacierfish, 775, forest_river, season.winter, 100, True, False) -legend = create_fish(Fish.legend, 163, mountain_lake, season.spring, 110, True, False) -mutant_carp = create_fish(Fish.mutant_carp, 682, sewers, season.all_seasons, 80, True, False) - -ms_angler = create_fish(Fish.ms_angler, 160, town_river, season.fall, 85, True, True) -son_of_crimsonfish = create_fish(Fish.son_of_crimsonfish, 159, ocean, season.summer, 95, True, True) -glacierfish_jr = create_fish(Fish.glacierfish_jr, 775, forest_river, season.winter, 100, True, True) -legend_ii = create_fish(Fish.legend_ii, 163, mountain_lake, season.spring, 110, True, True) -radioactive_carp = create_fish(Fish.radioactive_carp, 682, sewers, season.all_seasons, 80, True, True) - -baby_lunaloo = create_fish(SVEFish.baby_lunaloo, 3006, ginger_island_ocean, season.all_seasons, 15, mod_name=ModNames.sve) -bonefish = create_fish(SVEFish.bonefish, 3013, crimson_badlands, season.all_seasons, 70, mod_name=ModNames.sve) -bull_trout = create_fish(SVEFish.bull_trout, 3014, forest_river, season.not_spring, 45, mod_name=ModNames.sve) -butterfish = create_fish(SVEFish.butterfish, 3015, shearwater, season.not_winter, 75, mod_name=ModNames.sve) -clownfish = create_fish(SVEFish.clownfish, 3016, ginger_island_ocean, season.all_seasons, 45, mod_name=ModNames.sve) -daggerfish = create_fish(SVEFish.daggerfish, 3017, highlands, season.all_seasons, 50, mod_name=ModNames.sve) -frog = create_fish(SVEFish.frog, 3023, mountain_lake, (season.spring, season.summer), 70, mod_name=ModNames.sve) -gemfish = create_fish(SVEFish.gemfish, 3027, highlands, season.all_seasons, 100, mod_name=ModNames.sve) -goldenfish = create_fish(SVEFish.goldenfish, 3031, sprite_spring, season.all_seasons, 60, mod_name=ModNames.sve) -grass_carp = create_fish(SVEFish.grass_carp, 3034, secret_woods, (season.spring, season.summer), 85, mod_name=ModNames.sve) -king_salmon = create_fish(SVEFish.king_salmon, 3044, forest_river, (season.spring, season.summer), 80, mod_name=ModNames.sve) -kittyfish = create_fish(SVEFish.kittyfish, 3045, shearwater, (season.fall, season.winter), 85, mod_name=ModNames.sve) -lunaloo = create_fish(SVEFish.lunaloo, 3049, ginger_island_ocean, season.all_seasons, 70, mod_name=ModNames.sve) -meteor_carp = create_fish(SVEFish.meteor_carp, 3051, sprite_spring, season.all_seasons, 80, mod_name=ModNames.sve) -minnow = create_fish(SVEFish.minnow, 3052, town_river, season.all_seasons, 1, mod_name=ModNames.sve) -puppyfish = create_fish(SVEFish.puppyfish, 3061, shearwater, season.not_winter, 85, mod_name=ModNames.sve) -radioactive_bass = create_fish(SVEFish.radioactive_bass, 3062, sewers, season.all_seasons, 90, mod_name=ModNames.sve) -seahorse = create_fish(SVEFish.seahorse, 3068, ginger_island_ocean, season.all_seasons, 25, mod_name=ModNames.sve) -shiny_lunaloo = create_fish(SVEFish.shiny_lunaloo, 3070, ginger_island_ocean, season.all_seasons, 110, mod_name=ModNames.sve) -snatcher_worm = create_fish(SVEFish.snatcher_worm, 3075, mutant_bug_lair, season.all_seasons, 75, mod_name=ModNames.sve) -starfish = create_fish(SVEFish.starfish, 3079, ginger_island_ocean, season.all_seasons, 75, mod_name=ModNames.sve) -torpedo_trout = create_fish(SVEFish.torpedo_trout, 3084, fable_reef, season.all_seasons, 70, mod_name=ModNames.sve) -undeadfish = create_fish(SVEFish.undeadfish, 3085, crimson_badlands, season.all_seasons, 80, mod_name=ModNames.sve) -void_eel = create_fish(SVEFish.void_eel, 3087, witch_swamp, season.all_seasons, 100, mod_name=ModNames.sve) -water_grub = create_fish(SVEFish.water_grub, 3094, mutant_bug_lair, season.all_seasons, 60, mod_name=ModNames.sve) -sea_sponge = create_fish(SVEFish.sea_sponge, 3067, ginger_island_ocean, season.all_seasons, 40, mod_name=ModNames.sve) -dulse_seaweed = create_fish(SVEFish.dulse_seaweed, 3020, vineyard, season.all_seasons, 50, mod_name=ModNames.sve) - - -clam = create_fish("Clam", 372, ocean, season.all_seasons, -1) -cockle = create_fish("Cockle", 718, ocean, season.all_seasons, -1) -crab = create_fish("Crab", 717, ocean, season.all_seasons, -1) -crayfish = create_fish("Crayfish", 716, fresh_water, season.all_seasons, -1) -lobster = create_fish("Lobster", 715, ocean, season.all_seasons, -1) -mussel = create_fish("Mussel", 719, ocean, season.all_seasons, -1) -oyster = create_fish("Oyster", 723, ocean, season.all_seasons, -1) -periwinkle = create_fish("Periwinkle", 722, fresh_water, season.all_seasons, -1) -shrimp = create_fish("Shrimp", 720, ocean, season.all_seasons, -1) -snail = create_fish("Snail", 721, fresh_water, season.all_seasons, -1) +tuna = create_fish("Tuna", ocean + ginger_island_ocean, (season.summer, season.winter), 70) +void_salmon = create_fish("Void Salmon", witch_swamp, season.all_seasons, 80) +walleye = create_fish("Walleye", town_river + forest_river + forest_pond + mountain_lake, season.fall, 45) +woodskip = create_fish("Woodskip", secret_woods, season.all_seasons, 50) + +blob_fish = create_fish("Blobfish", night_market, season.winter, 75) +midnight_squid = create_fish("Midnight Squid", night_market, season.winter, 55) +spook_fish = create_fish("Spook Fish", night_market, season.winter, 60) + +angler = create_fish(Fish.angler, town_river, season.fall, 85, True, False) +crimsonfish = create_fish(Fish.crimsonfish, ocean, season.summer, 95, True, False) +glacierfish = create_fish(Fish.glacierfish, forest_river, season.winter, 100, True, False) +legend = create_fish(Fish.legend, mountain_lake, season.spring, 110, True, False) +mutant_carp = create_fish(Fish.mutant_carp, sewers, season.all_seasons, 80, True, False) + +ms_angler = create_fish(Fish.ms_angler, town_river, season.fall, 85, True, True) +son_of_crimsonfish = create_fish(Fish.son_of_crimsonfish, ocean, season.summer, 95, True, True) +glacierfish_jr = create_fish(Fish.glacierfish_jr, forest_river, season.winter, 100, True, True) +legend_ii = create_fish(Fish.legend_ii, mountain_lake, season.spring, 110, True, True) +radioactive_carp = create_fish(Fish.radioactive_carp, sewers, season.all_seasons, 80, True, True) + +baby_lunaloo = create_fish(SVEFish.baby_lunaloo, ginger_island_ocean, season.all_seasons, 15, mod_name=ModNames.sve) +bonefish = create_fish(SVEFish.bonefish, crimson_badlands, season.all_seasons, 70, mod_name=ModNames.sve) +bull_trout = create_fish(SVEFish.bull_trout, forest_river, season.not_spring, 45, mod_name=ModNames.sve) +butterfish = create_fish(SVEFish.butterfish, shearwater, season.not_winter, 75, mod_name=ModNames.sve) +clownfish = create_fish(SVEFish.clownfish, ginger_island_ocean, season.all_seasons, 45, mod_name=ModNames.sve) +daggerfish = create_fish(SVEFish.daggerfish, highlands, season.all_seasons, 50, mod_name=ModNames.sve) +frog = create_fish(SVEFish.frog, mountain_lake, (season.spring, season.summer), 70, mod_name=ModNames.sve) +gemfish = create_fish(SVEFish.gemfish, highlands, season.all_seasons, 100, mod_name=ModNames.sve) +goldenfish = create_fish(SVEFish.goldenfish, sprite_spring, season.all_seasons, 60, mod_name=ModNames.sve) +grass_carp = create_fish(SVEFish.grass_carp, secret_woods, (season.spring, season.summer), 85, mod_name=ModNames.sve) +king_salmon = create_fish(SVEFish.king_salmon, forest_river, (season.spring, season.summer), 80, mod_name=ModNames.sve) +kittyfish = create_fish(SVEFish.kittyfish, shearwater, (season.fall, season.winter), 85, mod_name=ModNames.sve) +lunaloo = create_fish(SVEFish.lunaloo, ginger_island_ocean, season.all_seasons, 70, mod_name=ModNames.sve) +meteor_carp = create_fish(SVEFish.meteor_carp, sprite_spring, season.all_seasons, 80, mod_name=ModNames.sve) +minnow = create_fish(SVEFish.minnow, town_river, season.all_seasons, 1, mod_name=ModNames.sve) +puppyfish = create_fish(SVEFish.puppyfish, shearwater, season.not_winter, 85, mod_name=ModNames.sve) +radioactive_bass = create_fish(SVEFish.radioactive_bass, sewers, season.all_seasons, 90, mod_name=ModNames.sve) +seahorse = create_fish(SVEFish.seahorse, ginger_island_ocean, season.all_seasons, 25, mod_name=ModNames.sve) +shiny_lunaloo = create_fish(SVEFish.shiny_lunaloo, ginger_island_ocean, season.all_seasons, 110, mod_name=ModNames.sve) +snatcher_worm = create_fish(SVEFish.snatcher_worm, mutant_bug_lair, season.all_seasons, 75, mod_name=ModNames.sve) +starfish = create_fish(SVEFish.starfish, ginger_island_ocean, season.all_seasons, 75, mod_name=ModNames.sve) +torpedo_trout = create_fish(SVEFish.torpedo_trout, fable_reef, season.all_seasons, 70, mod_name=ModNames.sve) +undeadfish = create_fish(SVEFish.undeadfish, crimson_badlands, season.all_seasons, 80, mod_name=ModNames.sve) +void_eel = create_fish(SVEFish.void_eel, witch_swamp, season.all_seasons, 100, mod_name=ModNames.sve) +water_grub = create_fish(SVEFish.water_grub, mutant_bug_lair, season.all_seasons, 60, mod_name=ModNames.sve) +sea_sponge = create_fish(SVEFish.sea_sponge, ginger_island_ocean, season.all_seasons, 40, mod_name=ModNames.sve) +dulse_seaweed = create_fish(SVEFish.dulse_seaweed, vineyard, season.all_seasons, 50, mod_name=ModNames.sve) + + +clam = create_fish("Clam", ocean, season.all_seasons, -1) +cockle = create_fish("Cockle", ocean, season.all_seasons, -1) +crab = create_fish("Crab", ocean, season.all_seasons, -1) +crayfish = create_fish("Crayfish", fresh_water, season.all_seasons, -1) +lobster = create_fish("Lobster", ocean, season.all_seasons, -1) +mussel = create_fish("Mussel", ocean, season.all_seasons, -1) +oyster = create_fish("Oyster", ocean, season.all_seasons, -1) +periwinkle = create_fish("Periwinkle", fresh_water, season.all_seasons, -1) +shrimp = create_fish("Shrimp", ocean, season.all_seasons, -1) +snail = create_fish("Snail", fresh_water, season.all_seasons, -1) legendary_fish = [angler, crimsonfish, glacierfish, legend, mutant_carp] extended_family = [ms_angler, son_of_crimsonfish, glacierfish_jr, legend_ii, radioactive_carp] diff --git a/worlds/stardew_valley/data/game_item.py b/worlds/stardew_valley/data/game_item.py deleted file mode 100644 index cac86d527d86..000000000000 --- a/worlds/stardew_valley/data/game_item.py +++ /dev/null @@ -1,13 +0,0 @@ -from dataclasses import dataclass - - -@dataclass(frozen=True) -class GameItem: - name: str - item_id: int - - def __repr__(self): - return f"{self.name} [{self.item_id}]" - - def __lt__(self, other): - return self.name < other.name diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 6098e6b09f98..96dd5a2afb2d 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -8,6 +8,7 @@ from .region_logic import RegionLogicMixin from ..data.bundle_data import BundleItem from ..stardew_rule import StardewRule +from ..strings.quality_names import Quality from ..strings.region_names import Region @@ -21,15 +22,14 @@ class BundleLogic(BaseLogic[Union[HasLogicMixin, RegionLogicMixin, MoneyLogicMix # Should be cached def can_complete_bundle(self, bundle_requirements: Tuple[BundleItem], number_required: int) -> StardewRule: item_rules = [] - highest_quality_yet = 0 + highest_quality_yet = Quality.basic can_speak_junimo = self.logic.region.can_reach(Region.wizard_tower) for bundle_item in bundle_requirements: if bundle_item.item.item_id == -1: return can_speak_junimo & self.logic.money.can_spend(bundle_item.amount) else: item_rules.append(bundle_item.item.name) - if bundle_item.quality > highest_quality_yet: - highest_quality_yet = bundle_item.quality + highest_quality_yet = Quality.get_highest(highest_quality_yet, bundle_item.quality) return can_speak_junimo & self.logic.has(tuple(item_rules), number_required) & self.logic.farming.can_grow_crop_quality(highest_quality_yet) @cached_property diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 432535a09b1a..e04f5b6b2ad5 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -23,6 +23,7 @@ from .strings.building_names import Building from .strings.calendar_names import Weekday from .strings.craftable_names import Bomb +from .strings.crop_names import Fruit from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance, \ SVEEntrance from .strings.generic_names import Generic @@ -80,7 +81,7 @@ def set_rules(world): def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.add_rule(multiworld.get_location("Old Master Cannoli", player), - logic.has("Sweet Gem Berry")) + logic.has(Fruit.sweet_gem_berry)) MultiWorldRules.add_rule(multiworld.get_location("Galaxy Sword Shrine", player), logic.has("Prismatic Shard")) MultiWorldRules.add_rule(multiworld.get_location("Krobus Stardrop", player), diff --git a/worlds/stardew_valley/strings/crop_names.py b/worlds/stardew_valley/strings/crop_names.py index c6a34c02c30d..595d8a867bcc 100644 --- a/worlds/stardew_valley/strings/crop_names.py +++ b/worlds/stardew_valley/strings/crop_names.py @@ -13,6 +13,7 @@ def fruity(name: str) -> str: class Fruit: + sweet_gem_berry = fruity("Sweet Gem Berry") any = "Any Fruit" blueberry = fruity("Blueberry") melon = fruity("Melon") diff --git a/worlds/stardew_valley/strings/flower_names.py b/worlds/stardew_valley/strings/flower_names.py index 934e193c89a1..7e708fc3c074 100644 --- a/worlds/stardew_valley/strings/flower_names.py +++ b/worlds/stardew_valley/strings/flower_names.py @@ -1,5 +1,7 @@ class Flower: + blue_jazz = "Blue Jazz" fairy_rose = "Fairy Rose" - sunflower = "Sunflower" poppy = "Poppy" - blue_jazz = "Blue Jazz" + summer_spangle = "Summer Spangle" + sunflower = "Sunflower" + tulip = "Tulip" diff --git a/worlds/stardew_valley/strings/quality_names.py b/worlds/stardew_valley/strings/quality_names.py new file mode 100644 index 000000000000..c55854af5870 --- /dev/null +++ b/worlds/stardew_valley/strings/quality_names.py @@ -0,0 +1,15 @@ +class Quality: + basic = "Basic" + silver = "Silver" + gold = "Gold" + iridium = "Iridium" + + @staticmethod + def get_highest(quality1: str, quality2: str) -> str: + for quality in qualities_in_desc_order: + if quality1 == quality or quality2 == quality: + return quality + return Quality.basic + + +qualities_in_desc_order = [Quality.iridium, Quality.gold, Quality.silver, Quality.basic] diff --git a/worlds/stardew_valley/test/TestBundles.py b/worlds/stardew_valley/test/TestBundles.py index a13829eb67ea..c7ea6faa83f5 100644 --- a/worlds/stardew_valley/test/TestBundles.py +++ b/worlds/stardew_valley/test/TestBundles.py @@ -1,6 +1,7 @@ import unittest from ..data.bundle_data import all_bundle_items, quality_crops_items +from ..strings.crop_names import Fruit class TestBundles(unittest.TestCase): @@ -18,7 +19,7 @@ def test_quality_crops_have_correct_amounts(self): for bundle_item in quality_crops_items: with self.subTest(bundle_item.item.name): name = bundle_item.item.name - if name == "Sweet Gem Berry" or name == "Ancient Fruit": + if name == Fruit.sweet_gem_berry or name == Fruit.ancient_fruit: self.assertEqual(bundle_item.amount, 1) else: self.assertEqual(bundle_item.amount, 5) From de09fbac19919a4978fbcf2b265660bf815e1671 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 21 Nov 2023 23:17:52 -0500 Subject: [PATCH 201/482] - WIP again --- worlds/stardew_valley/bundles/bundle.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index 2eb1570c9a27..ee2fd9f03353 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -1,11 +1,12 @@ +from typing import List + +from worlds.stardew_valley.bundles.bundle_item import BundleItem + + class Bundle: room: str - sprite: str - original_name: str name: str - rewards: List[str] - requirements: List[BundleItem] - color: str + items: List[BundleItem] number_required: int def __init__(self, key: str, value: str): From d2a6abab06270c74e8f63ed5c7860b55aca1ac88 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 22 Nov 2023 10:07:15 -0500 Subject: [PATCH 202/482] - WIP --- worlds/stardew_valley/bundles/bundle.py | 143 ++++++------------ worlds/stardew_valley/data/bundle_data.py | 28 +++- worlds/stardew_valley/strings/bundle_names.py | 14 ++ 3 files changed, 90 insertions(+), 95 deletions(-) create mode 100644 worlds/stardew_valley/strings/bundle_names.py diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index ee2fd9f03353..1b5c5db32749 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -1,3 +1,4 @@ +from random import Random from typing import List from worlds.stardew_valley.bundles.bundle_item import BundleItem @@ -9,102 +10,56 @@ class Bundle: items: List[BundleItem] number_required: int - def __init__(self, key: str, value: str): - key_parts = key.split("/") - self.room = key_parts[0] - self.sprite = key_parts[1] - - value_parts = value.split("/") - self.original_name = value_parts[0] - self.name = value_parts[0] - self.rewards = self.parse_stardew_objects(value_parts[1]) - self.requirements = self.parse_stardew_bundle_items(value_parts[2]) - self.color = value_parts[3] - if len(value_parts) > 4: - self.number_required = int(value_parts[4]) - else: - self.number_required = len(self.requirements) + def __init__(self, room: str, name: str, items: List[BundleItem], number_required): + self.room = room + self.name = name + self.items = items + self.number_required = number_required def __repr__(self): - return f"{self.original_name} -> {repr(self.requirements)}" - - def get_name_with_bundle(self) -> str: - return f"{self.original_name} Bundle" - - def to_pair(self) -> (str, str): - key = f"{self.room}/{self.sprite}" - str_rewards = "" - for reward in self.rewards: - str_rewards += f" {reward}" - str_rewards = str_rewards.strip() - str_requirements = "" - for requirement in self.requirements: - str_requirements += f" {requirement.item.item_id} {requirement.amount} {requirement.quality}" - str_requirements = str_requirements.strip() - value = f"{self.name}/{str_rewards}/{str_requirements}/{self.color}/{self.number_required}" - return key, value - - def remove_rewards(self): - self.rewards = [] - - def change_number_required(self, difference: int): - self.number_required = min(len(self.requirements), max(1, self.number_required + difference)) - if len(self.requirements) == 1 and self.requirements[0].item.item_id == -1: - one_fifth = self.requirements[0].amount / 5 - new_amount = int(self.requirements[0].amount + (difference * one_fifth)) - self.requirements[0] = BundleItem.money_bundle(new_amount) - thousand_amount = int(new_amount / 1000) - dollar_amount = str(new_amount % 1000) - while len(dollar_amount) < 3: - dollar_amount = f"0{dollar_amount}" - self.name = f"{thousand_amount},{dollar_amount}g" - - def randomize_requirements(self, random: Random, - potential_requirements: Union[List[BundleItem], List[List[BundleItem]]]): - if not potential_requirements: - return - - number_to_generate = len(self.requirements) - self.requirements.clear() - if number_to_generate > len(potential_requirements): - choices: Union[BundleItem, List[BundleItem]] = random.choices(potential_requirements, k=number_to_generate) - else: - choices: Union[BundleItem, List[BundleItem]] = random.sample(potential_requirements, number_to_generate) - for choice in choices: - if isinstance(choice, BundleItem): - self.requirements.append(choice) - else: - self.requirements.append(random.choice(choice)) - - def assign_requirements(self, new_requirements: List[BundleItem]) -> List[BundleItem]: - number_to_generate = len(self.requirements) - self.requirements.clear() - for requirement in new_requirements: - self.requirements.append(requirement) - if len(self.requirements) >= number_to_generate: - return new_requirements[number_to_generate:] + return f"{self.name} -> {self.number_required} from {repr(self.items)}" - @staticmethod - def parse_stardew_objects(string_objects: str) -> List[str]: - objects = [] - if len(string_objects) < 5: - return objects - rewards_parts = string_objects.split(" ") - for index in range(0, len(rewards_parts), 3): - objects.append(f"{rewards_parts[index]} {rewards_parts[index + 1]} {rewards_parts[index + 2]}") - return objects + +class BundleTemplate: + room: str + name: str + items: List[BundleItem] + number_possible_items: int + number_required_items: int + + def __init__(self, room: str, name: str, items: List[BundleItem], number_possible_items: int, number_required_items: int): + self.room = room + self.name = name + self.items = items + self.number_possible_items = number_possible_items + self.number_required_items = number_required_items @staticmethod - def parse_stardew_bundle_items(string_objects: str) -> List[BundleItem]: - bundle_items = [] - parts = string_objects.split(" ") - for index in range(0, len(parts), 3): - item_id = int(parts[index]) - bundle_item = BundleItem(all_bundle_items_by_id[item_id].item, - int(parts[index + 1]), - int(parts[index + 2])) - bundle_items.append(bundle_item) - return bundle_items - - # Shuffling the Vault doesn't really work with the stardew system in place - # shuffle_vault_amongst_themselves(random, bundles) \ No newline at end of file + def extend_from(template, items: List[BundleItem]): + return BundleTemplate(template.room, template.name, items, template.number_possible_items, template.number_required_items) + + def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: + number_required = self.number_required_items + price_difference + filtered_items = [item for item in self.items if allow_island_items or not item.requires_island] + number_items = len(filtered_items) + number_chosen_items = self.number_possible_items + if number_chosen_items < number_required: + number_chosen_items = number_required + + if number_chosen_items > number_items: + chosen_items = random.choices(filtered_items, k=number_chosen_items) + else: + chosen_items = random.sample(filtered_items, number_chosen_items) + return Bundle(self.room, self.name, chosen_items, number_required) + + @property + def requires_island(self) -> bool: + return False + + +class IslandBundleTemplate(BundleTemplate): + + @property + def requires_island(self) -> bool: + return True + diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index d5493dc1ec18..7b4ac71b16af 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -1,8 +1,10 @@ from . import fish_data from .museum_data import Mineral +from ..bundles.bundle import BundleTemplate, IslandBundleTemplate from ..bundles.bundle_item import BundleItem, IslandBundleItem from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood +from ..strings.bundle_names import CCRoom, BundleName from ..strings.crop_names import Fruit, Vegetable from ..strings.fish_names import Fish, WaterItem, Trash from ..strings.flower_names import Flower @@ -273,29 +275,52 @@ spring_foraging_items_vanilla = [wild_horseradish, daffodil, leek, dandelion] spring_foraging_items_thematic = [*spring_foraging_items_vanilla, spring_onion, salmonberry, morel] -spring_foraging_bundle_vanilla = Bundle() +spring_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.spring_foraging, spring_foraging_items_vanilla, 4, 4) +spring_foraging_bundle_thematic = BundleTemplate.extend_from(spring_foraging_bundle_vanilla, spring_foraging_items_thematic) summer_foraging_items_vanilla = [grape, spice_berry, sweet_pea] summer_foraging_items_thematic = [*summer_foraging_items_vanilla, fiddlehead_fern, red_mushroom, rainbow_shell] +summer_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.summer_foraging, summer_foraging_items_vanilla, 3, 3) +summer_foraging_bundle_thematic = BundleTemplate.extend_from(summer_foraging_bundle_vanilla, summer_foraging_items_thematic) fall_foraging_items_vanilla = [common_mushroom, wild_plum, hazelnut, blackberry] fall_foraging_items_thematic = [*fall_foraging_items_vanilla, chanterelle] +fall_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.fall_foraging, fall_foraging_items_vanilla, 4, 4) +fall_foraging_bundle_thematic = BundleTemplate.extend_from(fall_foraging_bundle_vanilla, fall_foraging_items_thematic) winter_foraging_items_vanilla = [winter_root, crystal_fruit, snow_yam, crocus] winter_foraging_items_thematic = [*winter_foraging_items_vanilla, holly, nautilus_shell] +winter_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.winter_foraging, winter_foraging_items_vanilla, 4, 4) +winter_foraging_bundle_thematic = BundleTemplate.extend_from(winter_foraging_bundle_vanilla, winter_foraging_items_thematic) construction_items_vanilla = [wood, stone, hardwood] construction_items_thematic = [*construction_items_vanilla, clay, fiber, sap.as_amount(50)] +construction_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.construction, construction_items_vanilla, 4, 4) +construction_bundle_thematic = BundleTemplate.extend_from(construction_bundle_vanilla, construction_items_thematic) exotic_foraging_items_vanilla = [coconut, cactus_fruit, cave_carrot, red_mushroom, purple_mushroom, maple_syrup, oak_resin, pine_tar, morel] exotic_foraging_items_thematic = [*exotic_foraging_items_vanilla, coral, sea_urchin, clam, cockle, mussel, oyster, seaweed] +exotic_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.exotic_foraging, exotic_foraging_items_vanilla, 4, 4) +exotic_foraging_bundle_thematic = BundleTemplate.extend_from(exotic_foraging_bundle_vanilla, exotic_foraging_items_thematic) beach_foraging_items = [nautilus_shell, coral, sea_urchin, rainbow_shell, clam, cockle, mussel, oyster, seaweed] +beach_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.beach_foraging, beach_foraging_items, 4, 4) + mines_foraging_items = [quartz, earth_crystal, frozen_tear, fire_quartz, red_mushroom, purple_mushroom, cave_carrot] +mines_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.mines_foraging, mines_foraging_items, 4, 4) + desert_foraging_items = [cactus_fruit.as_gold_quality(), cactus_fruit.as_amount(5), coconut.as_gold_quality(), coconut.as_amount(5)] +desert_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.desert_foraging, desert_foraging_items, 2, 2) + island_foraging_items = [ginger.as_amount(5), magma_cap.as_gold_quality(), magma_cap.as_amount(5)] +island_foraging_bundle = IslandBundleTemplate(CCRoom.crafts_room, BundleName.island_foraging, island_foraging_items, 2, 2) + sticky_items = [sap.as_amount(500), sap.as_amount(500)] +sticky_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.sticky, sticky_items, 1, 1) + wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] +wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 2, 2) + quality_foraging_items = sorted({item.as_gold_quality().as_amount(1) for item in [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, @@ -400,6 +425,7 @@ common_mushroom.as_amount(20), grape.as_amount(20), spring_onion.as_amount(20)] home_cook_items = [egg.as_amount(10), milk.as_amount(10), wheat_flour.as_amount(100), sugar.as_amount(100), vinegar.as_amount(100), chocolate_cake, pancakes, rhubarb_pie] +bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, green_tea, cranberry_candy] missing_bundle_items = [wine.as_silver_quality(), pale_ale.as_silver_quality(), beer.as_silver_quality(), mead.as_silver_quality(), cheese.as_silver_quality(), diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py new file mode 100644 index 000000000000..0b1e6d3dfbac --- /dev/null +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -0,0 +1,14 @@ +class CCRoom: + pantry = "Pantry" + crafts_room = "Crafts Room" + fish_tank = "Fish Tank" + bulletin_board = "Bulletin Board" + vault = "Vault" + boiler_room = "Boiler Room" + + +class BundleName: + spring_foraging = "Spring Foraging Bundle" + summer_foraging = "Summer Foraging Bundle" + fall_foraging = "Fall Foraging Bundle" + winter_foraging = "Winter Foraging Bundle" From e44228dacbde7f3746bc718b7418134a6789d7d5 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 22 Nov 2023 17:19:30 -0500 Subject: [PATCH 203/482] - started making the bundles --- worlds/stardew_valley/data/bundle_data.py | 31 ++++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 7b4ac71b16af..5d9181adc0db 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -116,6 +116,10 @@ duck_feather = BundleItem(AnimalProduct.duck_feather) duck_egg = BundleItem(AnimalProduct.duck_egg) rabbit_foot = BundleItem(AnimalProduct.rabbit_foot) +dinosaur_egg = BundleItem(AnimalProduct.dinosaur_egg) +void_egg = BundleItem(AnimalProduct.void_egg) +ostrich_egg = IslandBundleItem(AnimalProduct.ostrich_egg) +golden_egg = BundleItem(AnimalProduct.golden_egg) truffle_oil = BundleItem(ArtisanGood.truffle_oil) cloth = BundleItem(ArtisanGood.cloth) @@ -319,29 +323,42 @@ sticky_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.sticky, sticky_items, 1, 1) wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] -wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 2, 2) +wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3) quality_foraging_items = sorted({item.as_gold_quality().as_amount(1) for item in [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, *island_foraging_items]}) +quality_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.quality_foraging, quality_foraging_items, 4, 3) -spring_crop_items_vanilla = [parsnip, green_bean, cauliflower, potato] -spring_crop_items_thematic = [*spring_crop_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice] + +spring_crops_items_vanilla = [parsnip, green_bean, cauliflower, potato] +spring_crops_items_thematic = [*spring_crops_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice] +spring_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.spring_crops, spring_crops_items_vanilla, 4, 4) +spring_crops_bundle_thematic = BundleTemplate.extend_from(spring_crops_bundle_vanilla, spring_crops_items_thematic) summer_crops_items_vanilla = [tomato, hot_pepper, blueberry, melon] summer_crops_items_thematic = [*summer_crops_items_vanilla, corn, hops, poppy, radish, red_cabbage, starfruit, summer_spangle, sunflower, wheat] +summer_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.summer_crops, summer_crops_items_vanilla, 4, 4) +summer_crops_bundle_thematic = BundleTemplate.extend_from(summer_crops_bundle_vanilla, summer_crops_items_thematic) fall_crops_items_vanilla = [corn, eggplant, pumpkin, yam] fall_crops_items_thematic = [*fall_crops_items_vanilla, amaranth, artichoke, beet, bok_choy, cranberries, fairy_rose, grape, sunflower, wheat, sweet_gem_berry] +fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4) +fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic) -all_crops_items = sorted({*spring_crop_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) +all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]] quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items] - -animal_product_items_vanilla = [large_milk, large_brown_egg, large_egg, large_goat_milk, wool, duck_egg] -animal_product_items_thematic = [*animal_product_items_vanilla, egg, brown_egg, milk, goat_milk, truffle, duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg] +quality_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.quality_crops, quality_crops_items_vanilla, 4, 3) +quality_crops_bundle_thematic = BundleTemplate.extend_from(quality_crops_bundle_vanilla, quality_crops_items_thematic) + +animal_items_vanilla = [large_milk, large_brown_egg, large_egg, large_goat_milk, wool, duck_egg] +animal_items_thematic = [*animal_items_vanilla, egg, brown_egg, milk, goat_milk, truffle, + duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg, ostrich_egg] +animal_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.animal, animal_items_vanilla, 4, 3) +animal_bundle_thematic = BundleTemplate.extend_from(animal_bundle_vanilla, animal_items_thematic) artisan_goods_items_vanilla = [truffle_oil, cloth, goat_cheese, cheese, honey, jelly, apple, apricot, orange, peach, pomegranate, cherry] artisan_goods_items_thematic = [*artisan_goods_items_vanilla, beer, juice, mead, pale_ale, wine, pickles, caviar, aged_roe, coffee, green_tea, banana, mango] From 68631de9941bb4aa453693d26d83862dfb613c38 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 23 Nov 2023 00:53:38 -0500 Subject: [PATCH 204/482] - Finally passing all the tests --- worlds/stardew_valley/__init__.py | 19 +- worlds/stardew_valley/bundles/bundle.py | 56 +- worlds/stardew_valley/bundles/bundle_item.py | 57 +- worlds/stardew_valley/bundles/bundle_room.py | 29 + worlds/stardew_valley/bundles/bundles.py | 189 +++--- worlds/stardew_valley/data/bundle_data.py | 416 ++++++++----- worlds/stardew_valley/data/locations.csv | 569 ++++++++++-------- worlds/stardew_valley/data/museum_data.py | 213 ++++--- worlds/stardew_valley/locations.py | 16 +- worlds/stardew_valley/logic/bundle_logic.py | 50 +- worlds/stardew_valley/logic/crop_logic.py | 2 +- worlds/stardew_valley/logic/farming_logic.py | 14 +- worlds/stardew_valley/logic/fishing_logic.py | 13 + worlds/stardew_valley/logic/logic.py | 8 +- worlds/stardew_valley/logic/museum_logic.py | 2 +- worlds/stardew_valley/logic/skill_logic.py | 12 +- worlds/stardew_valley/options.py | 13 +- worlds/stardew_valley/rules.py | 40 +- worlds/stardew_valley/strings/bundle_names.py | 47 ++ worlds/stardew_valley/strings/metal_names.py | 1 + .../stardew_valley/strings/quality_names.py | 68 ++- worlds/stardew_valley/test/TestBundles.py | 26 +- worlds/stardew_valley/test/TestLogic.py | 4 +- worlds/stardew_valley/test/TestOptions.py | 3 +- 24 files changed, 1099 insertions(+), 768 deletions(-) create mode 100644 worlds/stardew_valley/bundles/bundle_room.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 560f93c4f278..658bc396f898 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -5,7 +5,8 @@ from Options import PerGameCommonOptions from worlds.AutoWorld import World, WebWorld from . import rules -from .bundles import get_all_bundles, Bundle +from .bundles.bundle_room import BundleRoom +from .bundles.bundles import get_all_bundles from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData from .logic.bundle_logic import BundleLogic @@ -67,11 +68,10 @@ class StardewValleyWorld(World): options_dataclass = StardewValleyOptions options: StardewValleyOptions - bundle: BundleLogic logic: StardewLogic web = StardewWebWorld() - modified_bundles: Dict[str, Bundle] + modified_bundles: List[BundleRoom] randomized_entrances: Dict[str, str] total_progression_items: int @@ -86,8 +86,7 @@ def generate_early(self): self.logic = StardewLogic(self.player, self.options) self.modified_bundles = get_all_bundles(self.multiworld.random, self.logic, - self.options.bundle_randomization, - self.options.bundle_price) + self.options) def force_change_options_if_incompatible(self): goal_is_walnut_hunter = self.options.goal == Goal.option_greatest_walnut_hunter @@ -115,7 +114,7 @@ def add_location(name: str, code: Optional[int], region: str): location.access_rule = lambda _: True region.locations.append(location) - create_locations(add_location, self.options, self.multiworld.random) + create_locations(add_location, self.modified_bundles, self.options, self.multiworld.random) self.multiworld.regions.extend(world_regions.values()) def create_items(self): @@ -324,12 +323,6 @@ def get_filler_item_rules(self): return self.options.trap_items != TrapItems.option_no_traps, self.options.exclude_ginger_island == ExcludeGingerIsland.option_true def fill_slot_data(self) -> Dict[str, Any]: - - modified_bundles = {} - for bundle_key in self.modified_bundles: - key, value = self.modified_bundles[bundle_key].to_pair() - modified_bundles[key] = value - excluded_options = [BundleRandomization, BundlePrice, NumberOfMovementBuffs, NumberOfLuckBuffs] excluded_option_names = [option.internal_name for option in excluded_options] generic_option_names = [option_name for option_name in PerGameCommonOptions.type_hints] @@ -339,7 +332,7 @@ def fill_slot_data(self) -> Dict[str, Any]: slot_data.update({ "seed": self.multiworld.per_slot_randoms[self.player].randrange(1000000000), # Seed should be max 9 digits "randomized_entrances": self.randomized_entrances, - "modified_bundles": modified_bundles, + "modified_bundles": self.modified_bundles, "client_version": "5.0.0", }) diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index 1b5c5db32749..dd4f0ffc096f 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -1,7 +1,8 @@ from random import Random from typing import List -from worlds.stardew_valley.bundles.bundle_item import BundleItem +from .bundle_item import BundleItem +from ..strings.currency_names import Currency class Bundle: @@ -40,6 +41,9 @@ def extend_from(template, items: List[BundleItem]): def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: number_required = self.number_required_items + price_difference + if price_difference > 0 and self.number_possible_items > 10: + number_required += price_difference + number_required = max(1, number_required) filtered_items = [item for item in self.items if allow_island_items or not item.requires_island] number_items = len(filtered_items) number_chosen_items = self.number_possible_items @@ -47,7 +51,7 @@ def create_bundle(self, price_difference: int, random: Random, allow_island_item number_chosen_items = number_required if number_chosen_items > number_items: - chosen_items = random.choices(filtered_items, k=number_chosen_items) + chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items) else: chosen_items = random.sample(filtered_items, number_chosen_items) return Bundle(self.room, self.name, chosen_items, number_required) @@ -57,9 +61,57 @@ def requires_island(self) -> bool: return False +class CurrencyBundleTemplate(BundleTemplate): + item: BundleItem + + def __init__(self, room: str, item: BundleItem): + super().__init__(room, "", [item], 1, 1) + self.item = item + + def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: + price_multiplier = round(1 + (price_difference * 0.4), 2) + currency_amount = int(self.item.amount * price_multiplier) + currency_name = "g" if self.item.item_name == Currency.money else f" {self.item.item_name}" + if currency_amount >= 1000: + unit_amount = currency_amount % 1000 + unit_amount = "000" if unit_amount == 0 else unit_amount + currency_display = f"{currency_amount // 1000},{unit_amount}" + else: + currency_display = f"{currency_amount}" + name = f"{currency_display}{currency_name} Bundle" + return Bundle(self.room, name, [BundleItem(self.item.item_name, currency_amount)], 1) + + class IslandBundleTemplate(BundleTemplate): @property def requires_island(self) -> bool: return True + +class DeepBundleTemplate(BundleTemplate): + categories: List[List[BundleItem]] + + def __init__(self, room: str, name: str, categories: List[List[BundleItem]], number_possible_items: int, number_required_items: int): + super().__init__(room, name, [], number_possible_items, number_required_items) + self.categories = categories + + def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: + number_required = self.number_required_items + price_difference + number_categories = len(self.categories) + number_chosen_categories = self.number_possible_items + if number_chosen_categories < number_required: + number_chosen_categories = number_required + + if number_chosen_categories > number_categories: + chosen_categories = self.categories + random.choices(self.categories, k=number_chosen_categories - number_categories) + else: + chosen_categories = random.sample(self.categories, number_chosen_categories) + + chosen_items = [] + for category in chosen_categories: + filtered_items = [item for item in category if allow_island_items or not item.requires_island] + chosen_items.append(random.choice(filtered_items)) + + return Bundle(self.room, self.name, chosen_items, number_required) + diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index 3e49d35095ed..168dffc41ecd 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -1,44 +1,42 @@ from dataclasses import dataclass from ..strings.crop_names import Fruit -from ..strings.quality_names import Quality +from ..strings.currency_names import Currency +from ..strings.quality_names import CropQuality, FishQuality, ForageQuality @dataclass(frozen=True) class BundleItem: - item: str + item_name: str amount: int = 1 - quality: str = Quality.basic + quality: str = CropQuality.basic @staticmethod def money_bundle(amount: int): - return BundleItem("Money", amount) + return BundleItem(Currency.money, amount) def as_amount(self, amount: int): - return BundleItem(self.item, amount, self.quality) + return BundleItem(self.item_name, amount, self.quality) def as_quality(self, quality: str): - return BundleItem(self.item, self.amount, quality) - - def as_silver_quality(self): - return self.as_quality(Quality.silver) - - def as_gold_quality(self): - return self.as_quality(Quality.gold) + return BundleItem(self.item_name, self.amount, quality) def as_quality_crop(self): amount = 5 difficult_crops = [Fruit.sweet_gem_berry, Fruit.ancient_fruit] - if self.item in difficult_crops: + if self.item_name in difficult_crops: amount = 1 - return self.as_gold_quality().as_amount(amount) + return self.as_quality(CropQuality.gold).as_amount(amount) - def is_gold_quality(self) -> bool: - return self.quality == Quality.gold or self.quality == Quality.iridium + def as_quality_fish(self): + return self.as_quality(FishQuality.gold) + + def as_quality_forage(self): + return self.as_quality(ForageQuality.gold) def __repr__(self): - quality = "" if self.quality == Quality.basic else self.quality - return f"{self.amount} {quality} {self.item}" + quality = "" if self.quality == CropQuality.basic else self.quality + return f"{self.amount} {quality} {self.item_name}" @property def requires_island(self) -> bool: @@ -47,6 +45,29 @@ def requires_island(self) -> bool: class IslandBundleItem(BundleItem): + def as_amount(self, amount: int): + return IslandBundleItem(self.item_name, amount, self.quality) + + def as_quality(self, quality: str): + return IslandBundleItem(self.item_name, self.amount, quality) + + def as_quality_crop(self): + amount = 5 + difficult_crops = [Fruit.sweet_gem_berry, Fruit.ancient_fruit] + if self.item_name in difficult_crops: + amount = 1 + return self.as_quality(CropQuality.gold).as_amount(amount) + + def as_quality_fish(self): + return self.as_quality(FishQuality.gold) + + def as_quality_forage(self): + return self.as_quality(ForageQuality.gold) + + def __repr__(self): + quality = "" if self.quality == CropQuality.basic else self.quality + return f"{self.amount} {quality} {self.item_name} [ISLAND]" + @property def requires_island(self) -> bool: return True diff --git a/worlds/stardew_valley/bundles/bundle_room.py b/worlds/stardew_valley/bundles/bundle_room.py new file mode 100644 index 000000000000..b2c84a1fa9c0 --- /dev/null +++ b/worlds/stardew_valley/bundles/bundle_room.py @@ -0,0 +1,29 @@ +from random import Random +from typing import List + +from .bundle import Bundle, BundleTemplate + + +class BundleRoom: + name: str + bundles: List[Bundle] + + def __init__(self, name: str, bundles: List[Bundle]): + self.name = name + self.bundles = bundles + + +class BundleRoomTemplate: + name: str + bundles: List[BundleTemplate] + number_bundles: int + + def __init__(self, name: str, bundles: List[BundleTemplate], number_bundles: int): + self.name = name + self.bundles = bundles + self.number_bundles = number_bundles + + def create_bundle_room(self, price_difference: int, random: Random, allow_island_items: bool): + filtered_bundles = [bundle for bundle in self.bundles if allow_island_items or not bundle.requires_island] + chosen_bundles = random.sample(filtered_bundles, self.number_bundles) + return BundleRoom(self.name, [bundle.create_bundle(price_difference, random, allow_island_items) for bundle in chosen_bundles]) diff --git a/worlds/stardew_valley/bundles/bundles.py b/worlds/stardew_valley/bundles/bundles.py index aac518f21579..64da9f1c62f6 100644 --- a/worlds/stardew_valley/bundles/bundles.py +++ b/worlds/stardew_valley/bundles/bundles.py @@ -1,113 +1,80 @@ from random import Random -from typing import List, Dict, Union +from typing import List + +from .bundle_room import BundleRoom +from ..data.bundle_data import pantry_vanilla, crafts_room_vanilla, fish_tank_vanilla, boiler_room_vanilla, bulletin_board_vanilla, vault_vanilla, \ + pantry_thematic, crafts_room_thematic, fish_tank_thematic, boiler_room_thematic, bulletin_board_thematic, vault_thematic, pantry_remixed, \ + crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed, vault_remixed, all_bundle_items_except_money +from ..logic.logic import StardewLogic +from ..options import BundleRandomization, StardewValleyOptions, ExcludeGingerIsland + + +def get_all_bundles(random: Random, logic: StardewLogic, options: StardewValleyOptions) -> List[BundleRoom]: + if options.bundle_randomization == BundleRandomization.option_vanilla: + return get_vanilla_bundles(random, options) + elif options.bundle_randomization == BundleRandomization.option_thematic: + return get_thematic_bundles(random, options) + elif options.bundle_randomization == BundleRandomization.option_remixed: + return get_remixed_bundles(random, options) + elif options.bundle_randomization == BundleRandomization.option_shuffled: + return get_shuffled_bundles(random, logic, options) + + raise NotImplementedError + + +def get_vanilla_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: + allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false + pantry = pantry_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + crafts_room = crafts_room_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + fish_tank = fish_tank_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + boiler_room = boiler_room_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + bulletin_board = bulletin_board_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + vault = vault_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault] + + +def get_thematic_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: + allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false + pantry = pantry_thematic.create_bundle_room(options.bundle_price, random, allow_island) + crafts_room = crafts_room_thematic.create_bundle_room(options.bundle_price, random, allow_island) + fish_tank = fish_tank_thematic.create_bundle_room(options.bundle_price, random, allow_island) + boiler_room = boiler_room_thematic.create_bundle_room(options.bundle_price, random, allow_island) + bulletin_board = bulletin_board_thematic.create_bundle_room(options.bundle_price, random, allow_island) + vault = vault_thematic.create_bundle_room(options.bundle_price, random, allow_island) + return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault] + + +def get_remixed_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: + allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false + pantry = pantry_remixed.create_bundle_room(options.bundle_price, random, allow_island) + crafts_room = crafts_room_remixed.create_bundle_room(options.bundle_price, random, allow_island) + fish_tank = fish_tank_remixed.create_bundle_room(options.bundle_price, random, allow_island) + boiler_room = boiler_room_remixed.create_bundle_room(options.bundle_price, random, allow_island) + bulletin_board = bulletin_board_remixed.create_bundle_room(options.bundle_price, random, allow_island) + vault = vault_remixed.create_bundle_room(options.bundle_price, random, allow_island) + return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault] + + +def get_shuffled_bundles(random: Random, logic: StardewLogic, options: StardewValleyOptions) -> List[BundleRoom]: + allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false + valid_bundle_items = [bundle_item for bundle_item in all_bundle_items_except_money if allow_island or not bundle_item.requires_island] + + rooms = [room for room in get_remixed_bundles(random, options) if room.name != "Vault"] + required_items = 0 + for room in rooms: + for bundle in room.bundles: + required_items += len(bundle.items) + random.shuffle(room.bundles) + random.shuffle(rooms) + + chosen_bundle_items = random.sample(valid_bundle_items, required_items) + sorted_bundle_items = sorted(chosen_bundle_items, key=lambda x: logic.has(x.item_name).get_difficulty()) + for room in rooms: + for bundle in room.bundles: + num_items = len(bundle.items) + bundle.items = sorted_bundle_items[:num_items] + sorted_bundle_items = sorted_bundle_items[num_items:] + + vault = vault_remixed.create_bundle_room(options.bundle_price, random, allow_island) + return [*rooms, vault] -from worlds.stardew_valley.logic.logic import StardewLogic -from worlds.stardew_valley.data.bundle_data import * -from worlds.stardew_valley.options import BundleRandomization, BundlePrice - - -def get_all_bundles(random: Random, logic: StardewLogic, randomization: BundleRandomization, price: BundlePrice) -> Dict[str, Bundle]: - bundles = {} - for bundle_key in vanilla_bundles: - bundle_value = vanilla_bundles[bundle_key] - bundle = Bundle(bundle_key, bundle_value) - bundles[bundle.get_name_with_bundle()] = bundle - - if randomization == BundleRandomization.option_thematic: - shuffle_bundles_thematically(random, bundles) - elif randomization == BundleRandomization.option_shuffled: - shuffle_bundles_completely(random, logic, bundles) - - price_difference = 0 - if price == BundlePrice.option_very_cheap: - price_difference = -2 - elif price == BundlePrice.option_cheap: - price_difference = -1 - elif price == BundlePrice.option_expensive: - price_difference = 1 - - for bundle_key in bundles: - bundles[bundle_key].remove_rewards() - bundles[bundle_key].change_number_required(price_difference) - - return bundles - - -def shuffle_bundles_completely(random: Random, logic: StardewLogic, bundles: Dict[str, Bundle]): - total_required_item_number = sum(len(bundle.requirements) for bundle in bundles.values()) - quality_crops_items_set = set(quality_crops_items) - all_bundle_items_without_quality_and_money = [item - for item in all_bundle_items_except_money - if item not in quality_crops_items_set] + \ - random.sample(quality_crops_items, 10) - choices = random.sample(all_bundle_items_without_quality_and_money, total_required_item_number - 4) - - items_sorted = sorted(choices, key=lambda x: logic.item_rules[x.item.name].get_difficulty()) - - keys = sorted(bundles.keys()) - random.shuffle(keys) - - for key in keys: - if not bundles[key].original_name.endswith("00g"): - items_sorted = bundles[key].assign_requirements(items_sorted) - - -def shuffle_bundles_thematically(random: Random, bundles: Dict[str, Bundle]): - shuffle_crafts_room_bundle_thematically(random, bundles) - shuffle_pantry_bundle_thematically(random, bundles) - shuffle_fish_tank_thematically(random, bundles) - shuffle_boiler_room_thematically(random, bundles) - shuffle_bulletin_board_thematically(random, bundles) - shuffle_abandoned_jojamart_thematically(random, bundles) - - -def shuffle_crafts_room_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Spring Foraging Bundle"].randomize_requirements(random, spring_foraging_items) - bundles["Summer Foraging Bundle"].randomize_requirements(random, summer_foraging_items) - bundles["Fall Foraging Bundle"].randomize_requirements(random, fall_foraging_items) - bundles["Winter Foraging Bundle"].randomize_requirements(random, winter_foraging_items) - bundles["Exotic Foraging Bundle"].randomize_requirements(random, exotic_foraging_items) - bundles["Construction Bundle"].randomize_requirements(random, construction_items) - - -def shuffle_pantry_bundle_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Spring Crops Bundle"].randomize_requirements(random, spring_crop_items) - bundles["Summer Crops Bundle"].randomize_requirements(random, summer_crops_items) - bundles["Fall Crops Bundle"].randomize_requirements(random, fall_crops_items) - bundles["Quality Crops Bundle"].randomize_requirements(random, quality_crops_items) - bundles["Animal Bundle"].randomize_requirements(random, animal_product_items) - bundles["Artisan Bundle"].randomize_requirements(random, artisan_goods_items) - - -def shuffle_fish_tank_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["River Fish Bundle"].randomize_requirements(random, river_fish_items) - bundles["Lake Fish Bundle"].randomize_requirements(random, lake_fish_items) - bundles["Ocean Fish Bundle"].randomize_requirements(random, ocean_fish_items) - bundles["Night Fishing Bundle"].randomize_requirements(random, night_fish_items) - bundles["Crab Pot Bundle"].randomize_requirements(random, crab_pot_items) - bundles["Specialty Fish Bundle"].randomize_requirements(random, specialty_fish_items) - - -def shuffle_boiler_room_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Blacksmith's Bundle"].randomize_requirements(random, blacksmith_items) - bundles["Geologist's Bundle"].randomize_requirements(random, geologist_items) - bundles["Adventurer's Bundle"].randomize_requirements(random, adventurer_items) - - -def shuffle_bulletin_board_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["Chef's Bundle"].randomize_requirements(random, chef_items) - bundles["Dye Bundle"].randomize_requirements(random, dye_items) - bundles["Field Research Bundle"].randomize_requirements(random, field_research_items) - bundles["Fodder Bundle"].randomize_requirements(random, fodder_items) - bundles["Enchanter's Bundle"].randomize_requirements(random, enchanter_items) - - -def shuffle_abandoned_jojamart_thematically(random: Random, bundles: Dict[str, Bundle]): - bundles["The Missing Bundle"].randomize_requirements(random, missing_bundle_items) - - -def shuffle_vault_amongst_themselves(random: Random, bundles: Dict[str, Bundle]): - bundles["2,500g Bundle"].randomize_requirements(random, vault_bundle_items) - bundles["5,000g Bundle"].randomize_requirements(random, vault_bundle_items) - bundles["10,000g Bundle"].randomize_requirements(random, vault_bundle_items) - bundles["25,000g Bundle"].randomize_requirements(random, vault_bundle_items) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 5d9181adc0db..d15e4ec3152b 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -1,7 +1,6 @@ -from . import fish_data -from .museum_data import Mineral -from ..bundles.bundle import BundleTemplate, IslandBundleTemplate +from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate from ..bundles.bundle_item import BundleItem, IslandBundleItem +from ..bundles.bundle_room import BundleRoomTemplate from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.bundle_names import CCRoom, BundleName @@ -12,9 +11,11 @@ from ..strings.forageable_names import Forageable from ..strings.geode_names import Geode from ..strings.gift_names import Gift +from ..strings.ingredient_names import Ingredient from ..strings.material_names import Material -from ..strings.metal_names import MetalBar, Artifact, Fossil +from ..strings.metal_names import MetalBar, Artifact, Fossil, Ore, Mineral from ..strings.monster_drop_names import Loot +from ..strings.quality_names import ForageQuality, ArtisanQuality, FishQuality from ..strings.seed_names import Seed wild_horseradish = BundleItem(Forageable.wild_horseradish) @@ -54,10 +55,10 @@ coral = BundleItem(WaterItem.coral) sea_urchin = BundleItem(WaterItem.sea_urchin) rainbow_shell = BundleItem(Forageable.rainbow_shell) -clam = BundleItem(fish_data.clam) -cockle = BundleItem(fish_data.cockle) -mussel = BundleItem(fish_data.mussel) -oyster = BundleItem(fish_data.oyster) +clam = BundleItem(Fish.clam) +cockle = BundleItem(Fish.cockle) +mussel = BundleItem(Fish.mussel) +oyster = BundleItem(Fish.oyster) seaweed = BundleItem(WaterItem.seaweed) wood = BundleItem(Material.wood, 99) @@ -102,6 +103,8 @@ red_cabbage = BundleItem(Vegetable.red_cabbage) starfruit = BundleItem(Fruit.starfruit) artichoke = BundleItem(Vegetable.artichoke) +pineapple = IslandBundleItem(Fruit.pineapple) +taro_root = IslandBundleItem(Vegetable.taro_root) egg = BundleItem(AnimalProduct.egg) large_egg = BundleItem(AnimalProduct.large_egg) @@ -135,6 +138,8 @@ pickles = BundleItem(ArtisanGood.pickles) caviar = BundleItem(ArtisanGood.caviar) aged_roe = BundleItem(ArtisanGood.aged_roe) +roe = BundleItem(AnimalProduct.roe) +squid_ink = BundleItem(AnimalProduct.squid_ink) coffee = BundleItem(Beverage.coffee) green_tea = BundleItem(ArtisanGood.green_tea) apple = BundleItem(Fruit.apple) @@ -143,60 +148,62 @@ peach = BundleItem(Fruit.peach) pomegranate = BundleItem(Fruit.pomegranate) cherry = BundleItem(Fruit.cherry) -lobster = BundleItem(fish_data.lobster) -crab = BundleItem(fish_data.crab) -shrimp = BundleItem(fish_data.shrimp) -crayfish = BundleItem(fish_data.crayfish) -snail = BundleItem(fish_data.snail) -periwinkle = BundleItem(fish_data.periwinkle) +banana = IslandBundleItem(Fruit.banana) +mango = IslandBundleItem(Fruit.mango) +lobster = BundleItem(Fish.lobster) +crab = BundleItem(Fish.crab) +shrimp = BundleItem(Fish.shrimp) +crayfish = BundleItem(Fish.crayfish) +snail = BundleItem(Fish.snail) +periwinkle = BundleItem(Fish.periwinkle) trash = BundleItem(Trash.trash) driftwood = BundleItem(Trash.driftwood) soggy_newspaper = BundleItem(Trash.soggy_newspaper) broken_cd = BundleItem(Trash.broken_cd) broken_glasses = BundleItem(Trash.broken_glasses) -chub = BundleItem(fish_data.chub) -catfish = BundleItem(fish_data.catfish) -rainbow_trout = BundleItem(fish_data.rainbow_trout) -lingcod = BundleItem(fish_data.lingcod) -walleye = BundleItem(fish_data.walleye) -perch = BundleItem(fish_data.perch) -pike = BundleItem(fish_data.pike) -bream = BundleItem(fish_data.bream) -salmon = BundleItem(fish_data.salmon) -sunfish = BundleItem(fish_data.sunfish) -tiger_trout = BundleItem(fish_data.tiger_trout) -shad = BundleItem(fish_data.shad) -smallmouth_bass = BundleItem(fish_data.smallmouth_bass) -dorado = BundleItem(fish_data.dorado) -carp = BundleItem(fish_data.carp) -midnight_carp = BundleItem(fish_data.midnight_carp) -largemouth_bass = BundleItem(fish_data.largemouth_bass) -sturgeon = BundleItem(fish_data.sturgeon) -bullhead = BundleItem(fish_data.bullhead) -tilapia = BundleItem(fish_data.tilapia) -pufferfish = BundleItem(fish_data.pufferfish) -tuna = BundleItem(fish_data.tuna) -super_cucumber = BundleItem(fish_data.super_cucumber) -flounder = BundleItem(fish_data.flounder) -anchovy = BundleItem(fish_data.anchovy) -sardine = BundleItem(fish_data.sardine) -red_mullet = BundleItem(fish_data.red_mullet) -herring = BundleItem(fish_data.herring) -eel = BundleItem(fish_data.eel) -octopus = BundleItem(fish_data.octopus) -red_snapper = BundleItem(fish_data.red_snapper) -squid = BundleItem(fish_data.squid) -sea_cucumber = BundleItem(fish_data.sea_cucumber) -albacore = BundleItem(fish_data.albacore) -halibut = BundleItem(fish_data.halibut) -scorpion_carp = BundleItem(fish_data.scorpion_carp) -sandfish = BundleItem(fish_data.sandfish) -woodskip = BundleItem(fish_data.woodskip) -lava_eel = BundleItem(fish_data.lava_eel) -ice_pip = BundleItem(fish_data.ice_pip) -stonefish = BundleItem(fish_data.stonefish) -ghostfish = BundleItem(fish_data.ghostfish) +chub = BundleItem(Fish.chub) +catfish = BundleItem(Fish.catfish) +rainbow_trout = BundleItem(Fish.rainbow_trout) +lingcod = BundleItem(Fish.lingcod) +walleye = BundleItem(Fish.walleye) +perch = BundleItem(Fish.perch) +pike = BundleItem(Fish.pike) +bream = BundleItem(Fish.bream) +salmon = BundleItem(Fish.salmon) +sunfish = BundleItem(Fish.sunfish) +tiger_trout = BundleItem(Fish.tiger_trout) +shad = BundleItem(Fish.shad) +smallmouth_bass = BundleItem(Fish.smallmouth_bass) +dorado = BundleItem(Fish.dorado) +carp = BundleItem(Fish.carp) +midnight_carp = BundleItem(Fish.midnight_carp) +largemouth_bass = BundleItem(Fish.largemouth_bass) +sturgeon = BundleItem(Fish.sturgeon) +bullhead = BundleItem(Fish.bullhead) +tilapia = BundleItem(Fish.tilapia) +pufferfish = BundleItem(Fish.pufferfish) +tuna = BundleItem(Fish.tuna) +super_cucumber = BundleItem(Fish.super_cucumber) +flounder = BundleItem(Fish.flounder) +anchovy = BundleItem(Fish.anchovy) +sardine = BundleItem(Fish.sardine) +red_mullet = BundleItem(Fish.red_mullet) +herring = BundleItem(Fish.herring) +eel = BundleItem(Fish.eel) +octopus = BundleItem(Fish.octopus) +red_snapper = BundleItem(Fish.red_snapper) +squid = BundleItem(Fish.squid) +sea_cucumber = BundleItem(Fish.sea_cucumber) +albacore = BundleItem(Fish.albacore) +halibut = BundleItem(Fish.halibut) +scorpion_carp = BundleItem(Fish.scorpion_carp) +sandfish = BundleItem(Fish.sandfish) +woodskip = BundleItem(Fish.woodskip) +lava_eel = BundleItem(Fish.lava_eel) +ice_pip = BundleItem(Fish.ice_pip) +stonefish = BundleItem(Fish.stonefish) +ghostfish = BundleItem(Fish.ghostfish) wilted_bouquet = BundleItem(Gift.wilted_bouquet) copper_bar = BundleItem(MetalBar.copper) @@ -205,6 +212,8 @@ iridium_bar = BundleItem(MetalBar.iridium) refined_quartz = BundleItem(MetalBar.quartz) coal = BundleItem(Material.coal, 5) +iridium_ore = BundleItem(Ore.iridium) +battery_pack = BundleItem(ArtisanGood.battery_pack) quartz = BundleItem(Mineral.quartz) fire_quartz = BundleItem(Mineral.fire_quartz) @@ -249,6 +258,17 @@ algae_soup = BundleItem(Meal.algae_soup) pale_broth = BundleItem(Meal.pale_broth) chowder = BundleItem(Meal.chowder) +cookie = BundleItem(Meal.cookie) +ancient_doll = BundleItem(Artifact.ancient_doll) +ice_cream = BundleItem(Meal.ice_cream) +cranberry_candy = BundleItem(Meal.cranberry_candy) +ginger_ale = IslandBundleItem(Beverage.ginger_ale) +pink_cake = BundleItem(Meal.pink_cake) +plum_pudding = BundleItem(Meal.plum_pudding) +chocolate_cake = BundleItem(Meal.chocolate_cake) +rhubarb_pie = BundleItem(Meal.rhubarb_pie) +shrimp_cocktail = BundleItem(Meal.shrimp_cocktail) + green_algae = BundleItem(WaterItem.green_algae) white_algae = BundleItem(WaterItem.white_algae) geode = BundleItem(Geode.geode) @@ -264,6 +284,7 @@ elvish_jewelry = BundleItem(Artifact.elvish_jewelry) ancient_drum = BundleItem(Artifact.ancient_drum) dried_starfish = BundleItem(Fossil.dried_starfish) +bone_fragment = BundleItem(Fossil.bone_fragment) dinosaur_mayo = BundleItem(ArtisanGood.dinosaur_mayonnaise) void_mayo = BundleItem(ArtisanGood.void_mayonnaise) @@ -273,10 +294,27 @@ void_salmon = BundleItem(Fish.void_salmon) tea_leaves = BundleItem(Vegetable.tea_leaves) blobfish = BundleItem(Fish.blobfish) +lionfish = IslandBundleItem(Fish.lionfish) +blue_discus = IslandBundleItem(Fish.blue_discus) +stingray = IslandBundleItem(Fish.stingray) +spookfish = BundleItem(Fish.spookfish) +midnight_squid = BundleItem(Fish.midnight_squid) + +angler = BundleItem(Fish.angler) +crimsonfish = BundleItem(Fish.crimsonfish) +mutant_carp = BundleItem(Fish.mutant_carp) +glacierfish = BundleItem(Fish.glacierfish) +legend = BundleItem(Fish.legend) ginger = IslandBundleItem(Forageable.ginger) magma_cap = IslandBundleItem(Forageable.magma_cap) +wheat_flour = BundleItem(Ingredient.wheat_flour) +sugar = BundleItem(Ingredient.sugar) +vinegar = BundleItem(Ingredient.vinegar) + + +# Crafts Room spring_foraging_items_vanilla = [wild_horseradish, daffodil, leek, dandelion] spring_foraging_items_thematic = [*spring_foraging_items_vanilla, spring_onion, salmonberry, morel] spring_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.spring_foraging, spring_foraging_items_vanilla, 4, 4) @@ -313,10 +351,10 @@ mines_foraging_items = [quartz, earth_crystal, frozen_tear, fire_quartz, red_mushroom, purple_mushroom, cave_carrot] mines_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.mines_foraging, mines_foraging_items, 4, 4) -desert_foraging_items = [cactus_fruit.as_gold_quality(), cactus_fruit.as_amount(5), coconut.as_gold_quality(), coconut.as_amount(5)] +desert_foraging_items = [cactus_fruit.as_quality(ForageQuality.gold), cactus_fruit.as_amount(5), coconut.as_quality(ForageQuality.gold), coconut.as_amount(5)] desert_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.desert_foraging, desert_foraging_items, 2, 2) -island_foraging_items = [ginger.as_amount(5), magma_cap.as_gold_quality(), magma_cap.as_amount(5)] +island_foraging_items = [ginger.as_amount(5), magma_cap.as_quality(ForageQuality.gold), magma_cap.as_amount(5)] island_foraging_bundle = IslandBundleTemplate(CCRoom.crafts_room, BundleName.island_foraging, island_foraging_items, 2, 2) sticky_items = [sap.as_amount(500), sap.as_amount(500)] @@ -325,13 +363,24 @@ wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3) -quality_foraging_items = sorted({item.as_gold_quality().as_amount(1) - for item in - [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, - *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, *island_foraging_items]}) +quality_foraging_items = list({item.as_quality(ForageQuality.gold).as_amount(1) + for item in + [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, + *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, *island_foraging_items]}) quality_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.quality_foraging, quality_foraging_items, 4, 3) +crafts_room_bundles_vanilla = [spring_foraging_bundle_vanilla, summer_foraging_bundle_vanilla, fall_foraging_bundle_vanilla, + winter_foraging_bundle_vanilla, construction_bundle_vanilla, exotic_foraging_bundle_vanilla] +crafts_room_bundles_thematic = [spring_foraging_bundle_thematic, summer_foraging_bundle_thematic, fall_foraging_bundle_thematic, + winter_foraging_bundle_thematic, construction_bundle_thematic, exotic_foraging_bundle_thematic] +crafts_room_bundles_remixed = [*crafts_room_bundles_thematic, beach_foraging_bundle, mines_foraging_bundle, desert_foraging_bundle, + island_foraging_bundle, sticky_bundle, wild_medicine_bundle, quality_foraging_bundle] +crafts_room_vanilla = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_vanilla, 6) +crafts_room_thematic = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_thematic, 6) +crafts_room_remixed = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_remixed, 6) + +# Pantry spring_crops_items_vanilla = [parsnip, green_bean, cauliflower, potato] spring_crops_items_thematic = [*spring_crops_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice] spring_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.spring_crops, spring_crops_items_vanilla, 4, 4) @@ -347,7 +396,7 @@ fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4) fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic) -all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) +all_crops_items = list({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]] quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items] @@ -356,64 +405,138 @@ animal_items_vanilla = [large_milk, large_brown_egg, large_egg, large_goat_milk, wool, duck_egg] animal_items_thematic = [*animal_items_vanilla, egg, brown_egg, milk, goat_milk, truffle, - duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg, ostrich_egg] -animal_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.animal, animal_items_vanilla, 4, 3) + duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg, ostrich_egg] +animal_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.animal, animal_items_vanilla, 6, 5) animal_bundle_thematic = BundleTemplate.extend_from(animal_bundle_vanilla, animal_items_thematic) -artisan_goods_items_vanilla = [truffle_oil, cloth, goat_cheese, cheese, honey, jelly, apple, apricot, orange, peach, pomegranate, cherry] -artisan_goods_items_thematic = [*artisan_goods_items_vanilla, beer, juice, mead, pale_ale, wine, pickles, caviar, aged_roe, coffee, green_tea, banana, mango] +artisan_items_vanilla = [truffle_oil, cloth, goat_cheese, cheese, honey, jelly, apple, apricot, orange, peach, pomegranate, cherry] +artisan_items_thematic = [*artisan_items_vanilla, beer, juice, mead, pale_ale, wine, pickles, caviar, aged_roe, coffee, green_tea, banana, mango] +artisan_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.artisan, artisan_items_vanilla, 12, 6) +artisan_bundle_thematic = BundleTemplate.extend_from(artisan_bundle_vanilla, artisan_items_thematic) -# Where to put Tea Leaves and Fiber? rare_crops_items = [ancient_fruit, sweet_gem_berry] -fish_farmer_items = [row.as_amount(15), aged_roe.as_amount(15), squid_ink] +rare_crops_bundle = BundleTemplate(CCRoom.pantry, BundleName.rare_crops, rare_crops_items, 2, 2) + +fish_farmer_items = [roe.as_amount(15), aged_roe.as_amount(15), squid_ink] +fish_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.fish_farmer, fish_farmer_items, 3, 2) + garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose] +garden_bundle = BundleTemplate(CCRoom.pantry, BundleName.garden, garden_items, 5, 4) + brewer_items = [mead, pale_ale, wine, juice, green_tea] +brewer_bundle = BundleTemplate(CCRoom.pantry, BundleName.brewer, brewer_items, 5, 4) + orchard_items = [apple, apricot, orange, peach, pomegranate, cherry, banana, mango] +orchard_bundle = BundleTemplate(CCRoom.pantry, BundleName.orchard, orchard_items, 6, 4) + island_crops_items = [pineapple, taro_root, banana, mango] +island_crops_bundle = IslandBundleTemplate(CCRoom.pantry, BundleName.island_crops, island_crops_items, 3, 3) +pantry_bundles_vanilla = [spring_crops_bundle_vanilla, summer_crops_bundle_vanilla, fall_crops_bundle_vanilla, + quality_crops_bundle_vanilla, animal_bundle_vanilla, artisan_bundle_vanilla] +pantry_bundles_thematic = [spring_crops_bundle_thematic, summer_crops_bundle_thematic, fall_crops_bundle_thematic, + quality_crops_bundle_thematic, animal_bundle_thematic, artisan_bundle_thematic] +pantry_bundles_remixed = [*pantry_bundles_thematic, rare_crops_bundle, fish_farmer_bundle, garden_bundle, + brewer_bundle, orchard_bundle, island_crops_bundle] +pantry_vanilla = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_vanilla, 6) +pantry_thematic = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_thematic, 6) +pantry_remixed = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_remixed, 6) + +# Fish Tank river_fish_items_vanilla = [sunfish, catfish, shad, tiger_trout] river_fish_items_thematic = [*river_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, pike, bream, salmon, smallmouth_bass, dorado] +river_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.river_fish, river_fish_items_vanilla, 4, 4) +river_fish_bundle_thematic = BundleTemplate.extend_from(river_fish_bundle_vanilla, river_fish_items_thematic) lake_fish_items_vanilla = [largemouth_bass, carp, bullhead, sturgeon] lake_fish_items_thematic = [*lake_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, midnight_carp] +lake_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.lake_fish, lake_fish_items_vanilla, 4, 4) +lake_fish_bundle_thematic = BundleTemplate.extend_from(lake_fish_bundle_vanilla, lake_fish_items_thematic) ocean_fish_items_vanilla = [sardine, tuna, red_snapper, tilapia] -ocean_fish_items_thematic = [*ocean_fish_items_vanilla, pufferfish, super_cucumber, flounder, anchovy, red_mullet, herring, eel, octopus, squid, sea_cucumber, albacore, halibut] +ocean_fish_items_thematic = [*ocean_fish_items_vanilla, pufferfish, super_cucumber, flounder, anchovy, red_mullet, + herring, eel, octopus, squid, sea_cucumber, albacore, halibut] +ocean_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.ocean_fish, ocean_fish_items_vanilla, 4, 4) +ocean_fish_bundle_thematic = BundleTemplate.extend_from(ocean_fish_bundle_vanilla, ocean_fish_items_thematic) night_fish_items_vanilla = [walleye, bream, eel] night_fish_items_thematic = [*night_fish_items_vanilla, super_cucumber, squid, midnight_carp] - -specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip] -specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip, stonefish, void_salmon, stingray, spookfish, midnight_squid] +night_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.night_fish, night_fish_items_vanilla, 3, 3) +night_fish_bundle_thematic = BundleTemplate.extend_from(night_fish_bundle_vanilla, night_fish_items_thematic) crab_pot_items_vanilla = [lobster, crayfish, crab, cockle, mussel, shrimp, snail, periwinkle, oyster, clam] crab_pot_items_thematic = [*crab_pot_items_vanilla, trash, driftwood, soggy_newspaper, broken_cd, broken_glasses] +crab_pot_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.crab_pot, crab_pot_items_vanilla, 10, 5) +crab_pot_bundle_thematic = BundleTemplate.extend_from(crab_pot_bundle_vanilla, crab_pot_items_thematic) + +specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip] +specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip, + stonefish, void_salmon, stingray, spookfish, midnight_squid] +specialty_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.specialty_fish, specialty_fish_items_vanilla, 4, 4) +specialty_fish_bundle_thematic = BundleTemplate.extend_from(specialty_fish_bundle_vanilla, specialty_fish_items_thematic) + +quality_fish_items = list({item.as_quality(FishQuality.gold) for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]}) +quality_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.quality_fish, quality_fish_items, 4, 4) -quality_fish_items = sorted({item.as_gold_quality() for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]}) master_fisher_items = [lava_eel, scorpion_carp, octopus, blobfish, lingcod, ice_pip, super_cucumber, stingray, void_salmon, pufferfish] -legendary_fish_items = [angler, legend, mutant carp, crimsonfish, glacierfish] +master_fisher_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.master_fisher, master_fisher_items, 4, 2) + +legendary_fish_items = [angler, legend, mutant_carp, crimsonfish, glacierfish] +legendary_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.legendary_fish, legendary_fish_items, 4, 2) + +island_fish_items = [lionfish, blue_discus, stingray] +island_fish_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.island_fish, island_fish_items, 3, 3) + +fish_tank_bundles_vanilla = [river_fish_bundle_vanilla, lake_fish_bundle_vanilla, ocean_fish_bundle_vanilla, + night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla] +fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic, + night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic] +fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle] +fish_tank_vanilla = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_vanilla, 6) +fish_tank_thematic = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_thematic, 6) +fish_tank_remixed = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_remixed, 6) +# Boiler Room blacksmith_items_vanilla = [copper_bar, iron_Bar, gold_bar] blacksmith_items_thematic = [*blacksmith_items_vanilla, iridium_bar, refined_quartz.as_amount(3), wilted_bouquet] +blacksmith_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.blacksmith, blacksmith_items_vanilla, 3, 3) +blacksmith_bundle_thematic = BundleTemplate.extend_from(blacksmith_bundle_vanilla, blacksmith_items_thematic) geologist_items_vanilla = [quartz, earth_crystal, frozen_tear, fire_quartz] geologist_items_thematic = [*geologist_items_vanilla, emerald, aquamarine, ruby, amethyst, topaz, jade, diamond] +geologist_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.geologist, geologist_items_vanilla, 4, 4) +geologist_bundle_thematic = BundleTemplate.extend_from(geologist_bundle_vanilla, geologist_items_thematic) adventurer_items_vanilla = [slime, bat_wing, solar_essence, void_essence] adventurer_items_thematic = [*adventurer_items_vanilla, bug_meat, coal, bone_fragment.as_amount(10)] +adventurer_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.adventurer, adventurer_items_vanilla, 4, 2) +adventurer_bundle_thematic = BundleTemplate.extend_from(adventurer_bundle_vanilla, adventurer_items_thematic) # Where to put radioactive bar? treasure_hunter_items = [emerald, aquamarine, ruby, amethyst, topaz, jade, diamond] +treasure_hunter_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.treasure_hunter, treasure_hunter_items, 6, 5) + engineer_items = [iridium_ore.as_amount(5), battery_pack, refined_quartz.as_amount(5), diamond] +engineer_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.engineer, engineer_items, 3, 3) + +boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla] +boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic] +boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle] +boiler_room_vanilla = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_vanilla, 3) +boiler_room_thematic = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_thematic, 3) +boiler_room_remixed = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_remixed, 3) +# Bulletin Board chef_items_vanilla = [maple_syrup, fiddlehead_fern, truffle, poppy, maki_roll, fried_egg] # More recipes? chef_items_thematic = [maki_roll, fried_egg, omelet, pizza, hashbrowns, pancakes, bread, tortilla, - farmer_s_lunch, survival_burger, dish_o_the_sea, miner_s_treat, roots_platter, salad, - cheese_cauliflower, parsnip_soup, fried_mushroom, salmon_dinner, pepper_poppers, spaghetti, - sashimi, blueberry_tart, algae_soup, pale_broth, chowder] + farmer_s_lunch, survival_burger, dish_o_the_sea, miner_s_treat, roots_platter, salad, + cheese_cauliflower, parsnip_soup, fried_mushroom, salmon_dinner, pepper_poppers, spaghetti, + sashimi, blueberry_tart, algae_soup, pale_broth, chowder] +chef_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.chef, chef_items_vanilla, 6, 6) +chef_bundle_thematic = BundleTemplate.extend_from(chef_bundle_vanilla, chef_items_thematic) dye_items_vanilla = [red_mushroom, sea_urchin, sunflower, duck_feather, aquamarine, red_cabbage] dye_red_items = [cranberries, hot_pepper, radish, rhubarb, spaghetti, strawberry, tomato, tulip] @@ -423,106 +546,79 @@ dye_blue_items = [blueberry, blue_jazz, blackberry, crystal_fruit] dye_purple_items = [beet, crocus, eggplant, red_cabbage, sweet_pea] dye_items_thematic = [dye_red_items, dye_orange_items, dye_yellow_items, dye_green_items, dye_blue_items, dye_purple_items] +dye_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.dye, dye_items_vanilla, 6, 6) +dye_bundle_thematic = DeepBundleTemplate(CCRoom.bulletin_board, BundleName.dye, dye_items_thematic, 6, 6) field_research_items_vanilla = [purple_mushroom, nautilus_shell, chub, frozen_geode] field_research_items_thematic = [*field_research_items_vanilla, geode, magma_geode, omni_geode, - rainbow_shell, amethyst, bream, carp] + rainbow_shell, amethyst, bream, carp] +field_research_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.field_research, field_research_items_vanilla, 4, 4) +field_research_bundle_thematic = BundleTemplate.extend_from(field_research_bundle_vanilla, field_research_items_thematic) fodder_items_vanilla = [wheat.as_amount(10), hay.as_amount(10), apple.as_amount(3)] fodder_items_thematic = [*fodder_items_vanilla, kale.as_amount(3), corn.as_amount(3), green_bean.as_amount(3), potato.as_amount(3), green_algae.as_amount(5), white_algae.as_amount(3)] +fodder_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.fodder, fodder_items_vanilla, 3, 3) +fodder_bundle_thematic = BundleTemplate.extend_from(fodder_bundle_vanilla, fodder_items_thematic) enchanter_items_vanilla = [oak_resin, wine, rabbit_foot, pomegranate] enchanter_items_thematic = [*enchanter_items_vanilla, purple_mushroom, solar_essence, - super_cucumber, void_essence, fire_quartz, frozen_tear, jade] + super_cucumber, void_essence, fire_quartz, frozen_tear, jade] +enchanter_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.enchanter, enchanter_items_vanilla, 4, 4) +enchanter_bundle_thematic = BundleTemplate.extend_from(enchanter_bundle_vanilla, enchanter_items_thematic) children_items = [salmonberry.as_amount(10), cookie, ancient_doll, ice_cream, cranberry_candy, ginger_ale, grape.as_amount(10), pink_cake, snail, fairy_rose, plum_pudding] +children_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.children, children_items, 4, 3) + forager_items = [salmonberry.as_amount(50), blackberry.as_amount(50), wild_plum.as_amount(20), snow_yam.as_amount(20), common_mushroom.as_amount(20), grape.as_amount(20), spring_onion.as_amount(20)] +forager_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.forager, forager_items, 3, 2) + home_cook_items = [egg.as_amount(10), milk.as_amount(10), wheat_flour.as_amount(100), sugar.as_amount(100), vinegar.as_amount(100), chocolate_cake, pancakes, rhubarb_pie] +home_cook_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.home_cook, home_cook_items, 3, 3) + bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, green_tea, cranberry_candy] +bartender_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.bartender, bartender_items, 3, 3) + +bulletin_board_bundles_vanilla = [chef_bundle_vanilla, dye_bundle_vanilla, field_research_bundle_vanilla, fodder_bundle_vanilla, enchanter_bundle_vanilla] +bulletin_board_bundles_thematic = [chef_bundle_thematic, dye_bundle_thematic, field_research_bundle_thematic, fodder_bundle_thematic, enchanter_bundle_thematic] +bulletin_board_bundles_remixed = [*bulletin_board_bundles_thematic, children_bundle, forager_bundle, home_cook_bundle, bartender_bundle] +bulletin_board_vanilla = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_vanilla, 5) +bulletin_board_thematic = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_thematic, 5) +bulletin_board_remixed = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_remixed, 5) + +missing_bundle_items_vanilla = [wine.as_quality(ArtisanQuality.silver), dinosaur_mayo, prismatic_shard, caviar, + ancient_fruit.as_quality_crop(), void_salmon.as_quality(FishQuality.gold)] +missing_bundle_items_thematic = [*missing_bundle_items_vanilla, pale_ale.as_quality(ArtisanQuality.silver), beer.as_quality(ArtisanQuality.silver), mead.as_quality(ArtisanQuality.silver), + cheese.as_quality(ArtisanQuality.silver), goat_cheese.as_quality(ArtisanQuality.silver), void_mayo, cloth, green_tea, truffle_oil, diamond, + sweet_gem_berry.as_quality_crop(), starfruit.as_quality_crop(), + tea_leaves.as_amount(5), lava_eel.as_quality(FishQuality.gold), scorpion_carp.as_quality(FishQuality.gold), blobfish.as_quality(FishQuality.gold)] +missing_bundle_vanilla = BundleTemplate(CCRoom.abandoned_joja_mart, BundleName.missing_bundle, missing_bundle_items_vanilla, 6, 5) +missing_bundle_thematic = BundleTemplate.extend_from(missing_bundle_vanilla, missing_bundle_items_thematic) +# Make thematic with other currencies +vault_2500_item = BundleItem.money_bundle(2500) +vault_5000_item = BundleItem.money_bundle(5000) +vault_10000_item = BundleItem.money_bundle(10000) +vault_25000_item = BundleItem.money_bundle(25000) -missing_bundle_items = [wine.as_silver_quality(), pale_ale.as_silver_quality(), beer.as_silver_quality(), mead.as_silver_quality(), cheese.as_silver_quality(), - goat_cheese.as_silver_quality(), dinosaur_mayo, void_mayo, cloth, green_tea, truffle_oil, caviar, prismatic_shard, diamond, - ancient_fruit.as_gold_quality().as_amount(5), sweet_gem_berry.as_gold_quality().as_amount(5), starfruit.as_gold_quality().as_amount(5), - tea_leaves.as_amount(5), - void_salmon.as_gold_quality(), lava_eel.as_gold_quality(), scorpion_carp.as_gold_quality(), blobfish.as_gold_quality()] +vault_2500_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_2500_item) +vault_5000_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_5000_item) +vault_10000_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_10000_item) +vault_25000_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_25000_item) -# Make thematic with other currencies -vault_2500_items = [BundleItem.money_bundle(2500)] -vault_5000_items = [BundleItem.money_bundle(5000)] -vault_10000_items = [BundleItem.money_bundle(10000)] -vault_25000_items = [BundleItem.money_bundle(25000)] - -crafts_room_bundle_items = [ - *spring_foraging_items, - *summer_foraging_items, - *fall_foraging_items, - *winter_foraging_items, - *exotic_foraging_items, - *construction_items, -] - -pantry_bundle_items = sorted({ - *spring_crop_items, - *summer_crops_items, - *fall_crops_items, - *quality_crops_items, - *animal_product_items, - *artisan_goods_items, -}) - -fish_tank_bundle_items = sorted({ - *river_fish_items, - *lake_fish_items, - *ocean_fish_items, - *night_fish_items, - *crab_pot_items, - *specialty_fish_items, -}) - -boiler_room_bundle_items = sorted({ - *blacksmith_items, - *geologist_items, - *adventurer_items, -}) - -bulletin_board_bundle_items = sorted({ - *chef_items, - *[item for dye_color_items in dye_items for item in dye_color_items], - *field_research_items, - *fodder_items, - *enchanter_items -}) - -vault_bundle_items = [ - *vault_2500_items, - *vault_5000_items, - *vault_10000_items, - *vault_25000_items, -] - -all_bundle_items_except_money = sorted({ - *crafts_room_bundle_items, - *pantry_bundle_items, - *fish_tank_bundle_items, - *boiler_room_bundle_items, - *bulletin_board_bundle_items, - *missing_bundle_items, -}, key=lambda x: x.item.name) - -all_bundle_items = sorted({ - *crafts_room_bundle_items, - *pantry_bundle_items, - *fish_tank_bundle_items, - *boiler_room_bundle_items, - *bulletin_board_bundle_items, - *vault_bundle_items, - *missing_bundle_items, -}, key=lambda x: x.item.name) - -all_bundle_items_by_name = {item.item.name: item for item in all_bundle_items} -all_bundle_items_by_id = {item.item.item_id: item for item in all_bundle_items} +vault_bundles = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] +vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles, 4) +vault_thematic = vault_vanilla +vault_remixed = vault_thematic + + +all_bundle_items_except_money = [] +all_remixed_bundles = [*crafts_room_bundles_remixed, *pantry_bundles_remixed, *fish_tank_bundles_remixed, + *boiler_room_bundles_remixed, *bulletin_board_bundles_remixed, missing_bundle_thematic] +for bundle in all_remixed_bundles: + all_bundle_items_except_money.extend(bundle.items) + +all_bundle_items_by_name = {item.item_name: item for item in all_bundle_items_except_money} diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a4aac2570a71..00b5961d4418 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1,34 +1,34 @@ id,region,name,tags,mod_name -1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE,MANDATORY", -7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,PANTRY_BUNDLE", -13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE,MANDATORY", -19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY", -27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", -30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,MANDATORY,VAULT_BUNDLE", +1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", 32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", 33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", @@ -36,6 +36,41 @@ id,region,name,tags,mod_name 35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", 36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", 37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +68,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +69,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +70,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +71,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +72,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +73,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +80,Vault,"500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +84,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +85,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +87,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +88,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 101,Pierre's General Store,Large Pack,BACKPACK, 102,Pierre's General Store,Deluxe Pack,BACKPACK, 103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", @@ -2385,16 +2420,16 @@ id,region,name,tags,mod_name 6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded 6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded 6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded -6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded 6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded 6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded 6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2432,40 +2467,40 @@ id,region,name,tags,mod_name 7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator 7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator 7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic -7402,Farm,Craft Travel Core,CRAFTSANITY,Magic -7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded -7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded -7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded -7406,Farm,Craft Glass Path,CRAFTSANITY,Archaeology -7407,Farm,Craft Bone Path,CRAFTSANITY,Archaeology -7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology -7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology -7410,Farm,Craft Water Strainer,CRAFTSANITY,Archaeology -7411,Farm,Craft Grinder,CRAFTSANITY,Archaeology -7412,Farm,Craft Ancient Battery Creator,CRAFTSANITY,Archaeology -7413,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology -7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology -7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology -7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology -7417,Farm,Craft Warp Totem: Volcano,CRAFTSANITY,Archaeology -7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic -7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic -7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7454,Issac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology -7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology -7458,Farm,Glass Bazier Recipe,CRAFTSANITY,Archaeology -7459,Farm,Glass Fence Recipe,CRAFTSANITY,Archaeology -7460,Farm,Water Strainer Recipe,CRAFTSANITY,Archaeology -7461,Farm,Grinder Recipe,CRAFTSANITY,Archaeology -7462,Farm,Ancient Battery Creator Recipe,CRAFTSANITY,Archaeology -7463,Farm,Preservation Chamber Recipe,CRAFTSANITY,Archaeology -7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology -7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology -7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology -7467,Farm,Warp Totem: Volcano Recipe,CRAFTSANITY,Archaeology +7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic +7402,Farm,Craft Travel Core,CRAFTSANITY,Magic +7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded +7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded +7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Farm,Craft Glass Path,CRAFTSANITY,Archaeology +7407,Farm,Craft Bone Path,CRAFTSANITY,Archaeology +7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology +7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology +7410,Farm,Craft Water Strainer,CRAFTSANITY,Archaeology +7411,Farm,Craft Grinder,CRAFTSANITY,Archaeology +7412,Farm,Craft Ancient Battery Creator,CRAFTSANITY,Archaeology +7413,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology +7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology +7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology +7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology +7417,Farm,Craft Warp Totem: Volcano,CRAFTSANITY,Archaeology +7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic +7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic +7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Issac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology +7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology +7458,Farm,Glass Bazier Recipe,CRAFTSANITY,Archaeology +7459,Farm,Glass Fence Recipe,CRAFTSANITY,Archaeology +7460,Farm,Water Strainer Recipe,CRAFTSANITY,Archaeology +7461,Farm,Grinder Recipe,CRAFTSANITY,Archaeology +7462,Farm,Ancient Battery Creator Recipe,CRAFTSANITY,Archaeology +7463,Farm,Preservation Chamber Recipe,CRAFTSANITY,Archaeology +7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology +7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology +7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology +7467,Farm,Warp Totem: Volcano Recipe,CRAFTSANITY,Archaeology 7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) @@ -2529,196 +2564,196 @@ id,region,name,tags,mod_name 7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded 7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded 7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded -8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic -8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic -8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded -8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded -8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded -8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded -8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded -8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded -8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded -8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded -8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded -8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded -8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded -8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded -8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded -8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded -8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded -8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded -8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded -8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded -8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded -8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded -8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded -8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded -8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded -8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded -8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded -8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded -8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology -8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology -8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology -8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology -8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology -8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology -8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology -8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology -8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology -8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology -8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology -8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology -8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology -8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology -8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology -8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology -8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology -8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology -8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology -8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology -8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology -8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology -8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology -8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology -8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology -8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology -8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology -8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology -8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology -8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology -8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology -8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology -8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology -8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology -8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology -8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology -8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology -8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology -8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology -8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology -8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology -8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology -8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology -8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology -8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology -8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology -8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology -8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology -8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology -8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology -8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology -8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology -8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology -8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology -8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology -8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology -8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology -8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology -8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology -8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology -8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology -8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology -8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology -8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology -8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology -8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology -8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology -8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology -8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology -8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology -8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology -8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology -8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology -8201,Shipping,Shipsanity: Warp Totem: Volcano,"SHIPSANITY,GINGER_ISLAND",Archaeology -8202,Shipping,Shipsanity: Water Strainer,SHIPSANITY,Archaeology +8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic +8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded +8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded +8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded +8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded +8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded +8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded +8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded +8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded +8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded +8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded +8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded +8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded +8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded +8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded +8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded +8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded +8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded +8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded +8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded +8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded +8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded +8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded +8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded +8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology +8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology +8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology +8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology +8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology +8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology +8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology +8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology +8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology +8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology +8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology +8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology +8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology +8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology +8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology +8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology +8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology +8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology +8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology +8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology +8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology +8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology +8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology +8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology +8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology +8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology +8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology +8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology +8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology +8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology +8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology +8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology +8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology +8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology +8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology +8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology +8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology +8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology +8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology +8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology +8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology +8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology +8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology +8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology +8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology +8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology +8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology +8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology +8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology +8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology +8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology +8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology +8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology +8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology +8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology +8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology +8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology +8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology +8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology +8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology +8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology +8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology +8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology +8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology +8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology +8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology +8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology +8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology +8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology +8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology +8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology +8201,Shipping,Shipsanity: Warp Totem: Volcano,"SHIPSANITY,GINGER_ISLAND",Archaeology +8202,Shipping,Shipsanity: Water Strainer,SHIPSANITY,Archaeology diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index cec0cd289724..2e80d7d2ddcd 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -3,25 +3,24 @@ from dataclasses import dataclass from typing import List, Tuple, Union, Optional -from . import common_data as common -from .game_item import GameItem -from worlds.stardew_valley.strings.monster_names import Monster +from ..strings.monster_names import Monster from ..strings.fish_names import WaterChest from ..strings.forageable_names import Forageable +from ..strings.metal_names import Mineral from ..strings.region_names import Region from ..strings.geode_names import Geode @dataclass(frozen=True) -class MuseumItem(GameItem): +class MuseumItem: + item_name: str locations: Tuple[str, ...] geodes: Tuple[str, ...] monsters: Tuple[str, ...] difficulty: float @staticmethod - def of(name: str, - item_id: int, + def of(item_name: str, difficulty: float, locations: Union[str, Tuple[str, ...]], geodes: Union[str, Tuple[str, ...]], @@ -35,10 +34,10 @@ def of(name: str, if isinstance(monsters, str): monsters = (monsters,) - return MuseumItem(name, item_id, locations, geodes, monsters, difficulty) + return MuseumItem(item_name, locations, geodes, monsters, difficulty) def __repr__(self): - return f"{self.name} [{self.item_id}] (Locations: {self.locations} |" \ + return f"{self.item_name} (Locations: {self.locations} |" \ f" Geodes: {self.geodes} |" \ f" Monsters: {self.monsters}) " @@ -52,19 +51,17 @@ def __repr__(self): def create_artifact(name: str, - item_id: int, difficulty: float, locations: Union[str, Tuple[str, ...]] = (), geodes: Union[str, Tuple[str, ...]] = (), monsters: Union[str, Tuple[str, ...]] = ()) -> MuseumItem: - artifact_item = MuseumItem.of(name, item_id, difficulty, locations, geodes, monsters) + artifact_item = MuseumItem.of(name, difficulty, locations, geodes, monsters) all_museum_artifacts.append(artifact_item) all_museum_items.append(artifact_item) return artifact_item def create_mineral(name: str, - item_id: int, locations: Union[str, Tuple[str, ...]], geodes: Union[str, Tuple[str, ...]] = (), monsters: Union[str, Tuple[str, ...]] = (), @@ -80,210 +77,210 @@ def create_mineral(name: str, if "Omni Geode" in geodes: difficulty += 31.0 / 2750.0 * 100 - mineral_item = MuseumItem.of(name, item_id, difficulty, locations, geodes, monsters) + mineral_item = MuseumItem.of(name, difficulty, locations, geodes, monsters) all_museum_minerals.append(mineral_item) all_museum_items.append(mineral_item) return mineral_item class Artifact: - dwarf_scroll_i = create_artifact("Dwarf Scroll I", 96, 5.6, Region.mines_floor_20, + dwarf_scroll_i = create_artifact("Dwarf Scroll I", 5.6, Region.mines_floor_20, monsters=unlikely) - dwarf_scroll_ii = create_artifact("Dwarf Scroll II", 97, 3, Region.mines_floor_20, + dwarf_scroll_ii = create_artifact("Dwarf Scroll II", 3, Region.mines_floor_20, monsters=unlikely) - dwarf_scroll_iii = create_artifact("Dwarf Scroll III", 98, 7.5, Region.mines_floor_60, + dwarf_scroll_iii = create_artifact("Dwarf Scroll III", 7.5, Region.mines_floor_60, monsters=Monster.blue_slime) - dwarf_scroll_iv = create_artifact("Dwarf Scroll IV", 99, 4, Region.mines_floor_100) - chipped_amphora = create_artifact("Chipped Amphora", 100, 6.7, Region.town, + dwarf_scroll_iv = create_artifact("Dwarf Scroll IV", 4, Region.mines_floor_100) + chipped_amphora = create_artifact("Chipped Amphora", 6.7, Region.town, geodes=Geode.artifact_trove) - arrowhead = create_artifact("Arrowhead", 101, 8.5, (Region.mountain, Region.forest, Region.bus_stop), + arrowhead = create_artifact("Arrowhead", 8.5, (Region.mountain, Region.forest, Region.bus_stop), geodes=Geode.artifact_trove) - ancient_doll = create_artifact("Ancient Doll", 103, 13.1, (Region.mountain, Region.forest, Region.bus_stop), + ancient_doll = create_artifact("Ancient Doll", 13.1, (Region.mountain, Region.forest, Region.bus_stop), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - elvish_jewelry = create_artifact("Elvish Jewelry", 104, 5.3, Region.forest, + elvish_jewelry = create_artifact("Elvish Jewelry", 5.3, Region.forest, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - chewing_stick = create_artifact("Chewing Stick", 105, 10.3, (Region.mountain, Region.forest, Region.town), + chewing_stick = create_artifact("Chewing Stick", 10.3, (Region.mountain, Region.forest, Region.town), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - ornamental_fan = create_artifact("Ornamental Fan", 106, 7.4, (Region.beach, Region.forest, Region.town), + ornamental_fan = create_artifact("Ornamental Fan", 7.4, (Region.beach, Region.forest, Region.town), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - dinosaur_egg = create_artifact("Dinosaur Egg", 107, 11.4, (Region.mountain, Region.skull_cavern), + dinosaur_egg = create_artifact("Dinosaur Egg", 11.4, (Region.mountain, Region.skull_cavern), geodes=WaterChest.fishing_chest, monsters=Monster.pepper_rex) - rare_disc = create_artifact("Rare Disc", 108, 5.6, Region.stardew_valley, + rare_disc = create_artifact("Rare Disc", 5.6, Region.stardew_valley, geodes=(Geode.artifact_trove, WaterChest.fishing_chest), monsters=unlikely) - ancient_sword = create_artifact("Ancient Sword", 109, 5.8, (Region.forest, Region.mountain), + ancient_sword = create_artifact("Ancient Sword", 5.8, (Region.forest, Region.mountain), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - rusty_spoon = create_artifact("Rusty Spoon", 110, 9.6, Region.town, + rusty_spoon = create_artifact("Rusty Spoon", 9.6, Region.town, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - rusty_spur = create_artifact("Rusty Spur", 111, 15.6, Region.farm, + rusty_spur = create_artifact("Rusty Spur", 15.6, Region.farm, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - rusty_cog = create_artifact("Rusty Cog", 112, 9.6, Region.mountain, + rusty_cog = create_artifact("Rusty Cog", 9.6, Region.mountain, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - chicken_statue = create_artifact("Chicken Statue", 113, 13.5, Region.farm, + chicken_statue = create_artifact("Chicken Statue", 13.5, Region.farm, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - ancient_seed = create_artifact("Ancient Seed", 114, 8.4, (Region.forest, Region.mountain), + ancient_seed = create_artifact("Ancient Seed", 8.4, (Region.forest, Region.mountain), geodes=(Geode.artifact_trove, WaterChest.fishing_chest), monsters=unlikely) - prehistoric_tool = create_artifact("Prehistoric Tool", 115, 11.1, (Region.mountain, Region.forest, Region.bus_stop), + prehistoric_tool = create_artifact("Prehistoric Tool", 11.1, (Region.mountain, Region.forest, Region.bus_stop), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - dried_starfish = create_artifact("Dried Starfish", 116, 12.5, Region.beach, + dried_starfish = create_artifact("Dried Starfish", 12.5, Region.beach, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - anchor = create_artifact("Anchor", 117, 8.5, Region.beach, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - glass_shards = create_artifact("Glass Shards", 118, 11.5, Region.beach, + anchor = create_artifact("Anchor", 8.5, Region.beach, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) + glass_shards = create_artifact("Glass Shards", 11.5, Region.beach, geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - bone_flute = create_artifact("Bone Flute", 119, 6.3, (Region.mountain, Region.forest, Region.town), + bone_flute = create_artifact("Bone Flute", 6.3, (Region.mountain, Region.forest, Region.town), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - prehistoric_handaxe = create_artifact("Prehistoric Handaxe", 120, 13.7, + prehistoric_handaxe = create_artifact("Prehistoric Handaxe", 13.7, (Region.mountain, Region.forest, Region.bus_stop), geodes=Geode.artifact_trove) - dwarvish_helm = create_artifact("Dwarvish Helm", 121, 8.7, Region.mines_floor_20, + dwarvish_helm = create_artifact("Dwarvish Helm", 8.7, Region.mines_floor_20, geodes=(Geode.geode, Geode.omni, Geode.artifact_trove)) - dwarf_gadget = create_artifact("Dwarf Gadget", 122, 9.7, Region.mines_floor_60, + dwarf_gadget = create_artifact("Dwarf Gadget", 9.7, Region.mines_floor_60, geodes=(Geode.magma, Geode.omni, Geode.artifact_trove)) - ancient_drum = create_artifact("Ancient Drum", 123, 9.5, (Region.bus_stop, Region.forest, Region.town), + ancient_drum = create_artifact("Ancient Drum", 9.5, (Region.bus_stop, Region.forest, Region.town), geodes=(Geode.frozen, Geode.omni, Geode.artifact_trove)) - golden_mask = create_artifact("Golden Mask", 124, 6.7, Region.desert, + golden_mask = create_artifact("Golden Mask", 6.7, Region.desert, geodes=Geode.artifact_trove) - golden_relic = create_artifact("Golden Relic", 125, 9.7, Region.desert, + golden_relic = create_artifact("Golden Relic", 9.7, Region.desert, geodes=Geode.artifact_trove) - strange_doll_green = create_artifact("Strange Doll (Green)", 126, 10, Region.town, + strange_doll_green = create_artifact("Strange Doll (Green)", 10, Region.town, geodes=Forageable.secret_note) - strange_doll = create_artifact("Strange Doll", 127, 10, Region.desert, + strange_doll = create_artifact("Strange Doll", 10, Region.desert, geodes=Forageable.secret_note) - prehistoric_scapula = create_artifact("Prehistoric Scapula", 579, 6.2, + prehistoric_scapula = create_artifact("Prehistoric Scapula", 6.2, (Region.dig_site, Region.forest, Region.town)) - prehistoric_tibia = create_artifact("Prehistoric Tibia", 580, 16.6, + prehistoric_tibia = create_artifact("Prehistoric Tibia", 16.6, (Region.dig_site, Region.forest, Region.railroad)) - prehistoric_skull = create_artifact("Prehistoric Skull", 581, 3.9, (Region.dig_site, Region.mountain)) - skeletal_hand = create_artifact("Skeletal Hand", 582, 7.9, (Region.dig_site, Region.backwoods, Region.beach)) - prehistoric_rib = create_artifact("Prehistoric Rib", 583, 15, (Region.dig_site, Region.farm, Region.town), + prehistoric_skull = create_artifact("Prehistoric Skull", 3.9, (Region.dig_site, Region.mountain)) + skeletal_hand = create_artifact("Skeletal Hand", 7.9, (Region.dig_site, Region.backwoods, Region.beach)) + prehistoric_rib = create_artifact("Prehistoric Rib", 15, (Region.dig_site, Region.farm, Region.town), monsters=Monster.pepper_rex) - prehistoric_vertebra = create_artifact("Prehistoric Vertebra", 584, 12.7, (Region.dig_site, Region.bus_stop), + prehistoric_vertebra = create_artifact("Prehistoric Vertebra", 12.7, (Region.dig_site, Region.bus_stop), monsters=Monster.pepper_rex) - skeletal_tail = create_artifact("Skeletal Tail", 585, 5.1, (Region.dig_site, Region.mines_floor_20), + skeletal_tail = create_artifact("Skeletal Tail", 5.1, (Region.dig_site, Region.mines_floor_20), geodes=WaterChest.fishing_chest) - nautilus_fossil = create_artifact("Nautilus Fossil", 586, 6.9, (Region.dig_site, Region.beach), + nautilus_fossil = create_artifact("Nautilus Fossil", 6.9, (Region.dig_site, Region.beach), geodes=WaterChest.fishing_chest) - amphibian_fossil = create_artifact("Amphibian Fossil", 587, 6.3, (Region.dig_site, Region.forest, Region.mountain), + amphibian_fossil = create_artifact("Amphibian Fossil", 6.3, (Region.dig_site, Region.forest, Region.mountain), geodes=WaterChest.fishing_chest) - palm_fossil = create_artifact("Palm Fossil", 588, 10.2, + palm_fossil = create_artifact("Palm Fossil", 10.2, (Region.dig_site, Region.desert, Region.forest, Region.beach)) - trilobite = create_artifact("Trilobite", 589, 7.4, (Region.dig_site, Region.desert, Region.forest, Region.beach)) + trilobite = create_artifact("Trilobite", 7.4, (Region.dig_site, Region.desert, Region.forest, Region.beach)) class Mineral: - quartz = create_mineral("Quartz", 80, Region.mines_floor_20) - fire_quartz = create_mineral("Fire Quartz", 82, Region.mines_floor_100, + quartz = create_mineral(Mineral.quartz, Region.mines_floor_20) + fire_quartz = create_mineral("Fire Quartz", Region.mines_floor_100, geodes=(Geode.magma, Geode.omni, WaterChest.fishing_chest), difficulty=1.0 / 12.0) - frozen_tear = create_mineral("Frozen Tear", 84, Region.mines_floor_60, + frozen_tear = create_mineral("Frozen Tear", Region.mines_floor_60, geodes=(Geode.frozen, Geode.omni, WaterChest.fishing_chest), monsters=unlikely, difficulty=1.0 / 12.0) - earth_crystal = create_mineral("Earth Crystal", 86, Region.mines_floor_20, + earth_crystal = create_mineral("Earth Crystal", Region.mines_floor_20, geodes=(Geode.geode, Geode.omni, WaterChest.fishing_chest), monsters=Monster.duggy, difficulty=1.0 / 12.0) - emerald = create_mineral("Emerald", 60, Region.mines_floor_100, + emerald = create_mineral("Emerald", Region.mines_floor_100, geodes=WaterChest.fishing_chest) - aquamarine = create_mineral("Aquamarine", 62, Region.mines_floor_60, + aquamarine = create_mineral("Aquamarine", Region.mines_floor_60, geodes=WaterChest.fishing_chest) - ruby = create_mineral("Ruby", 64, Region.mines_floor_100, + ruby = create_mineral("Ruby", Region.mines_floor_100, geodes=WaterChest.fishing_chest) - amethyst = create_mineral("Amethyst", 66, Region.mines_floor_20, + amethyst = create_mineral("Amethyst", Region.mines_floor_20, geodes=WaterChest.fishing_chest) - topaz = create_mineral("Topaz", 68, Region.mines_floor_20, + topaz = create_mineral("Topaz", Region.mines_floor_20, geodes=WaterChest.fishing_chest) - jade = create_mineral("Jade", 70, Region.mines_floor_60, + jade = create_mineral("Jade", Region.mines_floor_60, geodes=WaterChest.fishing_chest) - diamond = create_mineral("Diamond", 72, Region.mines_floor_60, + diamond = create_mineral("Diamond", Region.mines_floor_60, geodes=WaterChest.fishing_chest) - prismatic_shard = create_mineral("Prismatic Shard", 74, Region.skull_cavern_100, + prismatic_shard = create_mineral("Prismatic Shard", Region.skull_cavern_100, geodes=unlikely, monsters=unlikely) - alamite = create_mineral("Alamite", 538, Region.town, + alamite = create_mineral("Alamite", Region.town, geodes=(Geode.geode, Geode.omni)) - bixite = create_mineral("Bixite", 539, Region.town, + bixite = create_mineral("Bixite", Region.town, geodes=(Geode.magma, Geode.omni), monsters=unlikely) - baryte = create_mineral("Baryte", 540, Region.town, + baryte = create_mineral("Baryte", Region.town, geodes=(Geode.magma, Geode.omni)) - aerinite = create_mineral("Aerinite", 541, Region.town, + aerinite = create_mineral("Aerinite", Region.town, geodes=(Geode.frozen, Geode.omni)) - calcite = create_mineral("Calcite", 542, Region.town, + calcite = create_mineral("Calcite", Region.town, geodes=(Geode.geode, Geode.omni)) - dolomite = create_mineral("Dolomite", 543, Region.town, + dolomite = create_mineral("Dolomite", Region.town, geodes=(Geode.magma, Geode.omni)) - esperite = create_mineral("Esperite", 544, Region.town, + esperite = create_mineral("Esperite", Region.town, geodes=(Geode.frozen, Geode.omni)) - fluorapatite = create_mineral("Fluorapatite", 545, Region.town, + fluorapatite = create_mineral("Fluorapatite", Region.town, geodes=(Geode.frozen, Geode.omni)) - geminite = create_mineral("Geminite", 546, Region.town, + geminite = create_mineral("Geminite", Region.town, geodes=(Geode.frozen, Geode.omni)) - helvite = create_mineral("Helvite", 547, Region.town, + helvite = create_mineral("Helvite", Region.town, geodes=(Geode.magma, Geode.omni)) - jamborite = create_mineral("Jamborite", 548, Region.town, + jamborite = create_mineral("Jamborite", Region.town, geodes=(Geode.geode, Geode.omni)) - jagoite = create_mineral("Jagoite", 549, Region.town, + jagoite = create_mineral("Jagoite", Region.town, geodes=(Geode.geode, Geode.omni)) - kyanite = create_mineral("Kyanite", 550, Region.town, + kyanite = create_mineral("Kyanite", Region.town, geodes=(Geode.frozen, Geode.omni)) - lunarite = create_mineral("Lunarite", 551, Region.town, + lunarite = create_mineral("Lunarite", Region.town, geodes=(Geode.frozen, Geode.omni)) - malachite = create_mineral("Malachite", 552, Region.town, + malachite = create_mineral("Malachite", Region.town, geodes=(Geode.geode, Geode.omni)) - neptunite = create_mineral("Neptunite", 553, Region.town, + neptunite = create_mineral("Neptunite", Region.town, geodes=(Geode.magma, Geode.omni)) - lemon_stone = create_mineral("Lemon Stone", 554, Region.town, + lemon_stone = create_mineral("Lemon Stone", Region.town, geodes=(Geode.magma, Geode.omni)) - nekoite = create_mineral("Nekoite", 555, Region.town, + nekoite = create_mineral("Nekoite", Region.town, geodes=(Geode.geode, Geode.omni)) - orpiment = create_mineral("Orpiment", 556, Region.town, + orpiment = create_mineral("Orpiment", Region.town, geodes=(Geode.geode, Geode.omni)) - petrified_slime = create_mineral("Petrified Slime", 557, Region.town, + petrified_slime = create_mineral("Petrified Slime", Region.town, geodes=(Geode.geode, Geode.omni)) - thunder_egg = create_mineral("Thunder Egg", 558, Region.town, + thunder_egg = create_mineral("Thunder Egg", Region.town, geodes=(Geode.geode, Geode.omni)) - pyrite = create_mineral("Pyrite", 559, Region.town, + pyrite = create_mineral("Pyrite", Region.town, geodes=(Geode.frozen, Geode.omni)) - ocean_stone = create_mineral("Ocean Stone", 560, Region.town, + ocean_stone = create_mineral("Ocean Stone", Region.town, geodes=(Geode.frozen, Geode.omni)) - ghost_crystal = create_mineral("Ghost Crystal", 561, Region.town, + ghost_crystal = create_mineral("Ghost Crystal", Region.town, geodes=(Geode.frozen, Geode.omni)) - tigerseye = create_mineral("Tigerseye", 562, Region.town, + tigerseye = create_mineral("Tigerseye", Region.town, geodes=(Geode.magma, Geode.omni)) - jasper = create_mineral("Jasper", 563, Region.town, + jasper = create_mineral("Jasper", Region.town, geodes=(Geode.magma, Geode.omni)) - opal = create_mineral("Opal", 564, Region.town, + opal = create_mineral("Opal", Region.town, geodes=(Geode.frozen, Geode.omni)) - fire_opal = create_mineral("Fire Opal", 565, Region.town, + fire_opal = create_mineral("Fire Opal", Region.town, geodes=(Geode.magma, Geode.omni)) - celestine = create_mineral("Celestine", 566, Region.town, + celestine = create_mineral("Celestine", Region.town, geodes=(Geode.geode, Geode.omni)) - marble = create_mineral("Marble", 567, Region.town, + marble = create_mineral("Marble", Region.town, geodes=(Geode.frozen, Geode.omni)) - sandstone = create_mineral("Sandstone", 568, Region.town, + sandstone = create_mineral("Sandstone", Region.town, geodes=(Geode.geode, Geode.omni)) - granite = create_mineral("Granite", 569, Region.town, + granite = create_mineral("Granite", Region.town, geodes=(Geode.geode, Geode.omni)) - basalt = create_mineral("Basalt", 570, Region.town, + basalt = create_mineral("Basalt", Region.town, geodes=(Geode.magma, Geode.omni)) - limestone = create_mineral("Limestone", 571, Region.town, + limestone = create_mineral("Limestone", Region.town, geodes=(Geode.geode, Geode.omni)) - soapstone = create_mineral("Soapstone", 572, Region.town, + soapstone = create_mineral("Soapstone", Region.town, geodes=(Geode.frozen, Geode.omni)) - hematite = create_mineral("Hematite", 573, Region.town, + hematite = create_mineral("Hematite", Region.town, geodes=(Geode.frozen, Geode.omni)) - mudstone = create_mineral("Mudstone", 574, Region.town, + mudstone = create_mineral("Mudstone", Region.town, geodes=(Geode.geode, Geode.omni)) - obsidian = create_mineral("Obsidian", 575, Region.town, + obsidian = create_mineral("Obsidian", Region.town, geodes=(Geode.magma, Geode.omni)) - slate = create_mineral("Slate", 576, Region.town, + slate = create_mineral("Slate", Region.town, geodes=(Geode.geode, Geode.omni)) - fairy_stone = create_mineral("Fairy Stone", 577, Region.town, + fairy_stone = create_mineral("Fairy Stone", Region.town, geodes=(Geode.frozen, Geode.omni)) - star_shards = create_mineral("Star Shards", 578, Region.town, + star_shards = create_mineral("Star Shards", Region.town, geodes=(Geode.magma, Geode.omni)) @@ -292,4 +289,4 @@ class Mineral: skeleton_middle = (Artifact.prehistoric_rib, Artifact.prehistoric_vertebra) skeleton_back = (Artifact.prehistoric_tibia, Artifact.skeletal_tail) -all_museum_items_by_name = {item.name: item for item in all_museum_items} +all_museum_items_by_name = {item.item_name: item for item in all_museum_items} diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 5cd63adcc3dc..65d7022e3ace 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -5,6 +5,7 @@ from typing import Optional, Dict, Protocol, List, FrozenSet from . import data +from .bundles.bundle_room import BundleRoom from .options import StardewValleyOptions, Craftsanity, Chefsanity, Cooksanity, Shipsanity, Monstersanity from .data.fish_data import legendary_fish, special_fish, get_fish_for_mods from .data.museum_data import all_museum_items @@ -222,10 +223,10 @@ def extend_museumsanity_locations(randomized_locations: List[LocationData], opti elif options.museumsanity == Museumsanity.option_milestones: randomized_locations.extend(locations_by_tag[LocationTags.MUSEUM_MILESTONES]) elif options.museumsanity == Museumsanity.option_randomized: - randomized_locations.extend(location_table[f"{prefix}{museum_item.name}"] + randomized_locations.extend(location_table[f"{prefix}{museum_item.item_name}"] for museum_item in all_museum_items if random.random() < 0.4) elif options.museumsanity == Museumsanity.option_all: - randomized_locations.extend(location_table[f"{prefix}{museum_item.name}"] for museum_item in all_museum_items) + randomized_locations.extend(location_table[f"{prefix}{museum_item.item_name}"] for museum_item in all_museum_items) def extend_friendsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): @@ -308,12 +309,19 @@ def extend_walnut_purchase_locations(randomized_locations: List[LocationData], o randomized_locations.extend(locations_by_tag[LocationTags.WALNUT_PURCHASE]) -def extend_mandatory_locations(randomized_locations: List[LocationData], options): +def extend_mandatory_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): mandatory_locations = [location for location in locations_by_tag[LocationTags.MANDATORY]] filtered_mandatory_locations = filter_disabled_locations(options, mandatory_locations) randomized_locations.extend(filtered_mandatory_locations) +def extend_bundle_locations(randomized_locations: List[LocationData], bundle_rooms: List[BundleRoom]): + for room in bundle_rooms: + randomized_locations.append(location_table[f"Complete {room.name}"]) + for bundle in room.bundles: + randomized_locations.append(location_table[bundle.name]) + + def extend_backpack_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): if options.backpack_progression == BackpackProgression.option_vanilla: return @@ -413,11 +421,13 @@ def extend_craftsanity_locations(randomized_locations: List[LocationData], optio def create_locations(location_collector: StardewLocationCollector, + bundle_rooms: List[BundleRoom], options: StardewValleyOptions, random: Random): randomized_locations = [] extend_mandatory_locations(randomized_locations, options) + extend_bundle_locations(randomized_locations, bundle_rooms) extend_backpack_locations(randomized_locations, options) if options.tool_progression & ToolProgression.option_progressive: diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 96dd5a2afb2d..544d9d5273c3 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -1,14 +1,18 @@ from functools import cached_property -from typing import Tuple, Union +from typing import Union, List from .base_logic import BaseLogicMixin, BaseLogic from .farming_logic import FarmingLogicMixin +from .fishing_logic import FishingLogicMixin from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin from .region_logic import RegionLogicMixin -from ..data.bundle_data import BundleItem -from ..stardew_rule import StardewRule -from ..strings.quality_names import Quality +from .skill_logic import SkillLogicMixin +from ..bundles.bundle import Bundle +from ..stardew_rule import StardewRule, And, True_ +from ..strings.currency_names import Currency +from ..strings.machine_names import Machine +from ..strings.quality_names import CropQuality, ForageQuality, FishQuality, ArtisanQuality from ..strings.region_names import Region @@ -18,19 +22,39 @@ def __init__(self, *args, **kwargs): self.bundle = BundleLogic(*args, **kwargs) -class BundleLogic(BaseLogic[Union[HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, FarmingLogicMixin]]): +class BundleLogic(BaseLogic[Union[HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, FarmingLogicMixin, FishingLogicMixin, SkillLogicMixin]]): # Should be cached - def can_complete_bundle(self, bundle_requirements: Tuple[BundleItem], number_required: int) -> StardewRule: + def can_complete_bundle(self, bundle: Bundle) -> StardewRule: item_rules = [] - highest_quality_yet = Quality.basic + qualities = [] can_speak_junimo = self.logic.region.can_reach(Region.wizard_tower) - for bundle_item in bundle_requirements: - if bundle_item.item.item_id == -1: + for bundle_item in bundle.items: + if bundle_item.item_name == Currency.money: return can_speak_junimo & self.logic.money.can_spend(bundle_item.amount) - else: - item_rules.append(bundle_item.item.name) - highest_quality_yet = Quality.get_highest(highest_quality_yet, bundle_item.quality) - return can_speak_junimo & self.logic.has(tuple(item_rules), number_required) & self.logic.farming.can_grow_crop_quality(highest_quality_yet) + + item_rules.append(bundle_item.item_name) + qualities.append(bundle_item.quality) + quality_rules = self.get_quality_rules(qualities) + item_rules = self.logic.has(tuple(item_rules), bundle.number_required) + return can_speak_junimo & item_rules & quality_rules + + def get_quality_rules(self, qualities: List[str]) -> StardewRule: + crop_quality = CropQuality.get_highest(qualities) + fish_quality = FishQuality.get_highest(qualities) + forage_quality = ForageQuality.get_highest(qualities) + artisan_quality = ArtisanQuality.get_highest(qualities) + quality_rules = [] + if crop_quality != CropQuality.basic: + quality_rules.append(self.logic.farming.can_grow_crop_quality(crop_quality)) + if fish_quality != FishQuality.basic: + quality_rules.append(self.logic.fishing.can_catch_quality_fish(fish_quality)) + if forage_quality != ForageQuality.basic: + quality_rules.append(self.logic.skill.can_forage_quality(forage_quality)) + if artisan_quality != ArtisanQuality.basic: + quality_rules.append(self.logic.has(Machine.cask)) + if not quality_rules: + return True_() + return And(*quality_rules) @cached_property def can_complete_community_center(self) -> StardewRule: diff --git a/worlds/stardew_valley/logic/crop_logic.py b/worlds/stardew_valley/logic/crop_logic.py index 52d9d1b1d4cb..afcb6aa35449 100644 --- a/worlds/stardew_valley/logic/crop_logic.py +++ b/worlds/stardew_valley/logic/crop_logic.py @@ -26,7 +26,7 @@ def __init__(self, *args, **kwargs): class CropLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, SeasonLogicMixin, MoneyLogicMixin, -ToolLogicMixin, CropLogicMixin]]): + ToolLogicMixin, CropLogicMixin]]): @cache_self1 def can_grow(self, crop: CropItem) -> StardewRule: season_rule = self.logic.season.has_any(crop.farm_growth_seasons) diff --git a/worlds/stardew_valley/logic/farming_logic.py b/worlds/stardew_valley/logic/farming_logic.py index 6a09b3ee1091..b255aa27f785 100644 --- a/worlds/stardew_valley/logic/farming_logic.py +++ b/worlds/stardew_valley/logic/farming_logic.py @@ -3,8 +3,9 @@ from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin from .skill_logic import SkillLogicMixin -from ..stardew_rule import StardewRule, True_ +from ..stardew_rule import StardewRule, True_, False_ from ..strings.fertilizer_names import Fertilizer +from ..strings.quality_names import CropQuality class FarmingLogicMixin(BaseLogicMixin): @@ -24,16 +25,17 @@ def has_fertilizer(self, tier: int) -> StardewRule: if tier >= 3: return self.logic.has(Fertilizer.deluxe) - def can_grow_crop_quality(self, quality: int) -> StardewRule: - if quality <= 0: + def can_grow_crop_quality(self, quality: str) -> StardewRule: + if quality == CropQuality.basic: return True_() - if quality == 1: + if quality == CropQuality.silver: return self.logic.skill.has_farming_level(5) | (self.logic.farming.has_fertilizer(1) & self.logic.skill.has_farming_level(2)) | ( self.logic.farming.has_fertilizer(2) & self.logic.skill.has_farming_level(1)) | self.logic.farming.has_fertilizer(3) - if quality == 2: + if quality == CropQuality.gold: return self.logic.skill.has_farming_level(10) | ( self.logic.farming.has_fertilizer(1) & self.logic.skill.has_farming_level(5)) | ( self.logic.farming.has_fertilizer(2) & self.logic.skill.has_farming_level(3)) | ( self.logic.farming.has_fertilizer(3) & self.logic.skill.has_farming_level(2)) - if quality >= 3: + if quality == CropQuality.iridium: return self.logic.farming.has_fertilizer(3) & self.logic.skill.has_farming_level(4) + return False_() diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 2fe53510b96e..d8ab54a1b80c 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -13,6 +13,7 @@ from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, False_, And from ..strings.fish_names import SVEFish +from ..strings.quality_names import FishQuality from ..strings.region_names import Region from ..strings.skill_names import Skill @@ -61,3 +62,15 @@ def can_start_extended_family_quest(self) -> StardewRule: if self.options.special_order_locations != SpecialOrderLocations.option_board_qi: return False_() return self.logic.region.can_reach(Region.qi_walnut_room) & And(*(self.logic.fishing.can_catch_fish(fish) for fish in legendary_fish)) + + def can_catch_quality_fish(self, fish_quality: str) -> StardewRule: + if fish_quality == FishQuality.basic: + return True_() + rod_rule = self.logic.tool.has_fishing_rod(2) + if fish_quality == FishQuality.silver: + return rod_rule + if fish_quality == FishQuality.gold: + return rod_rule & self.logic.skill.has_level(Skill.fishing, 4) + if fish_quality == FishQuality.iridium: + return rod_rule & self.logic.skill.has_level(Skill.fishing, 10) + return False_() diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 76ed7686b1e7..680329fe1089 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -2,7 +2,7 @@ from dataclasses import dataclass -from worlds.stardew_valley.strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting +from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from .ability_logic import AbilityLogicMixin from .action_logic import ActionLogicMixin from .arcade_logic import ArcadeLogicMixin @@ -35,7 +35,7 @@ from .tool_logic import ToolLogicMixin from .traveling_merchant_logic import TravelingMerchantLogicMixin from .wallet_logic import WalletLogicMixin -from ..data import all_fish, all_purchasable_seeds, all_crops +from ..data import all_purchasable_seeds, all_crops from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name from ..data.fish_data import island_fish, extended_family, get_fish_for_mods @@ -100,7 +100,7 @@ def __init__(self, player: int, options: StardewValleyOptions): super().__init__(player, self.registry, options, self) self.registry.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value)}) - self.registry.museum_rules.update({donation.name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) + self.registry.museum_rules.update({donation.item_name: self.museum.can_find_museum_item(donation) for donation in all_museum_items}) for recipe in all_cooking_recipes: if recipe.mod_name and recipe.mod_name not in self.options.mods: @@ -357,7 +357,7 @@ def __init__(self, player: int, options: StardewValleyOptions): MetalBar.gold: self.can_smelt(Ore.gold), MetalBar.iridium: self.can_smelt(Ore.iridium), MetalBar.iron: self.can_smelt(Ore.iron), - MetalBar.quartz: self.can_smelt("Quartz") | self.can_smelt("Fire Quartz") | (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), + MetalBar.quartz: self.can_smelt(Mineral.quartz) | self.can_smelt("Fire Quartz") | (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))), MetalBar.radioactive: self.can_smelt(Ore.radioactive), Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 1d58c632b942..6d8c2836a324 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -33,7 +33,7 @@ def can_find_museum_item(self, item: MuseumItem) -> StardewRule: # monster_rule = self.can_farm_monster(item.monsters) # extra_rule = True_() pan_rule = False_() - if item.name == "Earth Crystal" or item.name == "Fire Quartz" or item.name == "Frozen Tear": + if item.item_name == "Earth Crystal" or item.item_name == "Fire Quartz" or item.item_name == "Frozen Tear": pan_rule = self.logic.action.can_pan() return pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 951f06bbed80..b123077ca2ac 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -2,7 +2,7 @@ from typing import Union, Tuple from Utils import cache_self1 -from worlds.stardew_valley.strings.craftable_names import Fishing +from ..strings.craftable_names import Fishing from .base_logic import BaseLogicMixin, BaseLogic from .combat_logic import CombatLogicMixin from .crop_logic import CropLogicMixin @@ -19,6 +19,7 @@ from ..stardew_rule import StardewRule, True_, Or from ..strings.machine_names import Machine from ..strings.performance_names import Performance +from ..strings.quality_names import ForageQuality from ..strings.region_names import Region from ..strings.skill_names import Skill from ..strings.tool_names import ToolMaterial, Tool @@ -158,3 +159,12 @@ def can_crab_pot(self) -> StardewRule: water_region_rules = self.logic.region.can_reach_any(fishing_regions) return crab_pot_rule & water_region_rules + + def can_forage_quality(self, quality: str) -> StardewRule: + if quality == ForageQuality.basic: + return True_() + if quality == ForageQuality.silver: + return self.has_level(Skill.foraging, 5) + if quality == ForageQuality.gold: + return self.has_level(Skill.foraging, 9) + return False_() diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index d62f8b0bdb6c..6ffc4c53d67f 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -105,7 +105,8 @@ class BundleRandomization(Choice): default = 1 option_vanilla = 0 option_thematic = 1 - option_shuffled = 2 + option_remixed = 2 + option_shuffled = 3 class BundlePrice(Choice): @@ -116,11 +117,11 @@ class BundlePrice(Choice): Expensive: Every bundle will require 1 extra item when applicable""" internal_name = "bundle_price" display_name = "Bundle Price" - default = 2 - option_very_cheap = 0 - option_cheap = 1 - option_normal = 2 - option_expensive = 3 + default = 0 + option_very_cheap = -2 + option_cheap = -1 + option_normal = 0 + option_expensive = 1 class EntranceRandomization(Choice): diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index e04f5b6b2ad5..9cb49ccb3fea 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -4,6 +4,7 @@ from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules from . import locations +from .bundles.bundle_room import BundleRoom from .data.craftable_data import all_crafting_recipes_by_name from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals, \ @@ -44,7 +45,7 @@ def set_rules(world): world_options = world.options player = world.player logic = world.logic - current_bundles = world.modified_bundles + bundle_rooms: List[BundleRoom] = world.modified_bundles all_location_names = list(location.name for location in multiworld.get_locations(player)) @@ -53,7 +54,7 @@ def set_rules(world): set_tool_rules(logic, multiworld, player, world_options) set_skills_rules(logic, multiworld, player, world_options) - set_bundle_rules(current_bundles, logic, multiworld, player) + set_bundle_rules(bundle_rooms, logic, multiworld, player) set_building_rules(logic, multiworld, player, world_options) set_cropsanity_rules(all_location_names, logic, multiworld, player, world_options) set_story_quests_rules(all_location_names, logic, multiworld, player, world_options) @@ -117,31 +118,16 @@ def set_building_rules(logic: StardewLogic, multiworld, player, world_options: S logic.registry.building_rules[building.name.replace(" Blueprint", "")]) -def set_bundle_rules(current_bundles, logic: StardewLogic, multiworld, player): - for bundle in current_bundles.values(): - location = multiworld.get_location(bundle.get_name_with_bundle(), player) - rules = logic.bundle.can_complete_bundle(tuple(bundle.requirements), bundle.number_required) - simplified_rules = rules - MultiWorldRules.set_rule(location, simplified_rules) - MultiWorldRules.add_rule(multiworld.get_location("Complete Crafts Room", player), - And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.CRAFTS_ROOM_BUNDLE]))) - MultiWorldRules.add_rule(multiworld.get_location("Complete Pantry", player), - And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.PANTRY_BUNDLE]))) - MultiWorldRules.add_rule(multiworld.get_location("Complete Fish Tank", player), - And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.FISH_TANK_BUNDLE]))) - MultiWorldRules.add_rule(multiworld.get_location("Complete Boiler Room", player), - And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.BOILER_ROOM_BUNDLE]))) - MultiWorldRules.add_rule(multiworld.get_location("Complete Bulletin Board", player), - And(*(logic.region.can_reach_location(bundle.name) - for bundle - in locations.locations_by_tag[LocationTags.BULLETIN_BOARD_BUNDLE]))) - MultiWorldRules.add_rule(multiworld.get_location("Complete Vault", player), - And(*(logic.region.can_reach_location(bundle.name) - for bundle in locations.locations_by_tag[LocationTags.VAULT_BUNDLE]))) +def set_bundle_rules(bundle_rooms: List[BundleRoom], logic: StardewLogic, multiworld, player): + for bundle_room in bundle_rooms: + room_rules = [] + for bundle in bundle_room.bundles: + location = multiworld.get_location(bundle.name, player) + bundle_rules = logic.bundle.can_complete_bundle(bundle).simplify() + room_rules.append(bundle_rules) + MultiWorldRules.set_rule(location, bundle_rules) + room_location = f"Complete {bundle_room.name}" + MultiWorldRules.add_rule(multiworld.get_location(room_location, player), And(*room_rules)) def set_skills_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 0b1e6d3dfbac..f6e2ebaf680c 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -5,6 +5,7 @@ class CCRoom: bulletin_board = "Bulletin Board" vault = "Vault" boiler_room = "Boiler Room" + abandoned_joja_mart = "Abandoned Joja Mart" class BundleName: @@ -12,3 +13,49 @@ class BundleName: summer_foraging = "Summer Foraging Bundle" fall_foraging = "Fall Foraging Bundle" winter_foraging = "Winter Foraging Bundle" + construction = "Construction Bundle" + exotic_foraging = "Exotic Foraging Bundle" + beach_foraging = "Beach Foraging Bundle" + mines_foraging = "Mines Foraging Bundle" + desert_foraging = "Desert Foraging Bundle" + island_foraging = "Island Foraging Bundle" + sticky = "Sticky Bundle" + wild_medicine = "Wild Medicine Bundle" + quality_foraging = "Quality Foraging Bundle" + spring_crops = "Spring Crops Bundle" + summer_crops = "Summer Crops Bundle" + fall_crops = "Fall Crops Bundle" + quality_crops = "Quality Crops Bundle" + animal = "Animal Bundle" + artisan = "Artisan Bundle" + rare_crops = "Rare Crops Bundle" + fish_farmer = "Fish Farmer's Bundle" + garden = "Garden Bundle" + brewer = "Brewer's Bundle" + orchard = "Orchard Bundle" + island_crops = "Island Crops Bundle" + river_fish = "River Fish Bundle" + lake_fish = "Lake Fish Bundle" + ocean_fish = "Ocean Fish Bundle" + night_fish = "Night Fishing Bundle" + crab_pot = "Crab Pot Bundle" + specialty_fish = "Specialty Fish Bundle" + quality_fish = "Quality Fish Bundle" + master_fisher = "Master Fisher's Bundle" + legendary_fish = "Legendary Fish Bundle" + island_fish = "Island Bundle" + blacksmith = "Blacksmith's Bundle" + geologist = "Geologist's Bundle" + adventurer = "Adventurer's Bundle" + treasure_hunter = "Treasure Hunter's Bundle" + engineer = "Engineer's Bundle" + chef = "Chef's Bundle" + dye = "Dye Bundle" + field_research = "Field Research Bundle" + fodder = "Fodder Bundle" + enchanter = "Enchanter's Bundle" + children = "Children's Bundle" + forager = "Forager's Bundle" + home_cook = "Home Cook's Bundle" + bartender = "Bartender's Bundle" + missing_bundle = "The Missing Bundle" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 60f3008cfc74..2cd519aa3f4c 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -30,6 +30,7 @@ class MetalBar: class Mineral: + quartz = "Quartz" earth_crystal = "Earth Crystal" fire_quartz = "Fire Quartz" marble = "Marble" diff --git a/worlds/stardew_valley/strings/quality_names.py b/worlds/stardew_valley/strings/quality_names.py index c55854af5870..740bb5a3efc2 100644 --- a/worlds/stardew_valley/strings/quality_names.py +++ b/worlds/stardew_valley/strings/quality_names.py @@ -1,15 +1,63 @@ -class Quality: - basic = "Basic" - silver = "Silver" - gold = "Gold" - iridium = "Iridium" +from typing import List + + +class CropQuality: + basic = "Basic Crop" + silver = "Silver Crop" + gold = "Gold Crop" + iridium = "Iridium Crop" + + @staticmethod + def get_highest(qualities: List[str]) -> str: + for quality in crop_qualities_in_desc_order: + if quality in qualities: + return quality + return CropQuality.basic + + +class FishQuality: + basic = "Basic Fish" + silver = "Silver Fish" + gold = "Gold Fish" + iridium = "Iridium Fish" + + @staticmethod + def get_highest(qualities: List[str]) -> str: + for quality in fish_qualities_in_desc_order: + if quality in qualities: + return quality + return FishQuality.basic + + +class ForageQuality: + basic = "Basic Forage" + silver = "Silver Forage" + gold = "Gold Forage" + iridium = "Iridium Forage" + + @staticmethod + def get_highest(qualities: List[str]) -> str: + for quality in forage_qualities_in_desc_order: + if quality in qualities: + return quality + return ForageQuality.basic + + +class ArtisanQuality: + basic = "Basic Artisan" + silver = "Silver Artisan" + gold = "Gold Artisan" + iridium = "Iridium Artisan" @staticmethod - def get_highest(quality1: str, quality2: str) -> str: - for quality in qualities_in_desc_order: - if quality1 == quality or quality2 == quality: + def get_highest(qualities: List[str]) -> str: + for quality in artisan_qualities_in_desc_order: + if quality in qualities: return quality - return Quality.basic + return ArtisanQuality.basic -qualities_in_desc_order = [Quality.iridium, Quality.gold, Quality.silver, Quality.basic] +crop_qualities_in_desc_order = [CropQuality.iridium, CropQuality.gold, CropQuality.silver, CropQuality.basic] +fish_qualities_in_desc_order = [FishQuality.iridium, FishQuality.gold, FishQuality.silver, FishQuality.basic] +forage_qualities_in_desc_order = [ForageQuality.iridium, ForageQuality.gold, ForageQuality.silver, ForageQuality.basic] +artisan_qualities_in_desc_order = [ArtisanQuality.iridium, ArtisanQuality.gold, ArtisanQuality.silver, ArtisanQuality.basic] diff --git a/worlds/stardew_valley/test/TestBundles.py b/worlds/stardew_valley/test/TestBundles.py index c7ea6faa83f5..cd6828cd79e5 100644 --- a/worlds/stardew_valley/test/TestBundles.py +++ b/worlds/stardew_valley/test/TestBundles.py @@ -1,31 +1,29 @@ import unittest -from ..data.bundle_data import all_bundle_items, quality_crops_items +from ..data.bundle_data import all_bundle_items_except_money, quality_crops_items_thematic from ..strings.crop_names import Fruit +from ..strings.quality_names import CropQuality class TestBundles(unittest.TestCase): def test_all_bundle_items_have_3_parts(self): - for bundle_item in all_bundle_items: - with self.subTest(bundle_item.item.name): - self.assertGreater(len(bundle_item.item.name), 0) - id = bundle_item.item.item_id - self.assertGreaterEqual(id, -1) - self.assertNotEqual(id, 0) + for bundle_item in all_bundle_items_except_money: + with self.subTest(bundle_item.item_name): + self.assertGreater(len(bundle_item.item_name), 0) self.assertGreater(bundle_item.amount, 0) - self.assertGreaterEqual(bundle_item.quality, 0) + self.assertTrue(bundle_item.quality) def test_quality_crops_have_correct_amounts(self): - for bundle_item in quality_crops_items: - with self.subTest(bundle_item.item.name): - name = bundle_item.item.name + for bundle_item in quality_crops_items_thematic: + with self.subTest(bundle_item.item_name): + name = bundle_item.item_name if name == Fruit.sweet_gem_berry or name == Fruit.ancient_fruit: self.assertEqual(bundle_item.amount, 1) else: self.assertEqual(bundle_item.amount, 5) def test_quality_crops_have_correct_quality(self): - for bundle_item in quality_crops_items: - with self.subTest(bundle_item.item.name): - self.assertEqual(bundle_item.quality, 2) + for bundle_item in quality_crops_items_thematic: + with self.subTest(bundle_item.item_name): + self.assertEqual(bundle_item.quality, CropQuality.gold) diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index 2384bf2bc7dd..b41f3e77a58c 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -20,8 +20,8 @@ def collect_all(mw): class TestLogic(unittest.TestCase): def test_given_bundle_item_then_is_available_in_logic(self): for bundle_item in all_bundle_items_except_money: - with self.subTest(msg=bundle_item.item.name): - self.assertIn(bundle_item.item.name, logic.registry.item_rules) + with self.subTest(msg=bundle_item.item_name): + self.assertIn(bundle_item.item_name, logic.registry.item_rules) def test_given_item_rule_then_can_be_resolved(self): for item in logic.registry.item_rules.keys(): diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 28cbfcf9f032..2996f5b7511c 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -163,13 +163,14 @@ def test_given_special_range_when_generate_exclude_ginger_island(self): check_no_ginger_island(self, multiworld) def test_given_choice_when_generate_exclude_ginger_island(self): - seed = int(random() * pow(10, 18) - 1) options = StardewValleyWorld.options_dataclass.type_hints for option_name, option in options.items(): if not option.options or option_name == ExcludeGingerIsland.internal_name: continue for value in option.options: + seed = int(random() * pow(10, 18) - 1) with self.subTest(f"{option_name}: {value} [Seed: {seed}]"): + # print(seed) multiworld = setup_solo_multiworld( {ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true, option_name: option.options[value]}, seed) From 704f2ed6119e670c77f5795ec70f1927ac7c70eb Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 23 Nov 2023 01:23:54 -0500 Subject: [PATCH 205/482] - Fixed slot data - Added seasonal fish bundles --- worlds/stardew_valley/__init__.py | 11 +++++++++- worlds/stardew_valley/data/bundle_data.py | 21 ++++++++++++++++++- worlds/stardew_valley/data/locations.csv | 5 +++++ worlds/stardew_valley/options.py | 3 ++- worlds/stardew_valley/strings/bundle_names.py | 5 +++++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 658bc396f898..996a024aff4b 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -323,6 +323,15 @@ def get_filler_item_rules(self): return self.options.trap_items != TrapItems.option_no_traps, self.options.exclude_ginger_island == ExcludeGingerIsland.option_true def fill_slot_data(self) -> Dict[str, Any]: + + bundles = dict() + for room in self.modified_bundles: + bundles[room.name] = dict() + for bundle in room.bundles: + bundles[room.name][bundle.name] = {"number_required": bundle.number_required} + for item in bundle.items: + bundles[room.name][bundle.name][item.item_name] = f"{item.amount} of {item.quality}" + excluded_options = [BundleRandomization, BundlePrice, NumberOfMovementBuffs, NumberOfLuckBuffs] excluded_option_names = [option.internal_name for option in excluded_options] generic_option_names = [option_name for option_name in PerGameCommonOptions.type_hints] @@ -332,7 +341,7 @@ def fill_slot_data(self) -> Dict[str, Any]: slot_data.update({ "seed": self.multiworld.per_slot_randoms[self.player].randrange(1000000000), # Seed should be max 9 digits "randomized_entrances": self.randomized_entrances, - "modified_bundles": self.modified_bundles, + "modified_bundles": bundles, "client_version": "5.0.0", }) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index d15e4ec3152b..0a3c7e5b7ca3 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -476,6 +476,24 @@ specialty_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.specialty_fish, specialty_fish_items_vanilla, 4, 4) specialty_fish_bundle_thematic = BundleTemplate.extend_from(specialty_fish_bundle_vanilla, specialty_fish_items_thematic) +spring_fish_items = [herring, halibut, shad, flounder, sunfish, sardine, catfish, anchovy, smallmouth_bass, eel, legend] +spring_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.spring_fish, spring_fish_items, 4, 4) + +summer_fish_items = [tuna, pike, red_mullet, sturgeon, red_snapper, super_cucumber, tilapia, pufferfish, rainbow_trout, + octopus, dorado, halibut, shad, flounder, sunfish, crimsonfish] +summer_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.summer_fish, summer_fish_items, 4, 4) + +fall_fish_items = [red_snapper, super_cucumber, tilapia, shad, sardine, catfish, anchovy, smallmouth_bass, eel, midnight_carp, + walleye, sea_cucumber, tiger_trout, albacore, salmon, angler] +fall_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.fall_fish, fall_fish_items, 4, 4) + +winter_fish_items = [perch, squid, lingcod, tuna, pike, red_mullet, sturgeon, red_snapper, herring, halibut, sardine, + midnight_carp, sea_cucumber, tiger_trout, albacore, glacierfish] +winter_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.winter_fish, winter_fish_items, 4, 4) + +rain_fish_items = [red_snapper, shad, catfish, eel, walleye] +rain_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.rain_fish, rain_fish_items, 3, 3) + quality_fish_items = list({item.as_quality(FishQuality.gold) for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]}) quality_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.quality_fish, quality_fish_items, 4, 4) @@ -492,7 +510,8 @@ night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla] fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic, night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic] -fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle] +fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, + winter_fish_bundle, rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle] fish_tank_vanilla = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_vanilla, 6) fish_tank_thematic = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_thematic, 6) fish_tank_remixed = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_remixed, 6) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 00b5961d4418..528a29a2b56d 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -49,6 +49,11 @@ id,region,name,tags,mod_name 53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 6ffc4c53d67f..7aafed1c7a7b 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -99,10 +99,11 @@ class BundleRandomization(Choice): """What items are needed for the community center bundles? Vanilla: Standard bundles from the vanilla game Thematic: Every bundle will require random items compatible with their original theme + Remixed: Picks bundles at random from thematic, vanilla remixed and new custom ones Shuffled: Every bundle will require random items and follow no particular structure""" internal_name = "bundle_randomization" display_name = "Bundle Randomization" - default = 1 + default = 2 option_vanilla = 0 option_thematic = 1 option_remixed = 2 diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index f6e2ebaf680c..242ed987426f 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -40,6 +40,11 @@ class BundleName: night_fish = "Night Fishing Bundle" crab_pot = "Crab Pot Bundle" specialty_fish = "Specialty Fish Bundle" + spring_fish = "Spring Fishing Bundle" + summer_fish = "Summer Fishing Bundle" + fall_fish = "Fall Fishing Bundle" + winter_fish = "Winter Fishing Bundle" + rain_fish = "Rain Fishing Bundle" quality_fish = "Quality Fish Bundle" master_fisher = "Master Fisher's Bundle" legendary_fish = "Legendary Fish Bundle" From e088ec30063e566fa910aee7b3e41baac23829fe Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 23 Nov 2023 22:09:43 -0500 Subject: [PATCH 206/482] - Added more currency bundles --- worlds/stardew_valley/bundles/bundle.py | 29 ++++++++++-- worlds/stardew_valley/data/bundle_data.py | 45 ++++++++++++------- worlds/stardew_valley/data/items.csv | 4 +- worlds/stardew_valley/data/locations.csv | 4 ++ worlds/stardew_valley/items.py | 20 ++++++--- worlds/stardew_valley/logic/ability_logic.py | 4 -- worlds/stardew_valley/logic/buff_logic.py | 23 ++++++++++ worlds/stardew_valley/logic/bundle_logic.py | 4 +- worlds/stardew_valley/logic/logic.py | 8 ++-- worlds/stardew_valley/logic/money_logic.py | 33 +++++++++++--- .../logic/special_order_logic.py | 10 +++-- worlds/stardew_valley/strings/bundle_names.py | 4 ++ .../stardew_valley/strings/currency_names.py | 5 +++ worlds/stardew_valley/test/TestOptions.py | 2 +- worlds/stardew_valley/test/TestRules.py | 3 +- worlds/stardew_valley/test/__init__.py | 4 +- 16 files changed, 152 insertions(+), 50 deletions(-) create mode 100644 worlds/stardew_valley/logic/buff_logic.py diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index dd4f0ffc096f..583c0c92c659 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -64,14 +64,32 @@ def requires_island(self) -> bool: class CurrencyBundleTemplate(BundleTemplate): item: BundleItem - def __init__(self, room: str, item: BundleItem): - super().__init__(room, "", [item], 1, 1) + def __init__(self, room: str, name: str, item: BundleItem): + super().__init__(room, name, [item], 1, 1) self.item = item def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: + currency_amount = self.get_currency_amount(price_difference) + return Bundle(self.room, self.name, [BundleItem(self.item.item_name, currency_amount)], 1) + + def get_currency_amount(self, price_difference): price_multiplier = round(1 + (price_difference * 0.4), 2) currency_amount = int(self.item.amount * price_multiplier) - currency_name = "g" if self.item.item_name == Currency.money else f" {self.item.item_name}" + return currency_amount + + @property + def requires_island(self) -> bool: + return self.item.item_name == Currency.qi_gem or self.item.item_name == Currency.golden_walnut + + +class MoneyBundleTemplate(CurrencyBundleTemplate): + + def __init__(self, room: str, item: BundleItem): + super().__init__(room, "", item) + + def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: + currency_amount = self.get_currency_amount(price_difference) + currency_name = "g" if currency_amount >= 1000: unit_amount = currency_amount % 1000 unit_amount = "000" if unit_amount == 0 else unit_amount @@ -81,6 +99,11 @@ def create_bundle(self, price_difference: int, random: Random, allow_island_item name = f"{currency_display}{currency_name} Bundle" return Bundle(self.room, name, [BundleItem(self.item.item_name, currency_amount)], 1) + def get_currency_amount(self, price_difference): + price_multiplier = round(1 + (price_difference * 0.4), 2) + currency_amount = int(self.item.amount * price_multiplier) + return currency_amount + class IslandBundleTemplate(BundleTemplate): diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 0a3c7e5b7ca3..b5d1a1ddf34f 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -1,10 +1,11 @@ -from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate +from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate, MoneyBundleTemplate from ..bundles.bundle_item import BundleItem, IslandBundleItem from ..bundles.bundle_room import BundleRoomTemplate from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.bundle_names import CCRoom, BundleName from ..strings.crop_names import Fruit, Vegetable +from ..strings.currency_names import Currency from ..strings.fish_names import Fish, WaterItem, Trash from ..strings.flower_names import Flower from ..strings.food_names import Beverage, Meal @@ -618,20 +619,34 @@ missing_bundle_thematic = BundleTemplate.extend_from(missing_bundle_vanilla, missing_bundle_items_thematic) # Make thematic with other currencies -vault_2500_item = BundleItem.money_bundle(2500) -vault_5000_item = BundleItem.money_bundle(5000) -vault_10000_item = BundleItem.money_bundle(10000) -vault_25000_item = BundleItem.money_bundle(25000) - -vault_2500_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_2500_item) -vault_5000_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_5000_item) -vault_10000_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_10000_item) -vault_25000_bundle = CurrencyBundleTemplate(CCRoom.vault, vault_25000_item) - -vault_bundles = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] -vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles, 4) -vault_thematic = vault_vanilla -vault_remixed = vault_thematic +vault_2500_gold = BundleItem.money_bundle(2500) +vault_5000_gold = BundleItem.money_bundle(5000) +vault_10000_gold = BundleItem.money_bundle(10000) +vault_25000_gold = BundleItem.money_bundle(25000) + +vault_2500_bundle = MoneyBundleTemplate(CCRoom.vault, vault_2500_gold) +vault_5000_bundle = MoneyBundleTemplate(CCRoom.vault, vault_5000_gold) +vault_10000_bundle = MoneyBundleTemplate(CCRoom.vault, vault_10000_gold) +vault_25000_bundle = MoneyBundleTemplate(CCRoom.vault, vault_25000_gold) + +vault_gambler_items = BundleItem(Currency.qi_coin, 10000) +vault_gambler_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.gambler, vault_gambler_items) + +vault_carnival_items = BundleItem(Currency.star_token, 2500) +vault_carnival_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.carnival, vault_carnival_items) + +vault_walnut_hunter_items = BundleItem(Currency.golden_walnut, 25) +vault_walnut_hunter_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.walnut_hunter, vault_walnut_hunter_items) + +vault_qi_helper_items = BundleItem(Currency.qi_gem, 25) +vault_qi_helper_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.qi_helper, vault_qi_helper_items) + +vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] +vault_bundles_thematic = vault_bundles_vanilla +vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle, vault_carnival_bundle] # , vault_walnut_hunter_bundle +vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles_vanilla, 4) +vault_thematic = BundleRoomTemplate(CCRoom.vault, vault_bundles_thematic, 4) +vault_remixed = BundleRoomTemplate(CCRoom.vault, vault_bundles_remixed, 4) all_bundle_items_except_money = [] diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index aa5365d09e41..b1cc58018c48 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -664,7 +664,7 @@ id,name,classification,groups,mod_name 5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", 5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", 5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5202,30 Qi Gems,useful,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", @@ -700,7 +700,7 @@ id,name,classification,groups,mod_name 5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", 5236,Aquatic Sanctuary,filler,RESOURCE_PACK, 5242,Exotic Double Bed,filler,RESOURCE_PACK, -5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK", +5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", 5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", 5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 528a29a2b56d..baf5f4e698af 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -76,6 +76,10 @@ id,region,name,tags,mod_name 89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,"Gambler's Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,"Carnival Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,"Walnut Hunter Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,"Qi's Helper Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 101,Pierre's General Store,Large Pack,BACKPACK, 102,Pierre's General Store,Deluxe Pack,BACKPACK, 103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index b31f53be7728..375f6fa6bec8 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -13,7 +13,7 @@ from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, \ Friendsanity, Museumsanity, \ Fishsanity, BuildingProgression, SkillProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations, Monstersanity, Goal, \ - Shipsanity, Chefsanity, Craftsanity + Shipsanity, Chefsanity, Craftsanity, BundleRandomization, BundlePrice from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff from .strings.ap_names.event_names import Event @@ -423,7 +423,7 @@ def create_player_buffs(item_factory: StardewItemFactory, options: StardewValley need_all_buffs = options.special_order_locations == SpecialOrderLocations.option_board_qi need_half_buffs = options.festival_locations == FestivalLocations.option_easy create_player_buff(item_factory, Buff.movement, movement_buffs, need_all_buffs, need_half_buffs, items) - create_player_buff(item_factory, Buff.luck, luck_buffs, need_all_buffs, need_half_buffs, items) + create_player_buff(item_factory, Buff.luck, luck_buffs, True, need_half_buffs, items) def create_player_buff(item_factory, buff: str, amount: int, need_all_buffs: bool, need_half_buffs: bool, items: List[Item]): @@ -501,11 +501,19 @@ def special_order_board_item_classification(item: ItemData, need_all_recipes: bo def create_special_order_qi_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - if (options.special_order_locations != SpecialOrderLocations.option_board_qi or - options.exclude_ginger_island == ExcludeGingerIsland.option_true): + if options.exclude_ginger_island == ExcludeGingerIsland.option_true: return - qi_gem_rewards = ["100 Qi Gems", "10 Qi Gems", "40 Qi Gems", "25 Qi Gems", "25 Qi Gems", - "40 Qi Gems", "20 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems"] + qi_gem_rewards = [] + if options.bundle_randomization >= BundleRandomization.option_remixed: + qi_gem_rewards.append("15 Qi Gems") + qi_gem_rewards.append("15 Qi Gems") + if options.bundle_price >= BundlePrice.option_expensive: + qi_gem_rewards.append("15 Qi Gems") + + if options.special_order_locations == SpecialOrderLocations.option_board_qi: + qi_gem_rewards.extend(["100 Qi Gems", "10 Qi Gems", "40 Qi Gems", "25 Qi Gems", "25 Qi Gems", + "40 Qi Gems", "20 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems"]) + qi_gem_items = [item_factory(reward) for reward in qi_gem_rewards] items.extend(qi_gem_items) diff --git a/worlds/stardew_valley/logic/ability_logic.py b/worlds/stardew_valley/logic/ability_logic.py index ad444ad99fca..ae12ffee4742 100644 --- a/worlds/stardew_valley/logic/ability_logic.py +++ b/worlds/stardew_valley/logic/ability_logic.py @@ -8,7 +8,6 @@ from .tool_logic import ToolLogicMixin from ..mods.logic.magic_logic import MagicLogicMixin from ..stardew_rule import StardewRule -from ..strings.ap_names.buff_names import Buff from ..strings.region_names import Region from ..strings.skill_names import Skill, ModSkill from ..strings.tool_names import ToolMaterial, Tool @@ -45,6 +44,3 @@ def can_chop_perfectly(self) -> StardewRule: foraging_rule = self.logic.skill.has_level(Skill.foraging, 10) region_rule = self.logic.region.can_reach(Region.forest) return region_rule & ((tool_rule & foraging_rule) | magic_rule) - - def has_max_buffs(self) -> StardewRule: - return self.logic.received(Buff.movement, self.options.movement_buff_number.value) & self.logic.received(Buff.luck, self.options.luck_buff_number.value) diff --git a/worlds/stardew_valley/logic/buff_logic.py b/worlds/stardew_valley/logic/buff_logic.py new file mode 100644 index 000000000000..fee9c9fc4d25 --- /dev/null +++ b/worlds/stardew_valley/logic/buff_logic.py @@ -0,0 +1,23 @@ +from typing import Union + +from .base_logic import BaseLogicMixin, BaseLogic +from .received_logic import ReceivedLogicMixin +from ..stardew_rule import StardewRule +from ..strings.ap_names.buff_names import Buff + + +class BuffLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.buff = BuffLogic(*args, **kwargs) + + +class BuffLogic(BaseLogic[Union[ReceivedLogicMixin]]): + def has_max_buffs(self) -> StardewRule: + return self.has_max_speed() & self.has_max_luck() + + def has_max_speed(self) -> StardewRule: + return self.logic.received(Buff.movement, self.options.movement_buff_number.value) + + def has_max_luck(self) -> StardewRule: + return self.logic.received(Buff.luck, self.options.luck_buff_number.value) diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 544d9d5273c3..4ff83eeb2c56 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -29,8 +29,8 @@ def can_complete_bundle(self, bundle: Bundle) -> StardewRule: qualities = [] can_speak_junimo = self.logic.region.can_reach(Region.wizard_tower) for bundle_item in bundle.items: - if bundle_item.item_name == Currency.money: - return can_speak_junimo & self.logic.money.can_spend(bundle_item.amount) + if Currency.is_currency(bundle_item.item_name): + return can_speak_junimo & self.logic.money.can_trade(bundle_item.item_name, bundle_item.amount) item_rules.append(bundle_item.item_name) qualities.append(bundle_item.quality) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 680329fe1089..33b0e23bb7ce 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -2,6 +2,7 @@ from dataclasses import dataclass +from .buff_logic import BuffLogicMixin from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from .ability_logic import AbilityLogicMixin from .action_logic import ActionLogicMixin @@ -87,9 +88,10 @@ @dataclass(frozen=False, repr=False) -class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, - ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, - MuseumLogicMixin, WalletLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, +class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, BuffLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, + SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, + BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, + CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin, SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin): player: int diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index ef7b8c6c3811..6dcdee6fd19d 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -2,16 +2,17 @@ from Utils import cache_self1 from .base_logic import BaseLogicMixin, BaseLogic +from .buff_logic import BuffLogicMixin from .has_logic import HasLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin -from ..stardew_rule import StardewRule, True_, CountPercent +from ..stardew_rule import StardewRule, True_, CountPercent, False_ from ..strings.currency_names import Currency from ..strings.region_names import Region qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", - "25 Qi Gems", "20 Qi Gems", "10 Qi Gems") + "25 Qi Gems", "20 Qi Gems", "10 Qi Gems", "15 Qi Gems", "15 Qi Gems", "15 Qi Gems") class MoneyLogicMixin(BaseLogicMixin): @@ -20,7 +21,7 @@ def __init__(self, *args, **kwargs): self.money = MoneyLogic(*args, **kwargs) -class MoneyLogic(BaseLogic[Union[MoneyLogicMixin, TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): +class MoneyLogic(BaseLogic[Union[RegionLogicMixin, MoneyLogicMixin, TimeLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin, BuffLogicMixin]]): @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: @@ -44,13 +45,31 @@ def can_spend_at(self, region: str, amount: int) -> StardewRule: return self.logic.region.can_reach(region) & self.logic.money.can_spend(amount) # Should be cached - def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: + def can_trade(self, currency: str, amount: int) -> StardewRule: if amount == 0: return True_() if currency == Currency.money: - return self.logic.money.can_spend_at(region, amount) + return self.can_spend(amount) + if currency == Currency.star_token: + return self.logic.region.can_reach(Region.fair) + if currency == Currency.qi_coin: + return self.logic.region.can_reach(Region.casino) & self.logic.buff.has_max_luck() if currency == Currency.qi_gem: - number_rewards = min(10, max(1, (amount // 10) + 2)) + number_rewards = min(13, max(1, (amount // 10))) return self.logic.received(qi_gem_rewards, number_rewards) + if currency == Currency.golden_walnut: + return self.can_spend_walnut(amount) + + return self.logic.has(currency) & self.logic.time.has_lived_months(amount) + + # Should be cached + def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule: + if amount == 0: + return True_() + if currency == Currency.money: + return self.logic.money.can_spend_at(region, amount) + + return self.logic.region.can_reach(region) & self.can_trade(currency, amount) - return self.logic.region.can_reach(region) & self.logic.has(currency) + def can_spend_walnut(self, amount: int) -> StardewRule: + return False_() diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 8ad27f9997fc..e1558bbf3ee8 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -4,6 +4,7 @@ from .arcade_logic import ArcadeLogicMixin from .artisan_logic import ArtisanLogicMixin from .base_logic import BaseLogicMixin, BaseLogic +from .buff_logic import BuffLogicMixin from .cooking_logic import CookingLogicMixin from .has_logic import HasLogicMixin from .mine_logic import MineLogicMixin @@ -42,8 +43,9 @@ def __init__(self, *args, **kwargs): class SpecialOrderLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, MoneyLogicMixin, -ShippingLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, RelationshipLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, CookingLogicMixin, -AbilityLogicMixin, SpecialOrderLogicMixin]]): + ShippingLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, RelationshipLogicMixin, ToolLogicMixin, SkillLogicMixin, + MineLogicMixin, CookingLogicMixin, BuffLogicMixin, + AbilityLogicMixin, SpecialOrderLogicMixin]]): def initialize_rules(self): self.update_rules({ @@ -79,14 +81,14 @@ def initialize_rules(self): SpecialOrder.lets_play_a_game: self.logic.arcade.has_junimo_kart_max_level(), SpecialOrder.four_precious_stones: self.logic.time.has_lived_max_months & self.logic.has("Prismatic Shard") & self.logic.ability.can_mine_perfectly_in_the_skull_cavern(), - SpecialOrder.qis_hungry_challenge: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.ability.has_max_buffs(), + SpecialOrder.qis_hungry_challenge: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.buff.has_max_buffs(), SpecialOrder.qis_cuisine: self.logic.cooking.can_cook() & self.logic.shipping.can_ship_items & (self.logic.money.can_spend_at(Region.saloon, 205000) | self.logic.money.can_spend_at(Region.pierre_store, 170000)), SpecialOrder.qis_kindness: self.logic.relationship.can_give_loved_gifts_to_everyone(), SpecialOrder.extended_family: self.logic.ability.can_fish_perfectly() & self.logic.has(Fish.angler) & self.logic.has(Fish.glacierfish) & self.logic.has(Fish.crimsonfish) & self.logic.has(Fish.mutant_carp) & self.logic.has(Fish.legend), SpecialOrder.danger_in_the_deep: self.logic.ability.can_mine_perfectly() & self.logic.mine.has_mine_elevator_to_floor(120), - SpecialOrder.skull_cavern_invasion: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.ability.has_max_buffs(), + SpecialOrder.skull_cavern_invasion: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.buff.has_max_buffs(), SpecialOrder.qis_prismatic_grange: self.logic.has(Loot.bug_meat) & # 100 Bug Meat self.logic.money.can_spend_at(Region.saloon, 24000) & # 100 Spaghetti self.logic.money.can_spend_at(Region.blacksmith, 15000) & # 100 Copper Ore diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 242ed987426f..47cdcdc2f48c 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -63,4 +63,8 @@ class BundleName: forager = "Forager's Bundle" home_cook = "Home Cook's Bundle" bartender = "Bartender's Bundle" + gambler = "Gambler's Bundle" + carnival = "Carnival Bundle" + walnut_hunter = "Walnut Hunter Bundle" + qi_helper = "Qi's Helper Bundle" missing_bundle = "The Missing Bundle" diff --git a/worlds/stardew_valley/strings/currency_names.py b/worlds/stardew_valley/strings/currency_names.py index bb2d9f6b0fcb..5192466c9ca7 100644 --- a/worlds/stardew_valley/strings/currency_names.py +++ b/worlds/stardew_valley/strings/currency_names.py @@ -1,8 +1,13 @@ class Currency: + qi_coin = "Qi Coin" golden_walnut = "Golden Walnut" qi_gem = "Qi Gem" star_token = "Star Token" money = "Money" cinder_shard = "Cinder Shard" + @staticmethod + def is_currency(item: str) -> bool: + return item in [Currency.qi_coin, Currency.golden_walnut, Currency.qi_gem, Currency.star_token, Currency.money] + diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 2996f5b7511c..02b580fb4299 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -63,12 +63,12 @@ def test_given_special_range_when_generate_then_basic_checks(self): basic_checks(self, multiworld) def test_given_choice_when_generate_then_basic_checks(self): - seed = int(random() * pow(10, 18) - 1) options = StardewValleyWorld.options_dataclass.type_hints for option_name, option in options.items(): if not option.options: continue for value in option.options: + seed = int(random() * pow(10, 18) - 1) with self.subTest(f"{option_name}: {value} [Seed: {seed}]"): world_options = {option_name: option.options[value]} multiworld = setup_solo_multiworld(world_options, seed) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index e950266d4d04..708b77d9c57e 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -5,7 +5,7 @@ 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 + FriendsanityHeartSize, BundleRandomization from ..strings.entrance_names import Entrance from ..strings.region_names import Region @@ -93,6 +93,7 @@ def test_old_master_cannoli(self): class TestBundlesLogic(SVTestBase): options = { + BundleRandomization.internal_name: BundleRandomization.option_vanilla } def test_vault_2500g_bundle(self): diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 36a70fdac2b8..ea0530e27411 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -61,8 +61,8 @@ def get_minsanity_options(): def minimal_locations_maximal_items(): min_max_options = { Goal.internal_name: Goal.option_craft_master, - BundleRandomization.internal_name: BundleRandomization.option_vanilla, - BundlePrice.internal_name: BundlePrice.option_very_cheap, + BundleRandomization.internal_name: BundleRandomization.option_shuffled, + BundlePrice.internal_name: BundlePrice.option_expensive, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, Cropsanity.internal_name: Cropsanity.option_disabled, BackpackProgression.internal_name: BackpackProgression.option_vanilla, From 3c11b6dfa35e29387aba891fdef0ccab57ec1dc0 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Wed, 22 Nov 2023 18:35:35 -0500 Subject: [PATCH 207/482] fix a typo --- worlds/stardew_valley/content/__init__.py | 0 worlds/stardew_valley/logic/logic_and_mods_design.md | 2 +- worlds/stardew_valley/stardew_rule.py | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 worlds/stardew_valley/content/__init__.py diff --git a/worlds/stardew_valley/content/__init__.py b/worlds/stardew_valley/content/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/worlds/stardew_valley/logic/logic_and_mods_design.md b/worlds/stardew_valley/logic/logic_and_mods_design.md index b1d2109af6ac..14716e1af0e1 100644 --- a/worlds/stardew_valley/logic/logic_and_mods_design.md +++ b/worlds/stardew_valley/logic/logic_and_mods_design.md @@ -35,7 +35,7 @@ overriding their logic afterward. Might be too complicated for no real gain tho. # Content pack (idea) -Instead of using modules to hold the data, and have each mods adding their data to existing content, each mod data should be in a `ContentPack`. Vanilla, Ginger +Instead of using modules to hold the data, and have each mod adding their data to existing content, each mod data should be in a `ContentPack`. Vanilla, Ginger Island, or anything that could be disabled would be in a content pack as well. Eventually, Vanilla content could even be disabled (a split would be required for items that are necessary to all content packs) to have a Ginger Island only diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 10da27a443ff..5064ff045dab 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -374,7 +374,6 @@ def __call__(self, state: CollectionState) -> bool: return True return False - def __repr__(self): return f"CountPercent {self.percent}" From 79e1cee9a778c92de70dbe7a39f4eb275dc52ce4 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Wed, 22 Nov 2023 23:37:23 -0500 Subject: [PATCH 208/482] remove unused init --- worlds/stardew_valley/content/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 worlds/stardew_valley/content/__init__.py diff --git a/worlds/stardew_valley/content/__init__.py b/worlds/stardew_valley/content/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 From fc3251a62943c18ae69790d503ada0f464c4fc4f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 23 Nov 2023 22:16:00 -0500 Subject: [PATCH 209/482] - Fix skill_logic.py --- worlds/stardew_valley/logic/skill_logic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index b123077ca2ac..b7cd051ac0ab 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -16,7 +16,7 @@ from ..data import all_crops from ..mods.logic.magic_logic import MagicLogicMixin from ..mods.logic.mod_skills_levels import get_mod_skill_levels -from ..stardew_rule import StardewRule, True_, Or +from ..stardew_rule import StardewRule, True_, Or, False_ from ..strings.machine_names import Machine from ..strings.performance_names import Performance from ..strings.quality_names import ForageQuality @@ -34,7 +34,7 @@ def __init__(self, *args, **kwargs): class SkillLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, ToolLogicMixin, SkillLogicMixin, -CombatLogicMixin, CropLogicMixin, MagicLogicMixin]]): + CombatLogicMixin, CropLogicMixin, MagicLogicMixin]]): # Should be cached def can_earn_level(self, skill: str, level: int) -> StardewRule: if level <= 0: From 025a6f235df1353d39d29f7c72fe86dfc1a950a0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 25 Nov 2023 20:32:57 -0500 Subject: [PATCH 210/482] - Added a few remixed bundkes --- worlds/stardew_valley/__init__.py | 4 +- worlds/stardew_valley/bundles/bundles.py | 12 ++++-- worlds/stardew_valley/data/bundle_data.py | 39 ++++++++++++++++--- worlds/stardew_valley/data/locations.csv | 2 + worlds/stardew_valley/items.py | 6 +-- worlds/stardew_valley/locations.py | 4 +- worlds/stardew_valley/rules.py | 3 ++ worlds/stardew_valley/strings/bundle_names.py | 2 + worlds/stardew_valley/test/TestGeneration.py | 14 ++++++- worlds/stardew_valley/test/__init__.py | 7 ++++ 10 files changed, 74 insertions(+), 19 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 996a024aff4b..6a85d2fd6b65 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -329,8 +329,8 @@ def fill_slot_data(self) -> Dict[str, Any]: bundles[room.name] = dict() for bundle in room.bundles: bundles[room.name][bundle.name] = {"number_required": bundle.number_required} - for item in bundle.items: - bundles[room.name][bundle.name][item.item_name] = f"{item.amount} of {item.quality}" + for i, item in enumerate(bundle.items): + bundles[room.name][bundle.name][i] = f"{item.item_name}|{item.amount}|{item.quality}" excluded_options = [BundleRandomization, BundlePrice, NumberOfMovementBuffs, NumberOfLuckBuffs] excluded_option_names = [option.internal_name for option in excluded_options] diff --git a/worlds/stardew_valley/bundles/bundles.py b/worlds/stardew_valley/bundles/bundles.py index 64da9f1c62f6..f4dca7f14df6 100644 --- a/worlds/stardew_valley/bundles/bundles.py +++ b/worlds/stardew_valley/bundles/bundles.py @@ -4,7 +4,8 @@ from .bundle_room import BundleRoom from ..data.bundle_data import pantry_vanilla, crafts_room_vanilla, fish_tank_vanilla, boiler_room_vanilla, bulletin_board_vanilla, vault_vanilla, \ pantry_thematic, crafts_room_thematic, fish_tank_thematic, boiler_room_thematic, bulletin_board_thematic, vault_thematic, pantry_remixed, \ - crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed, vault_remixed, all_bundle_items_except_money + crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed, vault_remixed, all_bundle_items_except_money, \ + abandoned_joja_mart_thematic, abandoned_joja_mart_vanilla, abandoned_joja_mart_remixed from ..logic.logic import StardewLogic from ..options import BundleRandomization, StardewValleyOptions, ExcludeGingerIsland @@ -30,7 +31,8 @@ def get_vanilla_bundles(random: Random, options: StardewValleyOptions) -> List[B boiler_room = boiler_room_vanilla.create_bundle_room(options.bundle_price, random, allow_island) bulletin_board = bulletin_board_vanilla.create_bundle_room(options.bundle_price, random, allow_island) vault = vault_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault] + abandoned_joja_mart = abandoned_joja_mart_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart] def get_thematic_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: @@ -41,7 +43,8 @@ def get_thematic_bundles(random: Random, options: StardewValleyOptions) -> List[ boiler_room = boiler_room_thematic.create_bundle_room(options.bundle_price, random, allow_island) bulletin_board = bulletin_board_thematic.create_bundle_room(options.bundle_price, random, allow_island) vault = vault_thematic.create_bundle_room(options.bundle_price, random, allow_island) - return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault] + abandoned_joja_mart = abandoned_joja_mart_thematic.create_bundle_room(options.bundle_price, random, allow_island) + return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart] def get_remixed_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: @@ -52,7 +55,8 @@ def get_remixed_bundles(random: Random, options: StardewValleyOptions) -> List[B boiler_room = boiler_room_remixed.create_bundle_room(options.bundle_price, random, allow_island) bulletin_board = bulletin_board_remixed.create_bundle_room(options.bundle_price, random, allow_island) vault = vault_remixed.create_bundle_room(options.bundle_price, random, allow_island) - return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault] + abandoned_joja_mart = abandoned_joja_mart_remixed.create_bundle_room(options.bundle_price, random, allow_island) + return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart] def get_shuffled_bundles(random: Random, logic: StardewLogic, options: StardewValleyOptions) -> List[BundleRoom]: diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index b5d1a1ddf34f..4644f86201e3 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -6,6 +6,7 @@ from ..strings.bundle_names import CCRoom, BundleName from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency +from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro from ..strings.fish_names import Fish, WaterItem, Trash from ..strings.flower_names import Flower from ..strings.food_names import Beverage, Meal @@ -151,6 +152,18 @@ cherry = BundleItem(Fruit.cherry) banana = IslandBundleItem(Fruit.banana) mango = IslandBundleItem(Fruit.mango) + +basic_fertilizer = BundleItem(Fertilizer.basic, 100) +quality_fertilizer = BundleItem(Fertilizer.quality, 20) +deluxe_fertilizer = IslandBundleItem(Fertilizer.deluxe, 5) +basic_retaining_soil = BundleItem(RetainingSoil.basic, 80) +quality_retaining_soil = BundleItem(RetainingSoil.quality, 50) +deluxe_retaining_soil = IslandBundleItem(RetainingSoil.deluxe, 20) +speed_gro = BundleItem(SpeedGro.basic, 40) +deluxe_speed_gro = BundleItem(SpeedGro.deluxe, 20) +hyper_speed_gro = IslandBundleItem(SpeedGro.hyper, 5) +tree_fertilizer = BundleItem(Fertilizer.tree, 20) + lobster = BundleItem(Fish.lobster) crab = BundleItem(Fish.crab) shrimp = BundleItem(Fish.shrimp) @@ -433,12 +446,17 @@ island_crops_items = [pineapple, taro_root, banana, mango] island_crops_bundle = IslandBundleTemplate(CCRoom.pantry, BundleName.island_crops, island_crops_items, 3, 3) +agronomist_items = [basic_fertilizer, quality_fertilizer, deluxe_fertilizer, + basic_retaining_soil, quality_retaining_soil, deluxe_retaining_soil, + speed_gro, deluxe_speed_gro, hyper_speed_gro, tree_fertilizer] +agronomist_bundle = BundleTemplate(CCRoom.pantry, BundleName.agronomist, agronomist_items, 4, 3) + pantry_bundles_vanilla = [spring_crops_bundle_vanilla, summer_crops_bundle_vanilla, fall_crops_bundle_vanilla, quality_crops_bundle_vanilla, animal_bundle_vanilla, artisan_bundle_vanilla] pantry_bundles_thematic = [spring_crops_bundle_thematic, summer_crops_bundle_thematic, fall_crops_bundle_thematic, quality_crops_bundle_thematic, animal_bundle_thematic, artisan_bundle_thematic] pantry_bundles_remixed = [*pantry_bundles_thematic, rare_crops_bundle, fish_farmer_bundle, garden_bundle, - brewer_bundle, orchard_bundle, island_crops_bundle] + brewer_bundle, orchard_bundle, island_crops_bundle, agronomist_bundle] pantry_vanilla = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_vanilla, 6) pantry_thematic = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_thematic, 6) pantry_remixed = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_remixed, 6) @@ -467,9 +485,11 @@ night_fish_bundle_thematic = BundleTemplate.extend_from(night_fish_bundle_vanilla, night_fish_items_thematic) crab_pot_items_vanilla = [lobster, crayfish, crab, cockle, mussel, shrimp, snail, periwinkle, oyster, clam] -crab_pot_items_thematic = [*crab_pot_items_vanilla, trash, driftwood, soggy_newspaper, broken_cd, broken_glasses] +crab_pot_trash_items = [trash, driftwood, soggy_newspaper, broken_cd, broken_glasses] +crab_pot_items_thematic = [*crab_pot_items_vanilla, *crab_pot_trash_items] crab_pot_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.crab_pot, crab_pot_items_vanilla, 10, 5) crab_pot_bundle_thematic = BundleTemplate.extend_from(crab_pot_bundle_vanilla, crab_pot_items_thematic) +recycling_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.recycling, crab_pot_trash_items, 4, 4) specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip] specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip, @@ -511,8 +531,11 @@ night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla] fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic, night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic] -fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, - winter_fish_bundle, rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle] +fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, winter_fish_bundle, + recycling_bundle, rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle] +# In Remixed, the trash items are in the recycling bundle, so we don't use the thematic version of the crab pot bundle that added trash items to it +fish_tank_bundles_remixed.remove(crab_pot_bundle_thematic) +fish_tank_bundles_remixed.append(crab_pot_bundle_vanilla) fish_tank_vanilla = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_vanilla, 6) fish_tank_thematic = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_thematic, 6) fish_tank_remixed = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_remixed, 6) @@ -618,6 +641,12 @@ missing_bundle_vanilla = BundleTemplate(CCRoom.abandoned_joja_mart, BundleName.missing_bundle, missing_bundle_items_vanilla, 6, 5) missing_bundle_thematic = BundleTemplate.extend_from(missing_bundle_vanilla, missing_bundle_items_thematic) +abandoned_joja_mart_bundles_vanilla = [missing_bundle_vanilla] +abandoned_joja_mart_bundles_thematic = [missing_bundle_thematic] +abandoned_joja_mart_vanilla = BundleRoomTemplate(CCRoom.abandoned_joja_mart, abandoned_joja_mart_bundles_vanilla, 1) +abandoned_joja_mart_thematic = BundleRoomTemplate(CCRoom.abandoned_joja_mart, abandoned_joja_mart_bundles_thematic, 1) +abandoned_joja_mart_remixed = abandoned_joja_mart_thematic + # Make thematic with other currencies vault_2500_gold = BundleItem.money_bundle(2500) vault_5000_gold = BundleItem.money_bundle(5000) @@ -643,7 +672,7 @@ vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] vault_bundles_thematic = vault_bundles_vanilla -vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle, vault_carnival_bundle] # , vault_walnut_hunter_bundle +vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle] # , vault_carnival_bundle , vault_walnut_hunter_bundle vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles_vanilla, 4) vault_thematic = BundleRoomTemplate(CCRoom.vault, vault_bundles_thematic, 4) vault_remixed = BundleRoomTemplate(CCRoom.vault, vault_bundles_remixed, 4) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index baf5f4e698af..3f4b1955b74a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -49,6 +49,8 @@ id,region,name,tags,mod_name 53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 375f6fa6bec8..92430d3e336d 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -523,13 +523,9 @@ def create_tv_channels(item_factory: StardewItemFactory, items: List[Item]): def create_crafting_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - has_shipsanity = options.shipsanity == Shipsanity.option_everything has_craftsanity = options.craftsanity == Craftsanity.option_all - has_craft_master = options.goal == Goal.option_craft_master - need_qi_recipes = has_shipsanity or has_craftsanity or has_craft_master crafting_recipes = [] - if need_qi_recipes: - crafting_recipes.extend([recipe for recipe in items_by_group[Group.QI_CRAFTING_RECIPE]]) + crafting_recipes.extend([recipe for recipe in items_by_group[Group.QI_CRAFTING_RECIPE]]) if has_craftsanity: crafting_recipes.extend([recipe for recipe in items_by_group[Group.CRAFTSANITY]]) crafting_recipes = remove_excluded_items(crafting_recipes, options) diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 65d7022e3ace..b5866f4af504 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -317,7 +317,9 @@ def extend_mandatory_locations(randomized_locations: List[LocationData], options def extend_bundle_locations(randomized_locations: List[LocationData], bundle_rooms: List[BundleRoom]): for room in bundle_rooms: - randomized_locations.append(location_table[f"Complete {room.name}"]) + room_location = f"Complete {room.name}" + if room_location in location_table: + randomized_locations.append(location_table[room_location]) for bundle in room.bundles: randomized_locations.append(location_table[bundle.name]) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 9cb49ccb3fea..9c4108f61f0b 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -22,6 +22,7 @@ from .strings.ap_names.transport_names import Transportation from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building +from .strings.bundle_names import CCRoom from .strings.calendar_names import Weekday from .strings.craftable_names import Bomb from .strings.crop_names import Fruit @@ -126,6 +127,8 @@ def set_bundle_rules(bundle_rooms: List[BundleRoom], logic: StardewLogic, multiw bundle_rules = logic.bundle.can_complete_bundle(bundle).simplify() room_rules.append(bundle_rules) MultiWorldRules.set_rule(location, bundle_rules) + if bundle_room.name == CCRoom.abandoned_joja_mart: + continue room_location = f"Complete {bundle_room.name}" MultiWorldRules.add_rule(multiworld.get_location(room_location, player), And(*room_rules)) diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 47cdcdc2f48c..6aa273eaf7a1 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -34,11 +34,13 @@ class BundleName: brewer = "Brewer's Bundle" orchard = "Orchard Bundle" island_crops = "Island Crops Bundle" + agronomist = "Agronomist's Bundle" river_fish = "River Fish Bundle" lake_fish = "Lake Fish Bundle" ocean_fish = "Ocean Fish Bundle" night_fish = "Night Fishing Bundle" crab_pot = "Crab Pot Bundle" + recycling = "Recycling Bundle" specialty_fish = "Specialty Fish Bundle" spring_fish = "Spring Fishing Bundle" summer_fish = "Summer Fishing Bundle" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index d55e3a4a2445..988eb9abeea6 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -3,7 +3,7 @@ from BaseClasses import ItemClassification, MultiWorld, Item from . import setup_solo_multiworld, SVTestBase, get_minsanity_options, allsanity_options_without_mods, \ - allsanity_options_with_mods, minimal_locations_maximal_items, SVTestCase, default_options + allsanity_options_with_mods, minimal_locations_maximal_items, SVTestCase, default_options, minimal_locations_maximal_items_with_island from .. import locations, items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name from ..items import Group, item_table @@ -343,7 +343,17 @@ def test_minimal_location_maximal_items_still_valid(self): number_items = len([item for item in multiworld.itempool if Group.RESOURCE_PACK not in item_table[item.name].groups and Group.TRAP not in item_table[item.name].groups]) self.assertGreaterEqual(number_locations, number_items) - print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items}") + print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items} [ISLAND EXCLUDED]") + + def test_minimal_location_maximal_items_with_island_still_valid(self): + min_max_options = minimal_locations_maximal_items_with_island() + multiworld = setup_solo_multiworld(min_max_options) + valid_locations = get_real_locations(self, multiworld) + number_locations = len(valid_locations) + number_items = len([item for item in multiworld.itempool + if Group.RESOURCE_PACK not in item_table[item.name].groups and Group.TRAP not in item_table[item.name].groups]) + self.assertGreaterEqual(number_locations, number_items) + print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items} [ISLAND INCLUDED]") def test_minsanity_has_fewer_than_locations(self): expected_locations = 122 diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index ea0530e27411..a295171b5028 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -92,6 +92,13 @@ def minimal_locations_maximal_items(): return min_max_options +@cache_argsless +def minimal_locations_maximal_items_with_island(): + min_max_options = minimal_locations_maximal_items() + min_max_options.update({ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false}) + return min_max_options + + @cache_argsless def allsanity_options_without_mods(): allsanity = { From 75b781c32848071cf1ad94eeaf01823b3e6ad4fd Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 23 Nov 2023 22:45:26 -0500 Subject: [PATCH 211/482] Run fill in performance tests --- worlds/stardew_valley/test/__init__.py | 10 ++++++++-- .../test/performance/TestPerformance.py | 13 ++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index a295171b5028..f9d35700cdd2 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -7,9 +7,9 @@ from Utils import cache_argsless from test.bases import WorldTestBase from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld +from worlds.AutoWorld import call_all from .. import StardewValleyWorld from ..mods.mod_data import all_mods -from worlds.AutoWorld import call_all from ..options import Cropsanity, SkillProgression, SpecialOrderLocations, Friendsanity, NumberOfLuckBuffs, SeasonRandomization, ToolProgression, \ ElevatorProgression, Museumsanity, BackpackProgression, BuildingProgression, ArcadeMachineLocations, HelpWantedLocations, Fishsanity, NumberOfMovementBuffs, \ BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods, Monstersanity, Shipsanity, \ @@ -151,6 +151,8 @@ class SVTestCase(unittest.TestCase): skip_long_tests: bool = True """Set to False to run tests that take long""" skip_performance_tests: bool = True + """Set to False to not call the fill in the tests""" + skip_fill: bool = True options = get_minsanity_options() @@ -163,6 +165,10 @@ def setUp(self) -> None: if performance_tests_key in os.environ: self.skip_performance_tests = not bool(os.environ[performance_tests_key]) + fill_tests_key = "fill" + if fill_tests_key in os.environ: + self.skip_fill = not bool(os.environ[fill_tests_key]) + class SVTestBase(WorldTestBase, SVTestCase): @@ -235,7 +241,7 @@ def setup_multiworld(test_options: Iterable[Dict[str, int]] = None, seed=None) - for name, option in StardewValleyWorld.options_dataclass.type_hints.items(): options = {} for i in range(1, len(test_options) + 1): - player_options = test_options[i-1] + player_options = test_options[i - 1] value = option(player_options[name]) if name in player_options else option.from_any(option.default) options.update({i: value}) setattr(args, name, options) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index ff7595c5db60..bc62baff63aa 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -1,8 +1,9 @@ import time from BaseClasses import get_seed -from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, \ - allsanity_options_with_mods, setup_multiworld, default_options +from Fill import distribute_items_restrictive, balance_multiworld_progression +from worlds import AutoWorld +from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options number_generations = 25 acceptable_deviation = 4 @@ -17,7 +18,14 @@ def performance_test_multiworld(tester, options, acceptable_time_per_player): seed = get_seed() with tester.subTest(f"Seed: {seed}"): time_before = time.time() + + print(f"Starting world setup") multiworld = setup_multiworld(options, seed) + distribute_items_restrictive(multiworld) + AutoWorld.call_all(multiworld, 'post_fill') + if multiworld.players > 1: + balance_multiworld_progression(multiworld) + time_after = time.time() elapsed_time = time_after - time_before total_time += elapsed_time @@ -159,7 +167,6 @@ def test_10_player(self): multiworld_options = [self.options] * number_players performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) - # class TestAllsanityWithMods(SVTestCase): # # def test_allsanity_with_mods_has_at_least_locations(self): From c90fa9b60f1244597d63e8b297c8df7db1960559 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 23 Nov 2023 23:28:44 -0500 Subject: [PATCH 212/482] rename count percent to has progression percent --- worlds/stardew_valley/__init__.py | 6 +++--- worlds/stardew_valley/logic/money_logic.py | 4 ++-- worlds/stardew_valley/logic/time_logic.py | 4 ++-- worlds/stardew_valley/stardew_rule.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 6a85d2fd6b65..9be73840d536 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -17,7 +17,7 @@ from .presets import sv_options_presets from .regions import create_regions from .rules import set_rules -from .stardew_rule import True_, StardewRule, CountPercent +from .stardew_rule import True_, StardewRule, HasProgressionPercent from .strings.ap_names.event_names import Event from .strings.goal_names import Goal as GoalName @@ -255,11 +255,11 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_allsanity: self.create_event_location(location_table[GoalName.allsanity], - CountPercent(self.player, 100), + HasProgressionPercent(self.player, 100), Event.victory) elif self.options.goal == Goal.option_perfection: self.create_event_location(location_table[GoalName.perfection], - CountPercent(self.player, 100), + HasProgressionPercent(self.player, 100), Event.victory) self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 6dcdee6fd19d..146561f49193 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -7,7 +7,7 @@ from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin -from ..stardew_rule import StardewRule, True_, CountPercent, False_ +from ..stardew_rule import StardewRule, True_, HasProgressionPercent, False_ from ..strings.currency_names import Currency from ..strings.region_names import Region @@ -32,7 +32,7 @@ def can_have_earned_total(self, amount: int) -> StardewRule: return shipping_bin_rule percent_progression_items_needed = min(100, amount // 10000) - return shipping_bin_rule & CountPercent(self.player, percent_progression_items_needed) + return shipping_bin_rule & HasProgressionPercent(self.player, percent_progression_items_needed) @cache_self1 def can_spend(self, amount: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 9152c3fa2458..a1c2134776fd 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -4,7 +4,7 @@ from Utils import cache_self1 from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin -from ..stardew_rule import StardewRule, CountPercent, True_ +from ..stardew_rule import StardewRule, HasProgressionPercent, True_ MAX_MONTHS = 12 MONTH_COEFFICIENT = 100 // MAX_MONTHS @@ -23,7 +23,7 @@ def has_lived_months(self, number: int) -> StardewRule: if number <= 0: return True_() number = min(number, MAX_MONTHS) - return CountPercent(self.player, number * MONTH_COEFFICIENT) + return HasProgressionPercent(self.player, number * MONTH_COEFFICIENT) @cached_property def has_lived_max_months(self) -> StardewRule: diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 5064ff045dab..18da71d0d12f 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -350,7 +350,7 @@ def simplify(self) -> StardewRule: return self.other_rules[self.item].simplify() -class CountPercent(StardewRule): +class HasProgressionPercent(StardewRule): player: int percent: int From 74c145f9f4214ebd73aa6c40f667bd99a2ccb347 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 24 Nov 2023 18:42:37 -0500 Subject: [PATCH 213/482] Run fill in performance tests --- worlds/stardew_valley/test/__init__.py | 4 +-- .../test/performance/TestPerformance.py | 35 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index f9d35700cdd2..e36041d35331 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -201,7 +201,7 @@ def collect_all_the_money(self): # Mostly a copy of test.general.setup_solo_multiworld, I just don't want to change the core. -def setup_solo_multiworld(test_options=None, seed=None, _cache: Dict[FrozenSet[Tuple[str, Any]], MultiWorld] = {}) -> MultiWorld: # noqa +def setup_solo_multiworld(test_options=None, seed=None, _cache: Dict[FrozenSet[Tuple[str, Any]], MultiWorld] = {}, _steps=gen_steps) -> MultiWorld: # noqa if test_options is None: test_options = {} @@ -218,7 +218,7 @@ def setup_solo_multiworld(test_options=None, seed=None, _cache: Dict[FrozenSet[T value = option(test_options[name]) if name in test_options else option.from_any(option.default) setattr(args, name, {1: value}) multiworld.set_options(args) - for step in gen_steps: + for step in _steps: call_all(multiworld, step) _cache[frozen_options] = multiworld diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index bc62baff63aa..9fbab476bcb4 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -9,7 +9,7 @@ acceptable_deviation = 4 -def performance_test_multiworld(tester, options, acceptable_time_per_player): +def performance_test_multiworld(tester, options, acceptable_time_per_player, skip_fill=True): number_players = len(options) acceptable_average_time = acceptable_time_per_player * number_players total_time = 0 @@ -21,10 +21,11 @@ def performance_test_multiworld(tester, options, acceptable_time_per_player): print(f"Starting world setup") multiworld = setup_multiworld(options, seed) - distribute_items_restrictive(multiworld) - AutoWorld.call_all(multiworld, 'post_fill') - if multiworld.players > 1: - balance_multiworld_progression(multiworld) + if not skip_fill: + distribute_items_restrictive(multiworld) + AutoWorld.call_all(multiworld, 'post_fill') + if multiworld.players > 1: + balance_multiworld_progression(multiworld) time_after = time.time() elapsed_time = time_after - time_before @@ -67,7 +68,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players # seed = 47965111899197590996 - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_duo(self): if self.skip_performance_tests: @@ -75,7 +76,7 @@ def test_duo(self): number_players = 2 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_5_player(self): if self.skip_performance_tests: @@ -83,7 +84,7 @@ def test_5_player(self): number_players = 5 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_10_player(self): if self.skip_performance_tests: @@ -91,7 +92,7 @@ def test_10_player(self): number_players = 10 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) class TestMinLocationMaxItems(SVTestCase): @@ -104,7 +105,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_duo(self): if self.skip_performance_tests: @@ -112,7 +113,7 @@ def test_duo(self): number_players = 2 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_5_player(self): if self.skip_performance_tests: @@ -120,7 +121,7 @@ def test_5_player(self): number_players = 5 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_10_player(self): if self.skip_performance_tests: @@ -128,7 +129,7 @@ def test_10_player(self): number_players = 10 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) class TestAllsanityWithoutMods(SVTestCase): @@ -141,7 +142,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_duo(self): if self.skip_performance_tests: @@ -149,7 +150,7 @@ def test_duo(self): number_players = 2 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_5_player(self): if self.skip_performance_tests: @@ -157,7 +158,7 @@ def test_5_player(self): number_players = 5 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) def test_10_player(self): if self.skip_performance_tests: @@ -165,7 +166,7 @@ def test_10_player(self): number_players = 10 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player) + performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) # class TestAllsanityWithMods(SVTestCase): # From f5ca3458673bdd0f1ff26a7e40c8c9bb64b70251 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 24 Nov 2023 20:05:40 -0500 Subject: [PATCH 214/482] fix seeds for more stability --- .../test/performance/TestPerformance.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 9fbab476bcb4..3475e843e88b 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -1,11 +1,16 @@ import time -from BaseClasses import get_seed from Fill import distribute_items_restrictive, balance_multiworld_progression from worlds import AutoWorld from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options -number_generations = 25 +# [get_seed() for i in range(25)] +default_seeds = [26726304721450259037, 19493037639362170392, 44164721370906817114, 26474738898839084739, 69120175480542843820, 48149350148064597489, + 75234106657911542927, 48255445659788767477, 51403062784428569537, 83505207683697218321, 31443992552358718495, 32042780995456241834, + 84919554258352630308, 85389057393026193188, 50198031915976050326, 77769362918960755651, 51141990932126554176, 25055921617426839758, + 68571386399161661782, 10489282145478582746, 82013340299462479898, 6654626230008781183, 49570869596326935545, 37049567542350773517, + 7595094757324306210] +number_generations = len(default_seeds) acceptable_deviation = 4 @@ -14,8 +19,7 @@ def performance_test_multiworld(tester, options, acceptable_time_per_player, ski acceptable_average_time = acceptable_time_per_player * number_players total_time = 0 all_times = {} - for i in range(number_generations): - seed = get_seed() + for i, seed in enumerate(default_seeds): with tester.subTest(f"Seed: {seed}"): time_before = time.time() From e1737b3fbef9516e421fc0f729147e39329cbdc3 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 24 Nov 2023 23:47:23 -0500 Subject: [PATCH 215/482] performance tests refactoring --- worlds/stardew_valley/test/__init__.py | 22 +-- .../test/performance/TestPerformance.py | 157 +++++++++++------- 2 files changed, 107 insertions(+), 72 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index e36041d35331..5c8d1d97bec1 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -145,29 +145,19 @@ class SVTestCase(unittest.TestCase): game = "Stardew Valley" world: StardewValleyWorld player: ClassVar[int] = 1 - """Set to False to not skip some 'extra' tests""" + # Set False to not skip some 'extra' tests skip_extra_tests: bool = True - """Set to False to run tests that take long""" + # Set False to run tests that take long skip_long_tests: bool = True - """Set to False to run tests that take long""" - skip_performance_tests: bool = True - """Set to False to not call the fill in the tests""" - skip_fill: bool = True options = get_minsanity_options() - def setUp(self) -> None: - super().setUp() + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() long_tests_key = "long" if long_tests_key in os.environ: - self.skip_long_tests = not bool(os.environ[long_tests_key]) - performance_tests_key = "performance" - if performance_tests_key in os.environ: - self.skip_performance_tests = not bool(os.environ[performance_tests_key]) - - fill_tests_key = "fill" - if fill_tests_key in os.environ: - self.skip_fill = not bool(os.environ[fill_tests_key]) + cls.skip_long_tests = not bool(os.environ[long_tests_key]) class SVTestBase(WorldTestBase, SVTestCase): diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 3475e843e88b..612b29118581 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -1,54 +1,97 @@ +import os import time +from dataclasses import dataclass +from statistics import mean, median, variance, stdev +from typing import List from Fill import distribute_items_restrictive, balance_multiworld_progression from worlds import AutoWorld from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options # [get_seed() for i in range(25)] -default_seeds = [26726304721450259037, 19493037639362170392, 44164721370906817114, 26474738898839084739, 69120175480542843820, 48149350148064597489, - 75234106657911542927, 48255445659788767477, 51403062784428569537, 83505207683697218321, 31443992552358718495, 32042780995456241834, - 84919554258352630308, 85389057393026193188, 50198031915976050326, 77769362918960755651, 51141990932126554176, 25055921617426839758, - 68571386399161661782, 10489282145478582746, 82013340299462479898, 6654626230008781183, 49570869596326935545, 37049567542350773517, - 7595094757324306210] +default_seeds = [26726304721450259037] * 25 number_generations = len(default_seeds) acceptable_deviation = 4 -def performance_test_multiworld(tester, options, acceptable_time_per_player, skip_fill=True): - number_players = len(options) - acceptable_average_time = acceptable_time_per_player * number_players - total_time = 0 - all_times = {} - for i, seed in enumerate(default_seeds): - with tester.subTest(f"Seed: {seed}"): - time_before = time.time() - - print(f"Starting world setup") - multiworld = setup_multiworld(options, seed) - if not skip_fill: - distribute_items_restrictive(multiworld) - AutoWorld.call_all(multiworld, 'post_fill') - if multiworld.players > 1: - balance_multiworld_progression(multiworld) - - time_after = time.time() - elapsed_time = time_after - time_before - total_time += elapsed_time - all_times[i] = elapsed_time - print(f"Multiworld {i + 1}/{number_generations} [{seed}] generated in {elapsed_time} seconds") - # tester.assertLessEqual(elapsed_time, acceptable_average_time * acceptable_deviation) - size = size_name(number_players) - average_time = total_time / number_generations - # Remove outliers - num_outliers = 0 - for world in all_times: - if all_times[world] > average_time * 4: - num_outliers += 1 - total_time -= all_times[world] - average_time = total_time / (number_generations - num_outliers) - print(f"Generated {(number_generations - num_outliers)} {size} multiworlds in {total_time} seconds") - print(f"Average time per world: {average_time} seconds (Acceptable: {acceptable_average_time})") - tester.assertLessEqual(average_time, acceptable_average_time) +@dataclass +class PerformanceResults: + case: SVTestCase + + amount_of_players: int + results: List[float] + acceptable_mean: float + + def __repr__(self): + size = size_name(self.amount_of_players) + + total_time = sum(self.results) + mean_time = mean(self.results) + median_time = median(self.results) + stdev_time = stdev(self.results, mean_time) + variance_time = variance(self.results, mean_time) + + return f"""Generated {len(self.results)} {size} multiworlds in {total_time:.4f} seconds. Average {mean_time:.4f} seconds (Acceptable: {self.acceptable_mean:.2f}) +Mean: {mean_time:.4f} Median: {median_time:.4f} Stdeviation: {stdev_time:.4f} Variance: {variance_time:.4f} Deviation percent: {stdev_time / mean_time:.2%}""" + + +class SVPerformanceTestCase(SVTestCase): + acceptable_time_per_player: float + results: List[PerformanceResults] + + # Set False to run tests that take long + skip_performance_tests: bool = True + # Set False to not call the fill in the tests""" + skip_fill: bool = True + + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + performance_tests_key = "performance" + if performance_tests_key in os.environ: + cls.skip_performance_tests = not bool(os.environ[performance_tests_key]) + + fill_tests_key = "fill" + if fill_tests_key in os.environ: + cls.skip_fill = not bool(os.environ[fill_tests_key]) + + @classmethod + def tearDownClass(cls) -> None: + case = None + for result in cls.results: + if type(result.case) is not case: + case = type(result.case) + print(case.__name__) + print(result) + print() + super().tearDownClass() + + def performance_test_multiworld(self, options): + amount_of_players = len(options) + acceptable_average_time = self.acceptable_time_per_player * amount_of_players + total_time = 0 + all_times = [] + for i, seed in enumerate(default_seeds): + with self.subTest(f"Seed: {seed}"): + time_before = time.time() + + print(f"Starting world setup") + multiworld = setup_multiworld(options, seed) + if not self.skip_fill: + distribute_items_restrictive(multiworld) + AutoWorld.call_all(multiworld, 'post_fill') + if multiworld.players > 1: + balance_multiworld_progression(multiworld) + + time_after = time.time() + elapsed_time = time_after - time_before + total_time += elapsed_time + all_times.append(elapsed_time) + print(f"Multiworld {i + 1}/{number_generations} [{seed}] generated in {elapsed_time:.4f} seconds") + # tester.assertLessEqual(elapsed_time, acceptable_average_time * acceptable_deviation) + + self.results.append(PerformanceResults(self, amount_of_players, all_times, acceptable_average_time)) + self.assertLessEqual(mean(all_times), acceptable_average_time) def size_name(number_players): @@ -61,9 +104,10 @@ def size_name(number_players): return f"{number_players}-player" -class TestDefaultOptions(SVTestCase): +class TestDefaultOptions(SVPerformanceTestCase): acceptable_time_per_player = 0.04 options = default_options() + results = [] def test_solo(self): if self.skip_performance_tests: @@ -71,8 +115,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players - # seed = 47965111899197590996 - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_duo(self): if self.skip_performance_tests: @@ -80,7 +123,7 @@ def test_duo(self): number_players = 2 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_5_player(self): if self.skip_performance_tests: @@ -88,7 +131,7 @@ def test_5_player(self): number_players = 5 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_10_player(self): if self.skip_performance_tests: @@ -96,12 +139,13 @@ def test_10_player(self): number_players = 10 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) -class TestMinLocationMaxItems(SVTestCase): +class TestMinLocationMaxItems(SVPerformanceTestCase): acceptable_time_per_player = 0.08 options = minimal_locations_maximal_items() + results = [] def test_solo(self): if self.skip_performance_tests: @@ -109,7 +153,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_duo(self): if self.skip_performance_tests: @@ -117,7 +161,7 @@ def test_duo(self): number_players = 2 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_5_player(self): if self.skip_performance_tests: @@ -125,7 +169,7 @@ def test_5_player(self): number_players = 5 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_10_player(self): if self.skip_performance_tests: @@ -133,12 +177,13 @@ def test_10_player(self): number_players = 10 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) -class TestAllsanityWithoutMods(SVTestCase): +class TestAllsanityWithoutMods(SVPerformanceTestCase): acceptable_time_per_player = 0.07 options = allsanity_options_without_mods() + results = [] def test_solo(self): if self.skip_performance_tests: @@ -146,7 +191,7 @@ def test_solo(self): number_players = 1 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_duo(self): if self.skip_performance_tests: @@ -154,7 +199,7 @@ def test_duo(self): number_players = 2 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_5_player(self): if self.skip_performance_tests: @@ -162,7 +207,7 @@ def test_5_player(self): number_players = 5 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) def test_10_player(self): if self.skip_performance_tests: @@ -170,7 +215,7 @@ def test_10_player(self): number_players = 10 multiworld_options = [self.options] * number_players - performance_test_multiworld(self, multiworld_options, self.acceptable_time_per_player, self.skip_fill) + self.performance_test_multiworld(multiworld_options) # class TestAllsanityWithMods(SVTestCase): # From ae957fea2b261e6fab3654e6b674ff93e2af40d1 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 00:52:58 -0500 Subject: [PATCH 216/482] shortcut geode logic if no geode --- worlds/stardew_valley/logic/museum_logic.py | 4 ++-- .../test/performance/TestPerformance.py | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 6d8c2836a324..c4af8a95313b 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -8,7 +8,7 @@ from .region_logic import RegionLogicMixin from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals -from ..stardew_rule import StardewRule, And, False_, Count +from ..stardew_rule import StardewRule, And, False_, Count, true_ from ..strings.region_names import Region @@ -29,7 +29,7 @@ def can_donate_museum_artifacts(self, number: int) -> StardewRule: @cache_self1 def can_find_museum_item(self, item: MuseumItem) -> StardewRule: region_rule = self.logic.region.can_reach_all_except_one(item.locations) - geodes_rule = And(*(self.logic.action.can_open_geode(geode) for geode in item.geodes)) + geodes_rule = And(*(self.logic.action.can_open_geode(geode) for geode in item.geodes)) if item.geodes else true_ # monster_rule = self.can_farm_monster(item.monsters) # extra_rule = True_() pan_rule = False_() diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 612b29118581..0daa7b54753e 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -4,13 +4,13 @@ from statistics import mean, median, variance, stdev from typing import List +from BaseClasses import get_seed from Fill import distribute_items_restrictive, balance_multiworld_progression from worlds import AutoWorld from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options -# [get_seed() for i in range(25)] -default_seeds = [26726304721450259037] * 25 -number_generations = len(default_seeds) +number_generations = 25 +default_seed = 58754761123126659868 acceptable_deviation = 4 @@ -71,7 +71,10 @@ def performance_test_multiworld(self, options): acceptable_average_time = self.acceptable_time_per_player * amount_of_players total_time = 0 all_times = [] - for i, seed in enumerate(default_seeds): + seeds = [get_seed() if self.skip_fill else default_seed + for _ in range(number_generations)] + + for i, seed in enumerate(seeds): with self.subTest(f"Seed: {seed}"): time_before = time.time() From 1a551f1e9e9fed6e066a4384cb5065ae60cf8012 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 01:20:29 -0500 Subject: [PATCH 217/482] invert and and or for better code reuse --- worlds/stardew_valley/stardew_rule.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 18da71d0d12f..93774e5b397d 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -14,14 +14,14 @@ def __call__(self, state: CollectionState) -> bool: raise NotImplementedError def __or__(self, other) -> StardewRule: - if type(other) is Or: - return Or(self, *other.rules) + if other is true_ or other is false_ or type(other) is Or: + return other | self return Or(self, other) def __and__(self, other) -> StardewRule: - if type(other) is And: - return And(*other.rules.union({self})) + if other is true_ or other is false_ or type(other) is And: + return other & self return And(self, other) @@ -103,10 +103,9 @@ def __repr__(self): return f"({' | '.join(repr(rule) for rule in self.rules)})" def __or__(self, other): - if other is true_: - return other - if other is false_: - return self + if other is true_ or other is false_: + return other | self + if type(other) is Or: return Or(*self.rules.union(other.rules)) @@ -158,10 +157,9 @@ def __repr__(self): return f"({' & '.join(repr(rule) for rule in self.rules)})" def __and__(self, other): - if other is true_: - return self - if other is false_: - return other + if other is true_ or other is false_: + return other & self + if type(other) is And: return And(*self.rules.union(other.rules)) From 68a2165f82a1f31c30d68c7bd19e68b9312f2563 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 24 Nov 2023 18:46:24 -0500 Subject: [PATCH 218/482] and optimization --- worlds/stardew_valley/stardew_rule.py | 63 ++++++++++++++----- .../test/TestLogicSimplification.py | 23 ++++++- worlds/stardew_valley/test/TestRules.py | 38 +++++++---- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 93774e5b397d..49060567909d 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,7 +1,8 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Iterable, Dict, List, Union, FrozenSet +from functools import reduce +from typing import Iterable, Dict, List, Union, FrozenSet, Optional, Sized from BaseClasses import CollectionState, ItemClassification from .items import item_table @@ -85,6 +86,8 @@ def get_difficulty(self): assert false_ is False_() assert true_ is True_() +_default_has_progression_percent = object() + class Or(StardewRule): rules: FrozenSet[StardewRule] @@ -143,27 +146,42 @@ def simplify(self) -> StardewRule: class And(StardewRule): rules: FrozenSet[StardewRule] _simplified: bool + _has_progression_percent: Optional[HasProgressionPercent] - def __init__(self, *rules: StardewRule): - self.rules = frozenset(rules) + def __init__(self, *rules: StardewRule, _has_progression_percent=_default_has_progression_percent): self._simplified = False + if _has_progression_percent is _default_has_progression_percent: + assert rules, "Can't create a And conditions without rules" + _has_progression_percent = HasProgressionPercent.reduce_and([i for i in rules if type(i) is HasProgressionPercent]) + if rules is not None: + rules = (i for i in rules if type(i) is not HasProgressionPercent) + + self.rules = frozenset(rules) + self._has_progression_percent = _has_progression_percent + def __call__(self, state: CollectionState) -> bool: self.simplify() result = all(rule(state) for rule in self.rules) return result def __repr__(self): - return f"({' & '.join(repr(rule) for rule in self.rules)})" + prefix = repr(self._has_progression_percent) + " & " if self._has_progression_percent else "" + return f"({prefix}{' & '.join(repr(rule) for rule in self.rules)})" def __and__(self, other): if other is true_ or other is false_: return other & self + if type(other) is HasProgressionPercent: + if self._has_progression_percent: + return And(*self.rules, _has_progression_percent=self._has_progression_percent & other) + return And(*self.rules, _has_progression_percent=other) + if type(other) is And: - return And(*self.rules.union(other.rules)) + return And(*self.rules.union(other.rules), _has_progression_percent=self._has_progression_percent) - return And(*self.rules.union({other})) + return And(*self.rules.union({other}), _has_progression_percent=self._has_progression_percent) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -180,7 +198,9 @@ def simplify(self) -> StardewRule: if false_ in self.rules: return false_ - simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules} + rules = self.rules.union({self._has_progression_percent}) if self._has_progression_percent else self.rules + simplified_rules = [simplified + for simplified in {rule.simplify() for rule in rules} if simplified is not true_] if not simplified_rules: @@ -348,17 +368,22 @@ def simplify(self) -> StardewRule: return self.other_rules[self.item].simplify() +@dataclass(frozen=True) class HasProgressionPercent(StardewRule): player: int percent: int - def __init__(self, player: int, percent: int): - - assert percent > 0, "CountPercent rule must be above 0%" - assert percent <= 100, "CountPercent rule can't require more than 100% of items" + @staticmethod + def reduce_and(rules: Union[Iterable[HasProgressionPercent], Sized]) -> Optional[HasProgressionPercent]: + if not rules: + return None + if len(rules) == 1: + return next(iter(rules)) + return reduce(HasProgressionPercent.__and__, (i for i in rules if type(rules) is HasProgressionPercent)) - self.player = player - self.percent = percent + def __post_init__(self): + assert self.percent > 0, "HasProgressionPercent rule must be above 0%" + assert self.percent <= 100, "HasProgressionPercent rule can't require more than 100% of items" def __call__(self, state: CollectionState) -> bool: stardew_world = state.multiworld.worlds[self.player] @@ -373,7 +398,17 @@ def __call__(self, state: CollectionState) -> bool: return False def __repr__(self): - return f"CountPercent {self.percent}" + return f"HasProgressionPercent {self.percent}" + + def __and__(self, other): + if type(other) is HasProgressionPercent: + return max(self, other, key=lambda x: x.percent) + return super().__and__(other) + + def __or__(self, other): + if type(other) is HasProgressionPercent: + return min(self, other, key=lambda x: x.percent) + return super().__or__(other) def get_difficulty(self): return self.percent diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index ce58ea557820..b16a14e66b8a 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -1,5 +1,6 @@ import unittest -from ..stardew_rule import Received, Has, False_, And, Or, True_ + +from ..stardew_rule import Received, Has, False_, And, Or, True_, HasProgressionPercent class TestSimplification(unittest.TestCase): @@ -56,3 +57,23 @@ def test_simplify_true_in_or(self): def test_simplify_false_in_and(self): rule = And(False_(), Received('Summer', 0, 1)) self.assertEqual(rule.simplify(), False_()) + + +class TestHasProgressionPercentSimplification(unittest.TestCase): + def test_has_progression_percent_and_uses_max(self): + rule = HasProgressionPercent(1, 20) & HasProgressionPercent(1, 10) + self.assertEqual(rule, HasProgressionPercent(1, 20)) + + def test_has_progression_percent_or_uses_min(self): + rule = HasProgressionPercent(1, 20) | HasProgressionPercent(1, 10) + self.assertEqual(rule, HasProgressionPercent(1, 10)) + + def test_and_between_progression_percent_and_other_progression_percent_uses_max(self): + cases = [ + And(HasProgressionPercent(1, 10)) & HasProgressionPercent(1, 20), + HasProgressionPercent(1, 10) & And(HasProgressionPercent(1, 20)), + And(HasProgressionPercent(1, 20)) & And(HasProgressionPercent(1, 10)), + ] + for i, case in enumerate(cases): + with self.subTest(f"{i} {repr(case)}"): + self.assertEqual(case, And(HasProgressionPercent(1, 20))) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 708b77d9c57e..9a3708034101 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -1,11 +1,11 @@ from collections import Counter from . import SVTestBase -from .. import options +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 + FriendsanityHeartSize, BundleRandomization, SkillProgression from ..strings.entrance_names import Entrance from ..strings.region_names import Region @@ -117,19 +117,19 @@ def test_coop_blueprint(self): 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)}") + 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)}") + 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)}") + 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)}") + 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)) @@ -147,19 +147,19 @@ def test_deluxe_coop_blueprint(self): 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)}") + 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)}") + 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)}") + 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)}") + f"Rule is {repr(self.multiworld.get_location('Big Shed Blueprint', self.player).access_rule)}") class TestArcadeMachinesLogic(SVTestBase): @@ -576,7 +576,8 @@ def test_cannot_make_any_donation_without_museum_access(self): guild_item = "Adventurer's Guild" swap_museum_and_guild(self.multiworld, self.player) collect_all_except(self.multiworld, guild_item) - donation_locations = [location for location in self.multiworld.get_locations() if not location.event and LocationTags.MUSEUM_DONATIONS in location_table[location.name].tags] + donation_locations = [location for location in self.multiworld.get_locations() if + not location.event and 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)) @@ -745,7 +746,8 @@ class TestShipsanityEverything(SVTestBase): 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.multiworld.get_locations() if not location.event and LocationTags.SHIPSANITY in location_table[location.name].tags] + shipsanity_locations = [location for location in self.multiworld.get_locations() if + not location.event and 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): @@ -757,3 +759,15 @@ def test_all_shipsanity_locations_require_shipping_bin(self): self.assertTrue(can_reach_shipsanity_location) 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) + print(rule) + self.assertEqual(0, sum(1 for i in rule.rules if type(i) == HasProgressionPercent)) + self.assertIsNotNone(rule._has_progression_percent) From cf8ea7ee188688959be4e8fc22f5f77d5a8d1095 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 13:48:54 -0500 Subject: [PATCH 219/482] or has progression percent optimization --- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/stardew_rule.py | 138 ++++++++++++++++-- .../test/TestLogicSimplification.py | 10 ++ worlds/stardew_valley/test/TestOptions.py | 6 +- worlds/stardew_valley/test/TestRules.py | 2 +- .../test/performance/TestPerformance.py | 4 +- 6 files changed, 144 insertions(+), 18 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 9c4108f61f0b..75bcbeaa15a8 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -130,7 +130,7 @@ def set_bundle_rules(bundle_rooms: List[BundleRoom], logic: StardewLogic, multiw if bundle_room.name == CCRoom.abandoned_joja_mart: continue room_location = f"Complete {bundle_room.name}" - MultiWorldRules.add_rule(multiworld.get_location(room_location, player), And(*room_rules)) + MultiWorldRules.set_rule(multiworld.get_location(room_location, player), And(*room_rules)) def set_skills_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 49060567909d..b5cb132ecd59 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,7 +1,7 @@ from __future__ import annotations -from dataclasses import dataclass -from functools import reduce +from dataclasses import dataclass, field +from functools import reduce, cached_property from typing import Iterable, Dict, List, Union, FrozenSet, Optional, Sized from BaseClasses import CollectionState, ItemClassification @@ -10,6 +10,39 @@ MISSING_ITEM = "THIS ITEM IS MISSING" +@dataclass +class StardewRuleExplanation: + rule: StardewRule + state: CollectionState + sub_rules: Iterable[StardewRule] = field(default_factory=set) + + def summary(self, depth=0): + return "\t" * depth + f"{str(self.rule)} -> {self.result}" + + def __str__(self, depth=0): + if not self.sub_rules: + return self.summary(depth) + + return self.summary(depth) + "\n" + "\n".join(StardewRuleExplanation.__str__(i, depth + 1) + if i.result is False else i.summary(depth + 1) + for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) + + def __repr__(self, depth=0): + if not self.sub_rules: + return self.summary(depth) + + return self.summary(depth) + "\n" + "\n".join(StardewRuleExplanation.__repr__(i, depth + 1) + for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) + + @cached_property + def result(self): + return self.rule(self.state) + + @cached_property + def explained_sub_rules(self): + return [i.explain(self.state) for i in self.sub_rules] + + class StardewRule: def __call__(self, state: CollectionState) -> bool: raise NotImplementedError @@ -32,6 +65,9 @@ def get_difficulty(self): def simplify(self) -> StardewRule: return self + def explain(self, state: CollectionState) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state) + class True_(StardewRule): # noqa @@ -91,28 +127,49 @@ def get_difficulty(self): class Or(StardewRule): rules: FrozenSet[StardewRule] + _simplified: bool + _has_progression_percent: Optional[HasProgressionPercent] + _detailed_rules: FrozenSet[StardewRule] - def __init__(self, *rules: StardewRule): - self.rules = frozenset(rules) - assert self.rules, "Can't create a Or conditions without rules" + def __init__(self, *rules: StardewRule, _has_progression_percent=_default_has_progression_percent): self._simplified = False + if _has_progression_percent is _default_has_progression_percent: + assert rules, "Can't create a Or conditions without rules" + _has_progression_percent = HasProgressionPercent.reduce_or([i for i in rules if type(i) is HasProgressionPercent]) + if rules is not None: + rules = (i for i in rules if type(i) is not HasProgressionPercent) + + self.rules = frozenset(rules) + self._detailed_rules = self.rules + self._has_progression_percent = _has_progression_percent + def __call__(self, state: CollectionState) -> bool: self.simplify() return any(rule(state) for rule in self.rules) + def __str__(self): + prefix = str(self._has_progression_percent) + " | " if self._has_progression_percent else "" + return f"({prefix}{' | '.join(str(rule) for rule in self._detailed_rules)})" + def __repr__(self): - return f"({' | '.join(repr(rule) for rule in self.rules)})" + prefix = repr(self._has_progression_percent) + " | " if self._has_progression_percent else "" + return f"({prefix}{' | '.join(repr(rule) for rule in self._detailed_rules)})" def __or__(self, other): if other is true_ or other is false_: return other | self + if type(other) is HasProgressionPercent: + if self._has_progression_percent: + return Or(*self.rules, _has_progression_percent=self._has_progression_percent | other) + return Or(*self.rules, _has_progression_percent=other) + if type(other) is Or: - return Or(*self.rules.union(other.rules)) + return Or(*self.rules.union(other.rules), _has_progression_percent=self._has_progression_percent) - return Or(*self.rules.union({other})) + return Or(*self.rules.union({other}), _has_progression_percent=self._has_progression_percent) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -129,7 +186,9 @@ def simplify(self) -> StardewRule: if true_ in self.rules: return true_ - simplified_rules = [simplified for simplified in {rule.simplify() for rule in self.rules} + rules = self.rules.union({self._has_progression_percent}) if self._has_progression_percent else self.rules + simplified_rules = [simplified + for simplified in {rule.simplify() for rule in rules} if simplified is not false_] if not simplified_rules: @@ -142,11 +201,16 @@ def simplify(self) -> StardewRule: self._simplified = True return self + def explain(self, state: CollectionState) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, self._detailed_rules) + class And(StardewRule): rules: FrozenSet[StardewRule] + _simplified: bool _has_progression_percent: Optional[HasProgressionPercent] + _detailed_rules: FrozenSet[StardewRule] def __init__(self, *rules: StardewRule, _has_progression_percent=_default_has_progression_percent): self._simplified = False @@ -158,6 +222,7 @@ def __init__(self, *rules: StardewRule, _has_progression_percent=_default_has_pr rules = (i for i in rules if type(i) is not HasProgressionPercent) self.rules = frozenset(rules) + self._detailed_rules = self.rules self._has_progression_percent = _has_progression_percent def __call__(self, state: CollectionState) -> bool: @@ -165,9 +230,13 @@ def __call__(self, state: CollectionState) -> bool: result = all(rule(state) for rule in self.rules) return result + def __str__(self): + prefix = str(self._has_progression_percent) + " & " if self._has_progression_percent else "" + return f"({prefix}{' & '.join(str(rule) for rule in self._detailed_rules)})" + def __repr__(self): prefix = repr(self._has_progression_percent) + " & " if self._has_progression_percent else "" - return f"({prefix}{' & '.join(repr(rule) for rule in self.rules)})" + return f"({prefix}{' & '.join(repr(rule) for rule in self._detailed_rules)})" def __and__(self, other): if other is true_ or other is false_: @@ -213,6 +282,9 @@ def simplify(self) -> StardewRule: self._simplified = True return self + def explain(self, state: CollectionState) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, self._detailed_rules) + class Count(StardewRule): count: int @@ -264,6 +336,9 @@ def simplify(self): self._simplified = True return self + def explain(self, state: CollectionState) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, self.rules) + class TotalReceived(StardewRule): count: int @@ -301,6 +376,9 @@ def __repr__(self): def get_difficulty(self): return self.count + def explain(self, state: CollectionState) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, [Received(i, self.player, 1) for i in self.items]) + @dataclass(frozen=True) class Received(StardewRule): @@ -339,6 +417,26 @@ def __repr__(self): def get_difficulty(self): return 1 + def explain(self, state: CollectionState) -> StardewRuleExplanation: + # FIXME this should be in core + if self.resolution_hint == 'Location': + spot = state.multiworld.get_location(self.spot, self.player) + # TODO explain virtual reach for room + access_rule = spot.access_rule + elif self.resolution_hint == 'Entrance': + spot = state.multiworld.get_entrance(self.spot, self.player) + access_rule = spot.access_rule + else: + # default to Region + spot = state.multiworld.get_region(self.spot, self.player) + # TODO check entrances rules + access_rule = None + + if not isinstance(access_rule, StardewRule): + return StardewRuleExplanation(self, state) + + return StardewRuleExplanation(self, state, [access_rule]) + class Has(StardewRule): item: str @@ -353,6 +451,11 @@ def __call__(self, state: CollectionState) -> bool: self.simplify() return self.other_rules[self.item](state) + def __str__(self): + if self.item not in self.other_rules: + return f"Has {self.item} -> {MISSING_ITEM}" + return f"Has {self.item}" + def __repr__(self): if self.item not in self.other_rules: return f"Has {self.item} -> {MISSING_ITEM}" @@ -367,19 +470,32 @@ def __hash__(self): def simplify(self) -> StardewRule: return self.other_rules[self.item].simplify() + def explain(self, state: CollectionState) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, [self.other_rules[self.item]]) + @dataclass(frozen=True) class HasProgressionPercent(StardewRule): player: int percent: int + # Cache in __new__ + @staticmethod def reduce_and(rules: Union[Iterable[HasProgressionPercent], Sized]) -> Optional[HasProgressionPercent]: if not rules: return None if len(rules) == 1: return next(iter(rules)) - return reduce(HasProgressionPercent.__and__, (i for i in rules if type(rules) is HasProgressionPercent)) + return reduce(HasProgressionPercent.__and__, rules) # noqa + + @staticmethod + def reduce_or(rules: Union[Iterable[HasProgressionPercent], Sized]) -> Optional[HasProgressionPercent]: + if not rules: + return None + if len(rules) == 1: + return next(iter(rules)) + return reduce(HasProgressionPercent.__or__, rules) # noqa def __post_init__(self): assert self.percent > 0, "HasProgressionPercent rule must be above 0%" diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index b16a14e66b8a..c2f5d89fe4d8 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -77,3 +77,13 @@ def test_and_between_progression_percent_and_other_progression_percent_uses_max( for i, case in enumerate(cases): with self.subTest(f"{i} {repr(case)}"): self.assertEqual(case, And(HasProgressionPercent(1, 20))) + + def test_or_between_progression_percent_and_other_progression_percent_uses_max(self): + cases = [ + Or(HasProgressionPercent(1, 20)) | HasProgressionPercent(1, 10), + HasProgressionPercent(1, 20) | Or(HasProgressionPercent(1, 10)), + Or(HasProgressionPercent(1, 10)) | Or(HasProgressionPercent(1, 20)) + ] + for i, case in enumerate(cases): + with self.subTest(f"{i} {repr(case)}"): + self.assertEqual(case, Or(HasProgressionPercent(1, 20))) diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 02b580fb4299..6b65675c4df2 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -5,7 +5,7 @@ from BaseClasses import ItemClassification, MultiWorld from Options import NamedRange -from . import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_without_mods, allsanity_options_with_mods +from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods, allsanity_options_with_mods from .. import StardewItem, items_by_group, Group, StardewValleyWorld from ..locations import locations_by_tag, LocationTags, location_table from ..options import ExcludeGingerIsland, ToolProgression, Goal, SeasonRandomization, TrapItems, SpecialOrderLocations, ArcadeMachineLocations @@ -23,7 +23,7 @@ def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): multiworld.state.collect(item) victory = multiworld.find_item("Victory", 1) can_reach_victory = victory.can_reach(multiworld.state) - tester.assertTrue(can_reach_victory) + tester.assertTrue(can_reach_victory, victory.access_rule.explain(multiworld.state)) def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): @@ -188,7 +188,7 @@ def test_given_island_related_goal_then_override_exclude_ginger_island(self): with self.subTest(f"Goal: {goal}, {island_option.internal_name}: {value}"): multiworld = setup_solo_multiworld( {Goal.internal_name: Goal.options[goal], - island_option.internal_name: island_option.options[value]}) + island_option.internal_name: island_option.options[value]}) stardew_world: StardewValleyWorld = multiworld.worlds[self.player] self.assertEqual(stardew_world.options.exclude_ginger_island, island_option.option_false) basic_checks(self, multiworld) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 9a3708034101..b9a4b68f35a8 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -756,7 +756,7 @@ def test_all_shipsanity_locations_require_shipping_bin(self): self.multiworld.state.collect(bin_item, event=False) shipsanity_rule = self.world.logic.region.can_reach_location(location.name) can_reach_shipsanity_location = shipsanity_rule(self.multiworld.state) - self.assertTrue(can_reach_shipsanity_location) + self.assertTrue(can_reach_shipsanity_location, shipsanity_rule.explain(self.multiworld.state)) self.remove(bin_item) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 0daa7b54753e..0c643d02895a 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -31,8 +31,8 @@ def __repr__(self): stdev_time = stdev(self.results, mean_time) variance_time = variance(self.results, mean_time) - return f"""Generated {len(self.results)} {size} multiworlds in {total_time:.4f} seconds. Average {mean_time:.4f} seconds (Acceptable: {self.acceptable_mean:.2f}) -Mean: {mean_time:.4f} Median: {median_time:.4f} Stdeviation: {stdev_time:.4f} Variance: {variance_time:.4f} Deviation percent: {stdev_time / mean_time:.2%}""" + return f"""Generated {len(self.results)} {size} multiworlds in {total_time:.2f} seconds. Average {mean_time:.2f} seconds (Acceptable: {self.acceptable_mean:.2f}) +Mean: {mean_time:.2f} Median: {median_time:.2f} Stdeviation: {stdev_time:.2f} Variance: {variance_time:.4f} Deviation percent: {stdev_time / mean_time:.2%}""" class SVPerformanceTestCase(SVTestCase): From dfda898ff9c0b0d487d0e57be7c3c95a4a7bfbcc Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 25 Nov 2023 21:20:08 -0500 Subject: [PATCH 220/482] - Fixed magic bait, improve rule explanation string --- worlds/stardew_valley/data/bundle_data.py | 25 +++++++++++++++++-- worlds/stardew_valley/data/locations.csv | 14 ++++++----- worlds/stardew_valley/stardew_rule.py | 2 +- worlds/stardew_valley/strings/bundle_names.py | 2 ++ 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 4644f86201e3..79841195a843 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -4,6 +4,7 @@ from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.bundle_names import CCRoom, BundleName +from ..strings.craftable_names import Fishing from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro @@ -320,6 +321,20 @@ glacierfish = BundleItem(Fish.glacierfish) legend = BundleItem(Fish.legend) +spinner = BundleItem(Fishing.spinner) +dressed_spinner = BundleItem(Fishing.dressed_spinner) +trap_bobber = BundleItem(Fishing.trap_bobber) +cork_bobber = BundleItem(Fishing.cork_bobber) +lead_bobber = BundleItem(Fishing.lead_bobber) +treasure_hunter = BundleItem(Fishing.treasure_hunter) +barbed_hook = BundleItem(Fishing.barbed_hook) +curiosity_lure = BundleItem(Fishing.curiosity_lure) +quality_bobber = BundleItem(Fishing.quality_bobber) +bait = BundleItem(Fishing.bait, 100) +magnet = BundleItem(Fishing.magnet) +wild_bait = BundleItem(Fishing.wild_bait, 10) +magic_bait = IslandBundleItem(Fishing.magic_bait, 5) + ginger = IslandBundleItem(Forageable.ginger) magma_cap = IslandBundleItem(Forageable.magma_cap) @@ -527,12 +542,18 @@ island_fish_items = [lionfish, blue_discus, stingray] island_fish_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.island_fish, island_fish_items, 3, 3) +tackle_items = [spinner, dressed_spinner, trap_bobber, cork_bobber, lead_bobber, treasure_hunter, barbed_hook, curiosity_lure, quality_bobber] +tackle_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.tackle, tackle_items, 3, 2) + +bait_items = [bait, magnet, wild_bait, magic_bait] +bait_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.bait, bait_items, 2, 2) + fish_tank_bundles_vanilla = [river_fish_bundle_vanilla, lake_fish_bundle_vanilla, ocean_fish_bundle_vanilla, night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla] fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic, night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic] -fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, winter_fish_bundle, - recycling_bundle, rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle] +fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, winter_fish_bundle, recycling_bundle, + rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle, tackle_bundle, bait_bundle] # In Remixed, the trash items are in the recycling bundle, so we don't use the thematic version of the crab pot bundle that added trash items to it fish_tank_bundles_remixed.remove(crab_pot_bundle_thematic) fish_tank_bundles_remixed.append(crab_pot_bundle_vanilla) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3f4b1955b74a..d89a18845833 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -50,6 +50,7 @@ id,region,name,tags,mod_name 54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", @@ -60,12 +61,13 @@ id,region,name,tags,mod_name 65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -68,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -69,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -70,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -71,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -72,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -73,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 80,Vault,"500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index b5cb132ecd59..1f312fbac543 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -17,7 +17,7 @@ class StardewRuleExplanation: sub_rules: Iterable[StardewRule] = field(default_factory=set) def summary(self, depth=0): - return "\t" * depth + f"{str(self.rule)} -> {self.result}" + return " " * depth + f"{str(self.rule)} -> {self.result}" def __str__(self, depth=0): if not self.sub_rules: diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 6aa273eaf7a1..aaa7b57bf0d4 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -51,6 +51,8 @@ class BundleName: master_fisher = "Master Fisher's Bundle" legendary_fish = "Legendary Fish Bundle" island_fish = "Island Bundle" + tackle = "Tackle Bundle" + bait = "Master Baiter Bundle" blacksmith = "Blacksmith's Bundle" geologist = "Geologist's Bundle" adventurer = "Adventurer's Bundle" From eb98fe363fdf3487426ad31a88369e74eae26d35 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 25 Nov 2023 21:39:04 -0500 Subject: [PATCH 221/482] - Added demolition bundle --- worlds/stardew_valley/data/bundle_data.py | 14 +++++++++++--- worlds/stardew_valley/data/locations.csv | 1 + worlds/stardew_valley/strings/bundle_names.py | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 79841195a843..833639208849 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -4,7 +4,7 @@ from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.bundle_names import CCRoom, BundleName -from ..strings.craftable_names import Fishing +from ..strings.craftable_names import Fishing, Craftable, Bomb from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro @@ -247,6 +247,11 @@ solar_essence = BundleItem(Loot.solar_essence) void_essence = BundleItem(Loot.void_essence) +cherry_bomb = BundleItem(Bomb.cherry_bomb, 5) +bomb = BundleItem(Bomb.bomb, 2) +mega_bomb = BundleItem(Bomb.mega_bomb) +explosive_ammo = BundleItem(Craftable.explosive_ammo, 5) + maki_roll = BundleItem(Meal.maki_roll) fried_egg = BundleItem(Meal.fried_egg) omelet = BundleItem(Meal.omelet) @@ -585,9 +590,12 @@ engineer_items = [iridium_ore.as_amount(5), battery_pack, refined_quartz.as_amount(5), diamond] engineer_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.engineer, engineer_items, 3, 3) +demolition_items = [cherry_bomb, bomb, mega_bomb, explosive_ammo] +demolition_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.demolition, demolition_items, 3, 3) + boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla] boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic] -boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle] +boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle, demolition_bundle] boiler_room_vanilla = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_vanilla, 3) boiler_room_thematic = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_thematic, 3) boiler_room_remixed = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_remixed, 3) @@ -693,7 +701,7 @@ vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] vault_bundles_thematic = vault_bundles_vanilla -vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle] # , vault_carnival_bundle , vault_walnut_hunter_bundle +vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle, vault_carnival_bundle] # , vault_walnut_hunter_bundle vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles_vanilla, 4) vault_thematic = BundleRoomTemplate(CCRoom.vault, vault_bundles_thematic, 4) vault_remixed = BundleRoomTemplate(CCRoom.vault, vault_bundles_remixed, 4) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index d89a18845833..d9198cbace7e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -64,6 +64,7 @@ id,region,name,tags,mod_name 68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index aaa7b57bf0d4..4406bfcf610e 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -58,6 +58,7 @@ class BundleName: adventurer = "Adventurer's Bundle" treasure_hunter = "Treasure Hunter's Bundle" engineer = "Engineer's Bundle" + demolition = "Demolition Bundle" chef = "Chef's Bundle" dye = "Dye Bundle" field_research = "Field Research Bundle" From 2ff2a4c2151012568274e0c334337c11e5055162 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 26 Nov 2023 00:45:01 -0500 Subject: [PATCH 222/482] - Add shipping event so the indirect connections don't fuck me over --- worlds/stardew_valley/__init__.py | 17 +++++++++++++---- worlds/stardew_valley/items.py | 1 + worlds/stardew_valley/logic/money_logic.py | 7 ++++--- worlds/stardew_valley/logic/shipping_logic.py | 11 ++++------- .../stardew_valley/logic/special_order_logic.py | 7 ++++--- .../strings/ap_names/event_names.py | 1 + 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 9be73840d536..008f87725e5b 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -20,6 +20,7 @@ from .stardew_rule import True_, StardewRule, HasProgressionPercent from .strings.ap_names.event_names import Event from .strings.goal_names import Goal as GoalName +from .strings.region_names import Region as RegionName client_version = 0 @@ -140,8 +141,7 @@ def create_items(self): self.multiworld.itempool += created_items self.setup_early_items() - self.setup_construction_events() - self.setup_quest_events() + self.setup_player_events() self.setup_victory() def precollect_farm_type(self): @@ -188,14 +188,23 @@ def setup_early_items(self): if self.options.backpack_progression == BackpackProgression.option_early_progressive: self.multiworld.early_items[self.player]["Progressive Backpack"] = 1 + def setup_player_events(self): + self.setup_construction_events() + self.setup_quest_events() + self.setup_action_events() + def setup_construction_events(self): - can_construct_buildings = LocationData(None, "Carpenter Shop", Event.can_construct_buildings) + can_construct_buildings = LocationData(None, RegionName.carpenter, Event.can_construct_buildings) self.create_event_location(can_construct_buildings, True_(), Event.can_construct_buildings) def setup_quest_events(self): - start_dark_talisman_quest = LocationData(None, "Railroad", Event.start_dark_talisman_quest) + start_dark_talisman_quest = LocationData(None, RegionName.railroad, Event.start_dark_talisman_quest) self.create_event_location(start_dark_talisman_quest, self.logic.wallet.has_rusty_key, Event.start_dark_talisman_quest) + def setup_action_events(self): + can_ship_event = LocationData(None, RegionName.shipping, Event.can_ship_items) + self.create_event_location(can_ship_event, True_(), Event.can_ship_items) + def setup_victory(self): if self.options.goal == Goal.option_community_center: self.create_event_location(location_table[GoalName.community_center], diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 92430d3e336d..4809ef8fff8c 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -131,6 +131,7 @@ def load_item_csv(): ItemData(None, Event.victory, ItemClassification.progression), ItemData(None, Event.can_construct_buildings, ItemClassification.progression), ItemData(None, Event.start_dark_talisman_quest, ItemClassification.progression), + ItemData(None, Event.can_ship_items, ItemClassification.progression), ] all_items: List[ItemData] = load_item_csv() + events diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 146561f49193..9e27fd2038fb 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -10,6 +10,7 @@ from ..stardew_rule import StardewRule, True_, HasProgressionPercent, False_ from ..strings.currency_names import Currency from ..strings.region_names import Region +from ..strings.ap_names.event_names import Event qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", "25 Qi Gems", "20 Qi Gems", "10 Qi Gems", "15 Qi Gems", "15 Qi Gems", "15 Qi Gems") @@ -27,12 +28,12 @@ class MoneyLogic(BaseLogic[Union[RegionLogicMixin, MoneyLogicMixin, TimeLogicMix def can_have_earned_total(self, amount: int) -> StardewRule: if amount < 2000: return True_() - shipping_bin_rule = self.logic.region.can_reach(Region.shipping) + shipping_rule = self.logic.received(Event.can_ship_items) if amount < 10000: - return shipping_bin_rule + return shipping_rule percent_progression_items_needed = min(100, amount // 10000) - return shipping_bin_rule & HasProgressionPercent(self.player, percent_progression_items_needed) + return shipping_rule & HasProgressionPercent(self.player, percent_progression_items_needed) @cache_self1 def can_spend(self, amount: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index 6b5fbb1bbd96..b589388802a0 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -5,13 +5,14 @@ from .base_logic import BaseLogic, BaseLogicMixin from .building_logic import BuildingLogicMixin from .has_logic import HasLogicMixin +from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from ..locations import LocationTags, locations_by_tag from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, And from ..strings.building_names import Building -from ..strings.region_names import Region +from ..strings.ap_names.event_names import Event class ShippingLogicMixin(BaseLogicMixin): @@ -20,7 +21,7 @@ def __init__(self, *args, **kwargs): self.shipping = ShippingLogic(*args, **kwargs) -class ShippingLogic(BaseLogic[Union[ShippingLogicMixin, BuildingLogicMixin, RegionLogicMixin, HasLogicMixin]]): +class ShippingLogic(BaseLogic[Union[ReceivedLogicMixin, ShippingLogicMixin, BuildingLogicMixin, RegionLogicMixin, HasLogicMixin]]): @cached_property def can_use_shipping_bin(self) -> StardewRule: @@ -28,11 +29,7 @@ def can_use_shipping_bin(self) -> StardewRule: @cache_self1 def can_ship(self, item: str) -> StardewRule: - return self.logic.shipping.can_ship_items & self.logic.has(item) - - @cached_property - def can_ship_items(self) -> StardewRule: - return self.logic.region.can_reach(Region.shipping) + return self.logic.received(Event.can_ship_items) & self.logic.has(item) def can_ship_everything(self) -> StardewRule: shipsanity_prefix = "Shipsanity: " diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index e1558bbf3ee8..097424352801 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -20,6 +20,7 @@ from ..stardew_rule import StardewRule, Has from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.transport_names import Transportation +from ..strings.ap_names.event_names import Event from ..strings.artisan_good_names import ArtisanGood from ..strings.crop_names import Vegetable, Fruit from ..strings.fertilizer_names import Fertilizer @@ -61,7 +62,7 @@ def initialize_rules(self): SpecialOrder.gifts_for_george: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek), SpecialOrder.fragments_of_the_past: self.logic.region.can_reach(Region.dig_site) & self.logic.tool.has_tool(Tool.pickaxe), SpecialOrder.gus_famous_omelet: self.logic.has(AnimalProduct.any_egg), - SpecialOrder.crop_order: self.logic.ability.can_farm_perfectly() & self.logic.shipping.can_ship_items, + SpecialOrder.crop_order: self.logic.ability.can_farm_perfectly() & self.logic.received(Event.can_ship_items), SpecialOrder.community_cleanup: self.logic.skill.can_crab_pot, SpecialOrder.the_strong_stuff: self.logic.artisan.can_keg(Vegetable.potato), SpecialOrder.pierres_prime_produce: self.logic.ability.can_farm_perfectly(), @@ -77,12 +78,12 @@ def initialize_rules(self): SpecialOrder.prismatic_jelly: self.logic.region.can_reach(Region.wizard_tower), SpecialOrder.qis_crop: self.logic.ability.can_farm_perfectly() & self.logic.region.can_reach(Region.greenhouse) & self.logic.region.can_reach(Region.island_west) & self.logic.skill.has_total_level(50) & - self.logic.has(Machine.seed_maker) & self.logic.shipping.can_ship_items, + self.logic.has(Machine.seed_maker) & self.logic.received(Event.can_ship_items), SpecialOrder.lets_play_a_game: self.logic.arcade.has_junimo_kart_max_level(), SpecialOrder.four_precious_stones: self.logic.time.has_lived_max_months & self.logic.has("Prismatic Shard") & self.logic.ability.can_mine_perfectly_in_the_skull_cavern(), SpecialOrder.qis_hungry_challenge: self.logic.ability.can_mine_perfectly_in_the_skull_cavern() & self.logic.buff.has_max_buffs(), - SpecialOrder.qis_cuisine: self.logic.cooking.can_cook() & self.logic.shipping.can_ship_items & + SpecialOrder.qis_cuisine: self.logic.cooking.can_cook() & self.logic.received(Event.can_ship_items) & (self.logic.money.can_spend_at(Region.saloon, 205000) | self.logic.money.can_spend_at(Region.pierre_store, 170000)), SpecialOrder.qis_kindness: self.logic.relationship.can_give_loved_gifts_to_everyone(), SpecialOrder.extended_family: self.logic.ability.can_fish_perfectly() & self.logic.has(Fish.angler) & self.logic.has(Fish.glacierfish) & diff --git a/worlds/stardew_valley/strings/ap_names/event_names.py b/worlds/stardew_valley/strings/ap_names/event_names.py index 2d18ba5bee11..ec5ddd1477da 100644 --- a/worlds/stardew_valley/strings/ap_names/event_names.py +++ b/worlds/stardew_valley/strings/ap_names/event_names.py @@ -2,3 +2,4 @@ class Event: victory = "Victory" can_construct_buildings = "Can Construct Buildings" start_dark_talisman_quest = "Start Dark Talisman Quest" + can_ship_items = "Can Ship Items" From 0f4d7503f3f787472627ceaab675d6a2776afd32 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 14:33:27 -0500 Subject: [PATCH 223/482] cleanup --- worlds/stardew_valley/stardew_rule.py | 2 -- worlds/stardew_valley/test/performance/TestPerformance.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 1f312fbac543..03da4823b808 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -479,8 +479,6 @@ class HasProgressionPercent(StardewRule): player: int percent: int - # Cache in __new__ - @staticmethod def reduce_and(rules: Union[Iterable[HasProgressionPercent], Sized]) -> Optional[HasProgressionPercent]: if not rules: diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 0c643d02895a..549bfd94592c 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -78,7 +78,7 @@ def performance_test_multiworld(self, options): with self.subTest(f"Seed: {seed}"): time_before = time.time() - print(f"Starting world setup") + print("Starting world setup") multiworld = setup_multiworld(options, seed) if not self.skip_fill: distribute_items_restrictive(multiworld) From b9ab718bb4c7d919601fd151131d891fb01bbef6 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 16:10:54 -0500 Subject: [PATCH 224/482] generify combinable rules --- worlds/stardew_valley/requirements.txt | 3 +- worlds/stardew_valley/stardew_rule.py | 189 +++++++++++++++--------- worlds/stardew_valley/test/TestRules.py | 2 +- 3 files changed, 125 insertions(+), 69 deletions(-) diff --git a/worlds/stardew_valley/requirements.txt b/worlds/stardew_valley/requirements.txt index a7141f6aa805..6cebc566c00b 100644 --- a/worlds/stardew_valley/requirements.txt +++ b/worlds/stardew_valley/requirements.txt @@ -1 +1,2 @@ -importlib_resources; python_version <= '3.8' \ No newline at end of file +importlib_resources; python_version <= '3.8' +frozendict diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 03da4823b808..00f47abcb470 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,8 +1,11 @@ from __future__ import annotations +import abc from dataclasses import dataclass, field -from functools import reduce, cached_property -from typing import Iterable, Dict, List, Union, FrozenSet, Optional, Sized +from functools import cached_property +from typing import Iterable, Dict, List, Union, FrozenSet, Sized, Hashable, Callable + +from frozendict import frozendict from BaseClasses import CollectionState, ItemClassification from .items import item_table @@ -43,7 +46,9 @@ def explained_sub_rules(self): return [i.explain(self.state) for i in self.sub_rules] -class StardewRule: +class StardewRule(abc.ABC): + + @abc.abstractmethod def __call__(self, state: CollectionState) -> bool: raise NotImplementedError @@ -59,6 +64,7 @@ def __and__(self, other) -> StardewRule: return And(self, other) + @abc.abstractmethod def get_difficulty(self): raise NotImplementedError @@ -122,54 +128,125 @@ def get_difficulty(self): assert false_ is False_() assert true_ is True_() -_default_has_progression_percent = object() +_default_combinable_rules = object() + + +class CombinableStardewRule(StardewRule, abc.ABC): + + @property + @abc.abstractmethod + def combination_key(self) -> Hashable: + raise NotImplementedError + + @property + @abc.abstractmethod + def value(self): + raise NotImplementedError + + def is_same_rule(self, other: CombinableStardewRule): + return self.combination_key == other.combination_key + + @staticmethod + def reduce_and(rules: Union[Iterable[CombinableStardewRule], Sized]) -> frozendict[Hashable, CombinableStardewRule]: + return CombinableStardewRule.reduce(rules, CombinableStardewRule.combine_and) + + @staticmethod + def reduce_or(rules: Union[Iterable[CombinableStardewRule], Sized]) -> frozendict[Hashable, CombinableStardewRule]: + return CombinableStardewRule.reduce(rules, CombinableStardewRule.combine_or) + + @staticmethod + def reduce(rules: Union[Iterable[CombinableStardewRule], Sized], + reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ + -> frozendict[Hashable, CombinableStardewRule]: + if not rules: + return frozendict() + + reduced_rules = {} + for rule in rules: + key = rule.combination_key + if key not in reduced_rules: + reduced_rules[key] = rule + continue + + reduced_rules[key] = reducer(reduced_rules[key], rule) + + return frozendict(reduced_rules) + + def add_into_and(self, rules: frozendict[Hashable, CombinableStardewRule]) -> frozendict[Hashable, CombinableStardewRule]: + return self.add_into(rules, CombinableStardewRule.combine_and) + + def add_into_or(self, rules: frozendict[Hashable, CombinableStardewRule]) -> frozendict[Hashable, CombinableStardewRule]: + return self.add_into(rules, CombinableStardewRule.combine_or) + + def add_into(self, rules: frozendict[Hashable, CombinableStardewRule], + reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ + -> frozendict[Hashable, CombinableStardewRule]: + if self.combination_key not in rules: + return rules | {self.combination_key: self} + + other = rules[self.combination_key] + return rules | {self.combination_key: reducer(self, other)} + + @staticmethod + def combine_and(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: + return max(left, right, key=lambda x: x.value) + + @staticmethod + def combine_or(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: + return min(left, right, key=lambda x: x.value) + + def __and__(self, other): + if isinstance(other, CombinableStardewRule) and self.is_same_rule(other): + return CombinableStardewRule.combine_and(self, other) + return super().__and__(other) + + def __or__(self, other): + if isinstance(other, CombinableStardewRule) and self.is_same_rule(other): + return CombinableStardewRule.combine_or(self, other) + return super().__or__(other) class Or(StardewRule): rules: FrozenSet[StardewRule] _simplified: bool - _has_progression_percent: Optional[HasProgressionPercent] + _combinable_rules: frozendict[Hashable, CombinableStardewRule] _detailed_rules: FrozenSet[StardewRule] - def __init__(self, *rules: StardewRule, _has_progression_percent=_default_has_progression_percent): + def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): self._simplified = False - if _has_progression_percent is _default_has_progression_percent: + if _combinable_rules is _default_combinable_rules: assert rules, "Can't create a Or conditions without rules" - _has_progression_percent = HasProgressionPercent.reduce_or([i for i in rules if type(i) is HasProgressionPercent]) + _combinable_rules = CombinableStardewRule.reduce_or([i for i in rules if isinstance(i, CombinableStardewRule)]) if rules is not None: - rules = (i for i in rules if type(i) is not HasProgressionPercent) + rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) self.rules = frozenset(rules) self._detailed_rules = self.rules - self._has_progression_percent = _has_progression_percent + self._combinable_rules = _combinable_rules def __call__(self, state: CollectionState) -> bool: self.simplify() return any(rule(state) for rule in self.rules) def __str__(self): - prefix = str(self._has_progression_percent) + " | " if self._has_progression_percent else "" - return f"({prefix}{' | '.join(str(rule) for rule in self._detailed_rules)})" + return f"({' | '.join(str(rule) for rule in self._detailed_rules.union(self._combinable_rules.values()))})" def __repr__(self): - prefix = repr(self._has_progression_percent) + " | " if self._has_progression_percent else "" - return f"({prefix}{' | '.join(repr(rule) for rule in self._detailed_rules)})" + return f"({' | '.join(repr(rule) for rule in self._detailed_rules.union(self._combinable_rules.values()))})" def __or__(self, other): if other is true_ or other is false_: return other | self - if type(other) is HasProgressionPercent: - if self._has_progression_percent: - return Or(*self.rules, _has_progression_percent=self._has_progression_percent | other) - return Or(*self.rules, _has_progression_percent=other) + if isinstance(other, CombinableStardewRule): + return Or(*self.rules, _combinable_rules=other.add_into_or(self._combinable_rules)) if type(other) is Or: - return Or(*self.rules.union(other.rules), _has_progression_percent=self._has_progression_percent) + return Or(*self.rules.union(other.rules), _combinable_rules=self._combinable_rules) - return Or(*self.rules.union({other}), _has_progression_percent=self._has_progression_percent) + return Or(*self.rules.union({other}), _combinable_rules=self._combinable_rules) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -186,7 +263,7 @@ def simplify(self) -> StardewRule: if true_ in self.rules: return true_ - rules = self.rules.union({self._has_progression_percent}) if self._has_progression_percent else self.rules + rules = self.rules.union(self._combinable_rules.values()) if self._combinable_rules else self.rules simplified_rules = [simplified for simplified in {rule.simplify() for rule in rules} if simplified is not false_] @@ -209,48 +286,46 @@ class And(StardewRule): rules: FrozenSet[StardewRule] _simplified: bool - _has_progression_percent: Optional[HasProgressionPercent] + _combinable_rules: frozendict[Hashable, CombinableStardewRule] _detailed_rules: FrozenSet[StardewRule] - def __init__(self, *rules: StardewRule, _has_progression_percent=_default_has_progression_percent): + def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): self._simplified = False - if _has_progression_percent is _default_has_progression_percent: + if _combinable_rules is _default_combinable_rules: assert rules, "Can't create a And conditions without rules" - _has_progression_percent = HasProgressionPercent.reduce_and([i for i in rules if type(i) is HasProgressionPercent]) + _combinable_rules = CombinableStardewRule.reduce_and([i for i in rules if isinstance(i, CombinableStardewRule)]) + # TODO is this needed? if rules is not None: - rules = (i for i in rules if type(i) is not HasProgressionPercent) + rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) self.rules = frozenset(rules) self._detailed_rules = self.rules - self._has_progression_percent = _has_progression_percent + self._combinable_rules = _combinable_rules def __call__(self, state: CollectionState) -> bool: self.simplify() - result = all(rule(state) for rule in self.rules) - return result + return all(rule(state) for rule in self.rules) def __str__(self): - prefix = str(self._has_progression_percent) + " & " if self._has_progression_percent else "" + prefix = str(self._combinable_rules) + " & " if self._combinable_rules else "" return f"({prefix}{' & '.join(str(rule) for rule in self._detailed_rules)})" def __repr__(self): - prefix = repr(self._has_progression_percent) + " & " if self._has_progression_percent else "" + prefix = repr(self._combinable_rules) + " & " if self._combinable_rules else "" return f"({prefix}{' & '.join(repr(rule) for rule in self._detailed_rules)})" def __and__(self, other): if other is true_ or other is false_: return other & self - if type(other) is HasProgressionPercent: - if self._has_progression_percent: - return And(*self.rules, _has_progression_percent=self._has_progression_percent & other) - return And(*self.rules, _has_progression_percent=other) + if isinstance(other, CombinableStardewRule): + return And(*self.rules, _combinable_rules=other.add_into_and(self._combinable_rules)) if type(other) is And: - return And(*self.rules.union(other.rules), _has_progression_percent=self._has_progression_percent) + return And(*self.rules.union(other.rules), _combinable_rules=self._combinable_rules) - return And(*self.rules.union({other}), _has_progression_percent=self._has_progression_percent) + return And(*self.rules.union({other}), _combinable_rules=self._combinable_rules) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -267,7 +342,7 @@ def simplify(self) -> StardewRule: if false_ in self.rules: return false_ - rules = self.rules.union({self._has_progression_percent}) if self._has_progression_percent else self.rules + rules = self.rules.union(self._combinable_rules.values()) if self._combinable_rules else self.rules simplified_rules = [simplified for simplified in {rule.simplify() for rule in rules} if simplified is not true_] @@ -427,8 +502,6 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: spot = state.multiworld.get_entrance(self.spot, self.player) access_rule = spot.access_rule else: - # default to Region - spot = state.multiworld.get_region(self.spot, self.player) # TODO check entrances rules access_rule = None @@ -475,30 +548,22 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: @dataclass(frozen=True) -class HasProgressionPercent(StardewRule): +class HasProgressionPercent(CombinableStardewRule): player: int percent: int - @staticmethod - def reduce_and(rules: Union[Iterable[HasProgressionPercent], Sized]) -> Optional[HasProgressionPercent]: - if not rules: - return None - if len(rules) == 1: - return next(iter(rules)) - return reduce(HasProgressionPercent.__and__, rules) # noqa - - @staticmethod - def reduce_or(rules: Union[Iterable[HasProgressionPercent], Sized]) -> Optional[HasProgressionPercent]: - if not rules: - return None - if len(rules) == 1: - return next(iter(rules)) - return reduce(HasProgressionPercent.__or__, rules) # noqa - def __post_init__(self): assert self.percent > 0, "HasProgressionPercent rule must be above 0%" assert self.percent <= 100, "HasProgressionPercent rule can't require more than 100% of items" + @property + def combination_key(self) -> Hashable: + return HasProgressionPercent.__name__ + + @property + def value(self): + return self.percent + def __call__(self, state: CollectionState) -> bool: stardew_world = state.multiworld.worlds[self.player] total_count = stardew_world.total_progression_items @@ -514,15 +579,5 @@ def __call__(self, state: CollectionState) -> bool: def __repr__(self): return f"HasProgressionPercent {self.percent}" - def __and__(self, other): - if type(other) is HasProgressionPercent: - return max(self, other, key=lambda x: x.percent) - return super().__and__(other) - - def __or__(self, other): - if type(other) is HasProgressionPercent: - return min(self, other, key=lambda x: x.percent) - return super().__or__(other) - def get_difficulty(self): return self.percent diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index b9a4b68f35a8..dcf1d23d1e18 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -770,4 +770,4 @@ def test_skill_logic_has_level_only_uses_one_has_progression_percent(self): rule = self.multiworld.worlds[1].logic.skill.has_level("Farming", 8) print(rule) self.assertEqual(0, sum(1 for i in rule.rules if type(i) == HasProgressionPercent)) - self.assertIsNotNone(rule._has_progression_percent) + self.assertIsNotNone(rule._combinable_rules) From 93aaee188ce608d1b4dddb5451ad64d5a57d9a75 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 17:45:31 -0500 Subject: [PATCH 225/482] fix or and combining of rules --- worlds/stardew_valley/stardew_rule.py | 123 ++++++++++++------ .../test/TestLogicSimplification.py | 8 +- worlds/stardew_valley/test/TestRules.py | 21 +-- 3 files changed, 97 insertions(+), 55 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 00f47abcb470..99956c21bf1e 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -172,6 +172,17 @@ def reduce(rules: Union[Iterable[CombinableStardewRule], Sized], return frozendict(reduced_rules) + @staticmethod + def merge_and(left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ + -> frozendict[ + Hashable, CombinableStardewRule]: + return CombinableStardewRule.reduce({*left.values(), *right.values()}, CombinableStardewRule.combine_and) + + @staticmethod + def merge_or(left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ + -> frozendict[Hashable, CombinableStardewRule]: + return CombinableStardewRule.reduce({*left.values(), *right.values()}, CombinableStardewRule.combine_or) + def add_into_and(self, rules: frozendict[Hashable, CombinableStardewRule]) -> frozendict[Hashable, CombinableStardewRule]: return self.add_into(rules, CombinableStardewRule.combine_and) @@ -207,14 +218,17 @@ def __or__(self, other): class Or(StardewRule): - rules: FrozenSet[StardewRule] + combinable_rules: frozendict[Hashable, CombinableStardewRule] + unique_rules: FrozenSet[StardewRule] + + detailed_rules: FrozenSet[StardewRule] _simplified: bool - _combinable_rules: frozendict[Hashable, CombinableStardewRule] - _detailed_rules: FrozenSet[StardewRule] + _combined_rules: FrozenSet[StardewRule] def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): self._simplified = False + self._combined_rules = frozenset() if _combinable_rules is _default_combinable_rules: assert rules, "Can't create a Or conditions without rules" @@ -222,31 +236,39 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru if rules is not None: rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) - self.rules = frozenset(rules) - self._detailed_rules = self.rules - self._combinable_rules = _combinable_rules + self.unique_rules = frozenset(rules) + self.combinable_rules = _combinable_rules + + self.detailed_rules = self.rules + + @property + def rules(self): + if not self._combined_rules: + self._combined_rules = self.unique_rules.union(self.combinable_rules.values()) + return self._combined_rules def __call__(self, state: CollectionState) -> bool: self.simplify() return any(rule(state) for rule in self.rules) def __str__(self): - return f"({' | '.join(str(rule) for rule in self._detailed_rules.union(self._combinable_rules.values()))})" + return f"({' | '.join(str(rule) for rule in self.rules)})" def __repr__(self): - return f"({' | '.join(repr(rule) for rule in self._detailed_rules.union(self._combinable_rules.values()))})" + return f"({' | '.join(repr(rule) for rule in self.rules)})" def __or__(self, other): if other is true_ or other is false_: return other | self if isinstance(other, CombinableStardewRule): - return Or(*self.rules, _combinable_rules=other.add_into_or(self._combinable_rules)) + return Or(*self.unique_rules, _combinable_rules=other.add_into_or(self.combinable_rules)) if type(other) is Or: - return Or(*self.rules.union(other.rules), _combinable_rules=self._combinable_rules) + return Or(*self.unique_rules.union(other.unique_rules), + _combinable_rules=CombinableStardewRule.merge_or(self.combinable_rules, other.combinable_rules)) - return Or(*self.rules.union({other}), _combinable_rules=self._combinable_rules) + return Or(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -260,37 +282,41 @@ def get_difficulty(self): def simplify(self) -> StardewRule: if self._simplified: return self - if true_ in self.rules: + if true_ in self.unique_rules: + self._combined_rules = frozenset({true_}) return true_ - rules = self.rules.union(self._combinable_rules.values()) if self._combinable_rules else self.rules - simplified_rules = [simplified - for simplified in {rule.simplify() for rule in rules} - if simplified is not false_] + simplified_rules = frozenset(simplified + for simplified in {rule.simplify() for rule in self.rules} + if simplified is not false_) if not simplified_rules: + self._combined_rules = frozenset({false_}) return false_ if len(simplified_rules) == 1: - return simplified_rules[0] + return next(iter(simplified_rules)) - self.rules = frozenset(simplified_rules) + self._combined_rules = frozenset(simplified_rules) self._simplified = True return self def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, self._detailed_rules) + return StardewRuleExplanation(self, state, self.detailed_rules) class And(StardewRule): - rules: FrozenSet[StardewRule] + combinable_rules: frozendict[Hashable, CombinableStardewRule] + unique_rules: FrozenSet[StardewRule] + + detailed_rules: FrozenSet[StardewRule] _simplified: bool - _combinable_rules: frozendict[Hashable, CombinableStardewRule] - _detailed_rules: FrozenSet[StardewRule] + _combined_rules: FrozenSet[StardewRule] def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): self._simplified = False + self._combined_rules = frozenset() if _combinable_rules is _default_combinable_rules: assert rules, "Can't create a And conditions without rules" @@ -299,33 +325,39 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru if rules is not None: rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) - self.rules = frozenset(rules) - self._detailed_rules = self.rules - self._combinable_rules = _combinable_rules + self.unique_rules = frozenset(rules) + self.combinable_rules = _combinable_rules + + self.detailed_rules = self.rules + + @property + def rules(self): + if not self._combined_rules: + self._combined_rules = self.unique_rules.union(self.combinable_rules.values()) + return self._combined_rules def __call__(self, state: CollectionState) -> bool: self.simplify() return all(rule(state) for rule in self.rules) def __str__(self): - prefix = str(self._combinable_rules) + " & " if self._combinable_rules else "" - return f"({prefix}{' & '.join(str(rule) for rule in self._detailed_rules)})" + return f"({' & '.join(str(rule) for rule in self.rules)})" def __repr__(self): - prefix = repr(self._combinable_rules) + " & " if self._combinable_rules else "" - return f"({prefix}{' & '.join(repr(rule) for rule in self._detailed_rules)})" + return f"({' & '.join(repr(rule) for rule in self.rules)})" def __and__(self, other): if other is true_ or other is false_: return other & self if isinstance(other, CombinableStardewRule): - return And(*self.rules, _combinable_rules=other.add_into_and(self._combinable_rules)) + return And(*self.unique_rules, _combinable_rules=other.add_into_and(self.combinable_rules)) if type(other) is And: - return And(*self.rules.union(other.rules), _combinable_rules=self._combinable_rules) + return And(*self.unique_rules.union(other.unique_rules), + _combinable_rules=CombinableStardewRule.merge_and(self.combinable_rules, other.combinable_rules)) - return And(*self.rules.union({other}), _combinable_rules=self._combinable_rules) + return And(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -339,26 +371,27 @@ def get_difficulty(self): def simplify(self) -> StardewRule: if self._simplified: return self - if false_ in self.rules: + if false_ in self.unique_rules: + self._combined_rules = frozenset({false_}) return false_ - rules = self.rules.union(self._combinable_rules.values()) if self._combinable_rules else self.rules - simplified_rules = [simplified - for simplified in {rule.simplify() for rule in rules} - if simplified is not true_] + simplified_rules = frozenset(simplified + for simplified in {rule.simplify() for rule in self.rules} + if simplified is not true_) if not simplified_rules: + self._combined_rules = frozenset({true_}) return true_ if len(simplified_rules) == 1: - return simplified_rules[0] + return next(iter(simplified_rules)) - self.rules = frozenset(simplified_rules) + self._combined_rules = frozenset(simplified_rules) self._simplified = True return self def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, self._detailed_rules) + return StardewRuleExplanation(self, state, self.rules) class Count(StardewRule): @@ -456,7 +489,7 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: @dataclass(frozen=True) -class Received(StardewRule): +class Received(CombinableStardewRule): item: str player: int count: int @@ -473,6 +506,14 @@ def __repr__(self): return f"Received {self.item}" return f"Received {self.count} {self.item}" + @property + def combination_key(self) -> Hashable: + return self.item + + @property + def value(self): + return self.count + def get_difficulty(self): return self.count diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index c2f5d89fe4d8..0b999cc254da 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -80,10 +80,10 @@ def test_and_between_progression_percent_and_other_progression_percent_uses_max( def test_or_between_progression_percent_and_other_progression_percent_uses_max(self): cases = [ - Or(HasProgressionPercent(1, 20)) | HasProgressionPercent(1, 10), - HasProgressionPercent(1, 20) | Or(HasProgressionPercent(1, 10)), - Or(HasProgressionPercent(1, 10)) | Or(HasProgressionPercent(1, 20)) + Or(HasProgressionPercent(1, 10)) | HasProgressionPercent(1, 20), + HasProgressionPercent(1, 10) | Or(HasProgressionPercent(1, 20)), + Or(HasProgressionPercent(1, 20)) | Or(HasProgressionPercent(1, 10)) ] for i, case in enumerate(cases): with self.subTest(f"{i} {repr(case)}"): - self.assertEqual(case, Or(HasProgressionPercent(1, 20))) + self.assertEqual(case, Or(HasProgressionPercent(1, 10))) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index dcf1d23d1e18..8bccc7da6de7 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -20,7 +20,7 @@ def test_sturgeon(self): self.multiworld.state.prog_items = {1: Counter()} sturgeon_rule = self.world.logic.has("Sturgeon") - self.assertFalse(sturgeon_rule(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state)) summer = self.world.create_item("Summer") self.multiworld.state.collect(summer, event=False) @@ -60,34 +60,35 @@ def test_old_master_cannoli(self): self.multiworld.state.collect(self.world.create_item("Summer"), event=False) self.collect_lots_of_money() - self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + rule = self.world.logic.region.can_reach_location("Old Master Cannoli") + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state)) fall = self.world.create_item("Fall") self.multiworld.state.collect(fall, event=False) - self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state)) tuesday = self.world.create_item("Traveling Merchant: Tuesday") self.multiworld.state.collect(tuesday, event=False) - self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state)) rare_seed = self.world.create_item("Rare Seed") self.multiworld.state.collect(rare_seed, event=False) - self.assertTrue(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertTrue(rule(self.multiworld.state)) self.remove(fall) - self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state)) self.remove(tuesday) green_house = self.world.create_item("Greenhouse") self.multiworld.state.collect(green_house, event=False) - self.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(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.assertFalse(self.world.logic.region.can_reach_location("Old Master Cannoli")(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state)) self.remove(friday) @@ -769,5 +770,5 @@ class TestVanillaSkillLogicSimplification(SVTestBase): def test_skill_logic_has_level_only_uses_one_has_progression_percent(self): rule = self.multiworld.worlds[1].logic.skill.has_level("Farming", 8) print(rule) - self.assertEqual(0, sum(1 for i in rule.rules if type(i) == HasProgressionPercent)) - self.assertIsNotNone(rule._combinable_rules) + self.assertEqual(1, sum(1 for i in rule.rules if type(i) == HasProgressionPercent)) + self.assertIsNotNone(rule.combinable_rules) From 97987a2ce207cda8845c82e639f77d0a00a18e2b Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 19:12:15 -0500 Subject: [PATCH 226/482] eliminate duplication between Or and And --- worlds/stardew_valley/stardew_rule.py | 210 +++++++++----------------- 1 file changed, 75 insertions(+), 135 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 99956c21bf1e..a45db3bea0ea 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,6 +1,6 @@ from __future__ import annotations -import abc +from abc import ABC, abstractmethod from dataclasses import dataclass, field from functools import cached_property from typing import Iterable, Dict, List, Union, FrozenSet, Sized, Hashable, Callable @@ -46,9 +46,9 @@ def explained_sub_rules(self): return [i.explain(self.state) for i in self.sub_rules] -class StardewRule(abc.ABC): +class StardewRule(ABC): - @abc.abstractmethod + @abstractmethod def __call__(self, state: CollectionState) -> bool: raise NotImplementedError @@ -64,7 +64,7 @@ def __and__(self, other) -> StardewRule: return And(self, other) - @abc.abstractmethod + @abstractmethod def get_difficulty(self): raise NotImplementedError @@ -75,7 +75,11 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: return StardewRuleExplanation(self, state) -class True_(StardewRule): # noqa +class LiteralStardewRule(StardewRule, ABC): + pass + + +class True_(LiteralStardewRule): # noqa def __new__(cls, _cache=[]): # noqa # Only one single instance will be ever created. @@ -99,7 +103,7 @@ def get_difficulty(self): return 0 -class False_(StardewRule): # noqa +class False_(LiteralStardewRule): # noqa def __new__(cls, _cache=[]): # noqa # Only one single instance will be ever created. @@ -131,29 +135,21 @@ def get_difficulty(self): _default_combinable_rules = object() -class CombinableStardewRule(StardewRule, abc.ABC): +class CombinableStardewRule(StardewRule, ABC): @property - @abc.abstractmethod + @abstractmethod def combination_key(self) -> Hashable: raise NotImplementedError @property - @abc.abstractmethod + @abstractmethod def value(self): raise NotImplementedError def is_same_rule(self, other: CombinableStardewRule): return self.combination_key == other.combination_key - @staticmethod - def reduce_and(rules: Union[Iterable[CombinableStardewRule], Sized]) -> frozendict[Hashable, CombinableStardewRule]: - return CombinableStardewRule.reduce(rules, CombinableStardewRule.combine_and) - - @staticmethod - def reduce_or(rules: Union[Iterable[CombinableStardewRule], Sized]) -> frozendict[Hashable, CombinableStardewRule]: - return CombinableStardewRule.reduce(rules, CombinableStardewRule.combine_or) - @staticmethod def reduce(rules: Union[Iterable[CombinableStardewRule], Sized], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ @@ -173,21 +169,11 @@ def reduce(rules: Union[Iterable[CombinableStardewRule], Sized], return frozendict(reduced_rules) @staticmethod - def merge_and(left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ - -> frozendict[ - Hashable, CombinableStardewRule]: - return CombinableStardewRule.reduce({*left.values(), *right.values()}, CombinableStardewRule.combine_and) - - @staticmethod - def merge_or(left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ + def merge(left: frozendict[Hashable, CombinableStardewRule], + right: frozendict[Hashable, CombinableStardewRule], + reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> frozendict[Hashable, CombinableStardewRule]: - return CombinableStardewRule.reduce({*left.values(), *right.values()}, CombinableStardewRule.combine_or) - - def add_into_and(self, rules: frozendict[Hashable, CombinableStardewRule]) -> frozendict[Hashable, CombinableStardewRule]: - return self.add_into(rules, CombinableStardewRule.combine_and) - - def add_into_or(self, rules: frozendict[Hashable, CombinableStardewRule]) -> frozendict[Hashable, CombinableStardewRule]: - return self.add_into(rules, CombinableStardewRule.combine_or) + return CombinableStardewRule.reduce({*left.values(), *right.values()}, reducer) def add_into(self, rules: frozendict[Hashable, CombinableStardewRule], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ @@ -198,26 +184,23 @@ def add_into(self, rules: frozendict[Hashable, CombinableStardewRule], other = rules[self.combination_key] return rules | {self.combination_key: reducer(self, other)} - @staticmethod - def combine_and(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: - return max(left, right, key=lambda x: x.value) - - @staticmethod - def combine_or(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: - return min(left, right, key=lambda x: x.value) - def __and__(self, other): if isinstance(other, CombinableStardewRule) and self.is_same_rule(other): - return CombinableStardewRule.combine_and(self, other) + return And.combine(self, other) return super().__and__(other) def __or__(self, other): if isinstance(other, CombinableStardewRule) and self.is_same_rule(other): - return CombinableStardewRule.combine_or(self, other) + return Or.combine(self, other) return super().__or__(other) -class Or(StardewRule): +class AggregatingStardewRule(StardewRule, ABC): + identity: LiteralStardewRule + complement: LiteralStardewRule + symbol: str + name: str + combinable_rules: frozendict[Hashable, CombinableStardewRule] unique_rules: FrozenSet[StardewRule] @@ -231,44 +214,31 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru self._combined_rules = frozenset() if _combinable_rules is _default_combinable_rules: - assert rules, "Can't create a Or conditions without rules" - _combinable_rules = CombinableStardewRule.reduce_or([i for i in rules if isinstance(i, CombinableStardewRule)]) - if rules is not None: - rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) + assert rules, f"Can't create a {self.name} conditions without rules" + _combinable_rules = CombinableStardewRule.reduce([i for i in rules if isinstance(i, CombinableStardewRule)], self.combine) + rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) self.unique_rules = frozenset(rules) self.combinable_rules = _combinable_rules self.detailed_rules = self.rules + @staticmethod + @abstractmethod + def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: + raise NotImplementedError + @property def rules(self): if not self._combined_rules: self._combined_rules = self.unique_rules.union(self.combinable_rules.values()) return self._combined_rules - def __call__(self, state: CollectionState) -> bool: - self.simplify() - return any(rule(state) for rule in self.rules) - def __str__(self): - return f"({' | '.join(str(rule) for rule in self.rules)})" + return f"({self.symbol.join(str(rule) for rule in self.rules)})" def __repr__(self): - return f"({' | '.join(repr(rule) for rule in self.rules)})" - - def __or__(self, other): - if other is true_ or other is false_: - return other | self - - if isinstance(other, CombinableStardewRule): - return Or(*self.unique_rules, _combinable_rules=other.add_into_or(self.combinable_rules)) - - if type(other) is Or: - return Or(*self.unique_rules.union(other.unique_rules), - _combinable_rules=CombinableStardewRule.merge_or(self.combinable_rules, other.combinable_rules)) - - return Or(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) + return f"({self.symbol.join(repr(rule) for rule in self.rules)})" def __eq__(self, other): return isinstance(other, self.__class__) and other.rules == self.rules @@ -276,23 +246,20 @@ def __eq__(self, other): def __hash__(self): return hash(self.rules) - def get_difficulty(self): - return min(rule.get_difficulty() for rule in self.rules) - def simplify(self) -> StardewRule: if self._simplified: return self - if true_ in self.unique_rules: - self._combined_rules = frozenset({true_}) - return true_ + if self.complement in self.unique_rules: + self._combined_rules = frozenset({self.complement}) + return self.complement simplified_rules = frozenset(simplified for simplified in {rule.simplify() for rule in self.rules} - if simplified is not false_) + if simplified is not self.identity) if not simplified_rules: - self._combined_rules = frozenset({false_}) - return false_ + self._combined_rules = frozenset({self.identity}) + return self.identity if len(simplified_rules) == 1: return next(iter(simplified_rules)) @@ -305,94 +272,67 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, self.detailed_rules) -class And(StardewRule): - combinable_rules: frozendict[Hashable, CombinableStardewRule] - unique_rules: FrozenSet[StardewRule] +class Or(AggregatingStardewRule): + identity = false_ + complement = true_ + symbol = " | " + name = "Or" - detailed_rules: FrozenSet[StardewRule] + def __call__(self, state: CollectionState) -> bool: + self.simplify() + return any(rule(state) for rule in self.rules) - _simplified: bool - _combined_rules: FrozenSet[StardewRule] + def __or__(self, other): + if other is true_ or other is false_: + return other | self - def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): - self._simplified = False - self._combined_rules = frozenset() + if isinstance(other, CombinableStardewRule): + return Or(*self.unique_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) - if _combinable_rules is _default_combinable_rules: - assert rules, "Can't create a And conditions without rules" - _combinable_rules = CombinableStardewRule.reduce_and([i for i in rules if isinstance(i, CombinableStardewRule)]) - # TODO is this needed? - if rules is not None: - rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) + if type(other) is Or: + return Or(*self.unique_rules.union(other.unique_rules), + _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) - self.unique_rules = frozenset(rules) - self.combinable_rules = _combinable_rules + return Or(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) - self.detailed_rules = self.rules + @staticmethod + def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: + return min(left, right, key=lambda x: x.value) + + def get_difficulty(self): + return min(rule.get_difficulty() for rule in self.rules) - @property - def rules(self): - if not self._combined_rules: - self._combined_rules = self.unique_rules.union(self.combinable_rules.values()) - return self._combined_rules + +class And(AggregatingStardewRule): + identity = true_ + complement = false_ + symbol = " & " + name = "And" def __call__(self, state: CollectionState) -> bool: self.simplify() return all(rule(state) for rule in self.rules) - def __str__(self): - return f"({' & '.join(str(rule) for rule in self.rules)})" - - def __repr__(self): - return f"({' & '.join(repr(rule) for rule in self.rules)})" - def __and__(self, other): if other is true_ or other is false_: return other & self if isinstance(other, CombinableStardewRule): - return And(*self.unique_rules, _combinable_rules=other.add_into_and(self.combinable_rules)) + return And(*self.unique_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) if type(other) is And: return And(*self.unique_rules.union(other.unique_rules), - _combinable_rules=CombinableStardewRule.merge_and(self.combinable_rules, other.combinable_rules)) + _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) return And(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) - def __eq__(self, other): - return isinstance(other, self.__class__) and other.rules == self.rules - - def __hash__(self): - return hash(self.rules) + @staticmethod + def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: + return max(left, right, key=lambda x: x.value) def get_difficulty(self): return max(rule.get_difficulty() for rule in self.rules) - def simplify(self) -> StardewRule: - if self._simplified: - return self - if false_ in self.unique_rules: - self._combined_rules = frozenset({false_}) - return false_ - - simplified_rules = frozenset(simplified - for simplified in {rule.simplify() for rule in self.rules} - if simplified is not true_) - - if not simplified_rules: - self._combined_rules = frozenset({true_}) - return true_ - - if len(simplified_rules) == 1: - return next(iter(simplified_rules)) - - self._combined_rules = frozenset(simplified_rules) - self._simplified = True - return self - - def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, self.rules) - class Count(StardewRule): count: int From 07f23b07cb9a1b4502d3ab20e98790014a281eb1 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 20:04:07 -0500 Subject: [PATCH 227/482] stop merging sets so much --- worlds/stardew_valley/stardew_rule.py | 53 ++++++++++++++----------- worlds/stardew_valley/test/TestLogic.py | 20 +++++----- worlds/stardew_valley/test/TestRules.py | 2 +- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index a45db3bea0ea..be16585f36ea 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -3,6 +3,7 @@ from abc import ABC, abstractmethod from dataclasses import dataclass, field from functools import cached_property +from itertools import chain from typing import Iterable, Dict, List, Union, FrozenSet, Sized, Hashable, Callable from frozendict import frozendict @@ -204,10 +205,9 @@ class AggregatingStardewRule(StardewRule, ABC): combinable_rules: frozendict[Hashable, CombinableStardewRule] unique_rules: FrozenSet[StardewRule] - detailed_rules: FrozenSet[StardewRule] + detailed_unique_rules: FrozenSet[StardewRule] _simplified: bool - _combined_rules: FrozenSet[StardewRule] def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): self._simplified = False @@ -221,55 +221,60 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru self.unique_rules = frozenset(rules) self.combinable_rules = _combinable_rules - self.detailed_rules = self.rules + self.detailed_unique_rules = self.unique_rules + + @property + def rules_iterable(self): + return chain(self.unique_rules, self.combinable_rules.values()) + + @property + def detailed_rules_iterable(self): + return chain(self.detailed_unique_rules, self.combinable_rules.values()) @staticmethod @abstractmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError - @property - def rules(self): - if not self._combined_rules: - self._combined_rules = self.unique_rules.union(self.combinable_rules.values()) - return self._combined_rules - def __str__(self): - return f"({self.symbol.join(str(rule) for rule in self.rules)})" + return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" def __repr__(self): - return f"({self.symbol.join(repr(rule) for rule in self.rules)})" + return f"({self.symbol.join(repr(rule) for rule in self.detailed_rules_iterable)})" def __eq__(self, other): - return isinstance(other, self.__class__) and other.rules == self.rules + return isinstance(other, self.__class__) and self.combinable_rules == other.combinable_rules and self.unique_rules == self.unique_rules def __hash__(self): - return hash(self.rules) + return hash((self.combinable_rules, self.unique_rules)) def simplify(self) -> StardewRule: if self._simplified: return self if self.complement in self.unique_rules: - self._combined_rules = frozenset({self.complement}) + self.unique_rules = frozenset({self.complement}) return self.complement simplified_rules = frozenset(simplified - for simplified in {rule.simplify() for rule in self.rules} + for simplified in (rule.simplify() for rule in self.unique_rules) if simplified is not self.identity) - if not simplified_rules: - self._combined_rules = frozenset({self.identity}) + if not simplified_rules and not self.combinable_rules: + self.unique_rules = frozenset({self.identity}) return self.identity - if len(simplified_rules) == 1: + if len(simplified_rules) == 1 and not self.combinable_rules: return next(iter(simplified_rules)) - self._combined_rules = frozenset(simplified_rules) + if not simplified_rules and len(self.combinable_rules) == 1: + return next(iter(self.combinable_rules.values())) + + self.unique_rules = frozenset(simplified_rules) self._simplified = True return self def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, self.detailed_rules) + return StardewRuleExplanation(self, state, self.detailed_unique_rules) class Or(AggregatingStardewRule): @@ -280,7 +285,7 @@ class Or(AggregatingStardewRule): def __call__(self, state: CollectionState) -> bool: self.simplify() - return any(rule(state) for rule in self.rules) + return any(rule(state) for rule in self.rules_iterable) def __or__(self, other): if other is true_ or other is false_: @@ -300,7 +305,7 @@ def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> Combin return min(left, right, key=lambda x: x.value) def get_difficulty(self): - return min(rule.get_difficulty() for rule in self.rules) + return min(rule.get_difficulty() for rule in self.rules_iterable) class And(AggregatingStardewRule): @@ -311,7 +316,7 @@ class And(AggregatingStardewRule): def __call__(self, state: CollectionState) -> bool: self.simplify() - return all(rule(state) for rule in self.rules) + return all(rule(state) for rule in self.rules_iterable) def __and__(self, other): if other is true_ or other is false_: @@ -331,7 +336,7 @@ def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> Combin return max(left, right, key=lambda x: x.value) def get_difficulty(self): - return max(rule.get_difficulty() for rule in self.rules) + return max(rule.get_difficulty() for rule in self.rules_iterable) class Count(StardewRule): diff --git a/worlds/stardew_valley/test/TestLogic.py b/worlds/stardew_valley/test/TestLogic.py index b41f3e77a58c..d2af6cac88c2 100644 --- a/worlds/stardew_valley/test/TestLogic.py +++ b/worlds/stardew_valley/test/TestLogic.py @@ -28,49 +28,49 @@ def test_given_item_rule_then_can_be_resolved(self): with self.subTest(msg=item): rule = logic.registry.item_rules[item] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve item rule for {item} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_building_rule_then_can_be_resolved(self): for building in logic.registry.building_rules.keys(): with self.subTest(msg=building): rule = logic.registry.building_rules[building] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve building rule for {building} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_quest_rule_then_can_be_resolved(self): for quest in logic.registry.quest_rules.keys(): with self.subTest(msg=quest): rule = logic.registry.quest_rules[quest] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve quest rule for {quest} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_special_order_rule_then_can_be_resolved(self): for special_order in logic.registry.special_order_rules.keys(): with self.subTest(msg=special_order): rule = logic.registry.special_order_rules[special_order] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve special order rule for {special_order} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_tree_fruit_rule_then_can_be_resolved(self): for tree_fruit in logic.registry.tree_fruit_rules.keys(): with self.subTest(msg=tree_fruit): rule = logic.registry.tree_fruit_rules[tree_fruit] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve tree fruit rule for {tree_fruit} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_seed_rule_then_can_be_resolved(self): for seed in logic.registry.seed_rules.keys(): with self.subTest(msg=seed): rule = logic.registry.seed_rules[seed] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve seed rule for {seed} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_crop_rule_then_can_be_resolved(self): for crop in logic.registry.crop_rules.keys(): with self.subTest(msg=crop): rule = logic.registry.crop_rules[crop] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve crop rule for {crop} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_fish_rule_then_can_be_resolved(self): for fish in logic.registry.fish_rules.keys(): @@ -78,21 +78,21 @@ def test_given_fish_rule_then_can_be_resolved(self): rule = logic.registry.fish_rules[fish] self.assertNotIn(MISSING_ITEM, repr(rule)) rule_result = rule(multi_world.state) - self.assertTrue(rule == False_() or rule_result, f"Could not resolve fish rule for {fish} {rule}") + self.assertTrue(rule == False_() or rule_result, rule.explain(multi_world.state)) def test_given_museum_rule_then_can_be_resolved(self): for donation in logic.registry.museum_rules.keys(): with self.subTest(msg=donation): rule = logic.registry.museum_rules[donation] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve museum rule for {donation} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_cooking_rule_then_can_be_resolved(self): for cooking_rule in logic.registry.cooking_rules.keys(): with self.subTest(msg=cooking_rule): rule = logic.registry.cooking_rules[cooking_rule] self.assertNotIn(MISSING_ITEM, repr(rule)) - self.assertTrue(rule == False_() or rule(multi_world.state), f"Could not resolve cooking rule for {cooking_rule} {rule}") + self.assertTrue(rule == False_() or rule(multi_world.state), rule.explain(multi_world.state)) def test_given_location_rule_then_can_be_resolved(self): for location in multi_world.get_locations(1): diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 8bccc7da6de7..fc8aaaf1b2a3 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -770,5 +770,5 @@ class TestVanillaSkillLogicSimplification(SVTestBase): def test_skill_logic_has_level_only_uses_one_has_progression_percent(self): rule = self.multiworld.worlds[1].logic.skill.has_level("Farming", 8) print(rule) - self.assertEqual(1, sum(1 for i in rule.rules if type(i) == HasProgressionPercent)) + self.assertEqual(1, sum(1 for i in rule.rules_iterable if type(i) == HasProgressionPercent)) self.assertIsNotNone(rule.combinable_rules) From cedad21172e99d9aed6ddb3c6f79fa6f22510bea Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 21:19:26 -0500 Subject: [PATCH 228/482] change frozensets for tuple --- worlds/stardew_valley/stardew_rule.py | 33 ++++++++--------- .../test/TestLogicSimplification.py | 35 +++++++------------ 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index be16585f36ea..b77601ebf35b 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -4,7 +4,7 @@ from dataclasses import dataclass, field from functools import cached_property from itertools import chain -from typing import Iterable, Dict, List, Union, FrozenSet, Sized, Hashable, Callable +from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable from frozendict import frozendict @@ -200,25 +200,22 @@ class AggregatingStardewRule(StardewRule, ABC): identity: LiteralStardewRule complement: LiteralStardewRule symbol: str - name: str combinable_rules: frozendict[Hashable, CombinableStardewRule] - unique_rules: FrozenSet[StardewRule] - - detailed_unique_rules: FrozenSet[StardewRule] + unique_rules: Union[Iterable[StardewRule], Sized] + detailed_unique_rules: Union[Iterable[StardewRule], Sized] _simplified: bool def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): self._simplified = False - self._combined_rules = frozenset() if _combinable_rules is _default_combinable_rules: - assert rules, f"Can't create a {self.name} conditions without rules" - _combinable_rules = CombinableStardewRule.reduce([i for i in rules if isinstance(i, CombinableStardewRule)], self.combine) + assert rules, f"Can't create an aggregating condition without rules" + _combinable_rules = CombinableStardewRule.reduce((i for i in rules if isinstance(i, CombinableStardewRule)), self.combine) rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) - self.unique_rules = frozenset(rules) + self.unique_rules = tuple(rules) self.combinable_rules = _combinable_rules self.detailed_unique_rules = self.unique_rules @@ -252,7 +249,7 @@ def simplify(self) -> StardewRule: if self._simplified: return self if self.complement in self.unique_rules: - self.unique_rules = frozenset({self.complement}) + self.unique_rules = (self.complement,) return self.complement simplified_rules = frozenset(simplified @@ -260,7 +257,7 @@ def simplify(self) -> StardewRule: if simplified is not self.identity) if not simplified_rules and not self.combinable_rules: - self.unique_rules = frozenset({self.identity}) + self.unique_rules = (self.identity,) return self.identity if len(simplified_rules) == 1 and not self.combinable_rules: @@ -269,19 +266,18 @@ def simplify(self) -> StardewRule: if not simplified_rules and len(self.combinable_rules) == 1: return next(iter(self.combinable_rules.values())) - self.unique_rules = frozenset(simplified_rules) + self.unique_rules = simplified_rules self._simplified = True return self def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, self.detailed_unique_rules) + return StardewRuleExplanation(self, state, frozenset(self.detailed_unique_rules)) class Or(AggregatingStardewRule): identity = false_ complement = true_ symbol = " | " - name = "Or" def __call__(self, state: CollectionState) -> bool: self.simplify() @@ -295,10 +291,10 @@ def __or__(self, other): return Or(*self.unique_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) if type(other) is Or: - return Or(*self.unique_rules.union(other.unique_rules), + return Or(*self.unique_rules, *other.unique_rules, _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) - return Or(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) + return Or(*self.unique_rules, other, _combinable_rules=self.combinable_rules) @staticmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: @@ -312,7 +308,6 @@ class And(AggregatingStardewRule): identity = true_ complement = false_ symbol = " & " - name = "And" def __call__(self, state: CollectionState) -> bool: self.simplify() @@ -326,10 +321,10 @@ def __and__(self, other): return And(*self.unique_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) if type(other) is And: - return And(*self.unique_rules.union(other.unique_rules), + return And(*self.unique_rules, *other.unique_rules, _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) - return And(*self.unique_rules.union({other}), _combinable_rules=self.combinable_rules) + return And(*self.unique_rules, other, _combinable_rules=self.combinable_rules) @staticmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index 0b999cc254da..98c45bedd20d 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -1,4 +1,5 @@ import unittest +from unittest import skip from ..stardew_rule import Received, Has, False_, And, Or, True_, HasProgressionPercent @@ -22,33 +23,23 @@ def test_simplify_false_in_or(self): self.assertEqual((Has("Wood", rules) | summer | Has("Rock", rules)).simplify(), summer) - # This feature has been disabled and that seems to save time - # 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))) - # self.assertEqual(rule.simplify(), - # And(Received('Summer', 0, 1), Received('Fall', 0, 1), - # Received('Winter', 0, 1), Received('Spring', 0, 1))) + def test_simplify_and_in_and(self): + rule = And(Received('Summer', 0, 1), Received('Fall', 0, 1)) & And(Received('Winter', 0, 1), Received('Spring', 0, 1)) + self.assertEqual(rule.simplify(), And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1))) + @skip("This feature has been disabled and that seems to save time") 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))) - self.assertEqual(rule.simplify(), - And(Received('Summer', 0, 1), Received('Fall', 0, 1))) + rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), And(Received('Summer', 0, 1), Received('Fall', 0, 1))) + self.assertEqual(rule.simplify(), And(Received('Summer', 0, 1), Received('Fall', 0, 1))) - # This feature has been disabled and that seems to save time - # 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))) - # self.assertEqual(rule.simplify(), - # Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), - # Received('Spring', 0, 1))) + def test_simplify_or_in_or(self): + rule = Or(Received('Summer', 0, 1), Received('Fall', 0, 1)) | Or(Received('Winter', 0, 1), Received('Spring', 0, 1)) + self.assertEqual(rule.simplify(), Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1))) + @skip("This feature has been disabled and that seems to save time") 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))) - self.assertEqual(rule.simplify(), - Or(Received('Summer', 0, 1), Received('Fall', 0, 1))) + rule = And(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), Or(Received('Summer', 0, 1), Received('Fall', 0, 1))) + self.assertEqual(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)) From 007f8d7315d6ddbb23790f52082c24c3577fbc27 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 21:43:58 -0500 Subject: [PATCH 229/482] split rules while merging --- worlds/stardew_valley/stardew_rule.py | 29 +++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index b77601ebf35b..c5b30456e42d 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -4,7 +4,7 @@ from dataclasses import dataclass, field from functools import cached_property from itertools import chain -from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable +from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple from frozendict import frozendict @@ -152,7 +152,29 @@ def is_same_rule(self, other: CombinableStardewRule): return self.combination_key == other.combination_key @staticmethod - def reduce(rules: Union[Iterable[CombinableStardewRule], Sized], + def split_rules(rules: Union[Iterable[StardewRule]], + reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ + -> Tuple[Tuple[StardewRule, ...], frozendict[Hashable, CombinableStardewRule]]: + if not rules: + return (), frozendict() + + other_rules = [] + reduced_rules = {} + for rule in rules: + if isinstance(rule, CombinableStardewRule): + key = rule.combination_key + if key not in reduced_rules: + reduced_rules[key] = rule + continue + + reduced_rules[key] = reducer(reduced_rules[key], rule) + else: + other_rules.append(rule) + + return tuple(other_rules), frozendict(reduced_rules) + + @staticmethod + def reduce(rules: Union[Iterable[CombinableStardewRule]], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> frozendict[Hashable, CombinableStardewRule]: if not rules: @@ -212,8 +234,7 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru if _combinable_rules is _default_combinable_rules: assert rules, f"Can't create an aggregating condition without rules" - _combinable_rules = CombinableStardewRule.reduce((i for i in rules if isinstance(i, CombinableStardewRule)), self.combine) - rules = (i for i in rules if not isinstance(i, CombinableStardewRule)) + rules, _combinable_rules = CombinableStardewRule.split_rules(rules, self.combine) self.unique_rules = tuple(rules) self.combinable_rules = _combinable_rules From aa313f5a7085b6f3241274c99dc096cd1a6e12ae Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 22:11:10 -0500 Subject: [PATCH 230/482] use type instead of __class__ --- worlds/stardew_valley/stardew_rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index c5b30456e42d..2fda9c949a74 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -261,7 +261,7 @@ def __repr__(self): return f"({self.symbol.join(repr(rule) for rule in self.detailed_rules_iterable)})" def __eq__(self, other): - return isinstance(other, self.__class__) and self.combinable_rules == other.combinable_rules and self.unique_rules == self.unique_rules + return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.unique_rules == self.unique_rules def __hash__(self): return hash((self.combinable_rules, self.unique_rules)) From f073b68999bfe780c17fc4a8d557004a11f2584e Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 22:21:26 -0500 Subject: [PATCH 231/482] delete dead code --- worlds/stardew_valley/logic/season_logic.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index d006b799deea..03a5fd423813 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -5,7 +5,7 @@ from .received_logic import ReceivedLogicMixin from .time_logic import TimeLogicMixin from ..options import SeasonRandomization -from ..stardew_rule import StardewRule, True_, And, Or +from ..stardew_rule import StardewRule, True_, Or from ..strings.generic_names import Generic from ..strings.season_names import Season @@ -38,8 +38,3 @@ def has_any(self, seasons: Iterable[str]): def has_any_not_winter(self): return self.logic.season.has_any([Season.spring, Season.summer, Season.fall]) - - def has_all(self, seasons: Iterable[str]): - if not seasons: - return True_() - return And(*(self.logic.season.has(season) for season in seasons)) From 2ef19a7ad12004bdf225e00ee21726dc130d6319 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 22:30:02 -0500 Subject: [PATCH 232/482] stuff --- worlds/stardew_valley/stardew_rule.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 2fda9c949a74..671800b53363 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -459,14 +459,6 @@ def __post_init__(self): assert item_table[self.item].classification & ItemClassification.progression, \ f"Item [{item_table[self.item].name}] has to be progression to be used in logic" - def __call__(self, state: CollectionState) -> bool: - return state.has(self.item, self.player, self.count) - - def __repr__(self): - if self.count == 1: - return f"Received {self.item}" - return f"Received {self.count} {self.item}" - @property def combination_key(self) -> Hashable: return self.item @@ -475,6 +467,14 @@ def combination_key(self) -> Hashable: def value(self): return self.count + def __call__(self, state: CollectionState) -> bool: + return state.has(self.item, self.player, self.count) + + def __repr__(self): + if self.count == 1: + return f"Received {self.item}" + return f"Received {self.count} {self.item}" + def get_difficulty(self): return self.count From f2ba99b5be263a90f268fbd73da84ab82e7af3b9 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 23:22:32 -0500 Subject: [PATCH 233/482] rename unique rules to other rules --- worlds/stardew_valley/stardew_rule.py | 35 ++++++++++++++------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 671800b53363..32a0f763f18d 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -224,7 +224,7 @@ class AggregatingStardewRule(StardewRule, ABC): symbol: str combinable_rules: frozendict[Hashable, CombinableStardewRule] - unique_rules: Union[Iterable[StardewRule], Sized] + other_rules: Union[Iterable[StardewRule], Sized] detailed_unique_rules: Union[Iterable[StardewRule], Sized] _simplified: bool @@ -236,14 +236,14 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru assert rules, f"Can't create an aggregating condition without rules" rules, _combinable_rules = CombinableStardewRule.split_rules(rules, self.combine) - self.unique_rules = tuple(rules) + self.other_rules = tuple(rules) self.combinable_rules = _combinable_rules - self.detailed_unique_rules = self.unique_rules + self.detailed_unique_rules = self.other_rules @property def rules_iterable(self): - return chain(self.unique_rules, self.combinable_rules.values()) + return chain(self.other_rules, self.combinable_rules.values()) @property def detailed_rules_iterable(self): @@ -261,24 +261,25 @@ def __repr__(self): return f"({self.symbol.join(repr(rule) for rule in self.detailed_rules_iterable)})" def __eq__(self, other): - return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.unique_rules == self.unique_rules + return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.other_rules == self.other_rules def __hash__(self): - return hash((self.combinable_rules, self.unique_rules)) + return hash((self.combinable_rules, self.other_rules)) def simplify(self) -> StardewRule: if self._simplified: return self - if self.complement in self.unique_rules: - self.unique_rules = (self.complement,) + self.other_rules = frozenset(self.other_rules) + if self.complement in self.other_rules: + self.other_rules = (self.complement,) return self.complement simplified_rules = frozenset(simplified - for simplified in (rule.simplify() for rule in self.unique_rules) + for simplified in (rule.simplify() for rule in self.other_rules) if simplified is not self.identity) if not simplified_rules and not self.combinable_rules: - self.unique_rules = (self.identity,) + self.other_rules = (self.identity,) return self.identity if len(simplified_rules) == 1 and not self.combinable_rules: @@ -287,7 +288,7 @@ def simplify(self) -> StardewRule: if not simplified_rules and len(self.combinable_rules) == 1: return next(iter(self.combinable_rules.values())) - self.unique_rules = simplified_rules + self.other_rules = simplified_rules self._simplified = True return self @@ -309,13 +310,13 @@ def __or__(self, other): return other | self if isinstance(other, CombinableStardewRule): - return Or(*self.unique_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) + return Or(*self.other_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) if type(other) is Or: - return Or(*self.unique_rules, *other.unique_rules, + return Or(*self.other_rules, *other.other_rules, _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) - return Or(*self.unique_rules, other, _combinable_rules=self.combinable_rules) + return Or(*self.other_rules, other, _combinable_rules=self.combinable_rules) @staticmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: @@ -339,13 +340,13 @@ def __and__(self, other): return other & self if isinstance(other, CombinableStardewRule): - return And(*self.unique_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) + return And(*self.other_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) if type(other) is And: - return And(*self.unique_rules, *other.unique_rules, + return And(*self.other_rules, *other.other_rules, _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) - return And(*self.unique_rules, other, _combinable_rules=self.combinable_rules) + return And(*self.other_rules, other, _combinable_rules=self.combinable_rules) @staticmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: From 2487c67595011e3452cf229dbd4915e40e3f5adb Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 25 Nov 2023 23:41:46 -0500 Subject: [PATCH 234/482] check combined rules before simplifying --- worlds/stardew_valley/stardew_rule.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 32a0f763f18d..c1676fe7573f 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -302,8 +302,10 @@ class Or(AggregatingStardewRule): symbol = " | " def __call__(self, state: CollectionState) -> bool: + if any(rule(state) for rule in self.combinable_rules.values()): + return True self.simplify() - return any(rule(state) for rule in self.rules_iterable) + return any(rule(state) for rule in self.other_rules) def __or__(self, other): if other is true_ or other is false_: @@ -332,8 +334,10 @@ class And(AggregatingStardewRule): symbol = " & " def __call__(self, state: CollectionState) -> bool: + if not all(rule(state) for rule in self.combinable_rules.values()): + return False self.simplify() - return all(rule(state) for rule in self.rules_iterable) + return all(rule(state) for rule in self.other_rules) def __and__(self, other): if other is true_ or other is false_: From fdaef3e0367cc3f44d4c4ab77d21411434d9f258 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 00:53:02 -0500 Subject: [PATCH 235/482] simplify merge of combinable stardew rules --- worlds/stardew_valley/stardew_rule.py | 24 +++++-------------- .../test/performance/TestPerformance.py | 5 ++-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index c1676fe7573f..fdd6b6eddb2f 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -155,9 +155,6 @@ def is_same_rule(self, other: CombinableStardewRule): def split_rules(rules: Union[Iterable[StardewRule]], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> Tuple[Tuple[StardewRule, ...], frozendict[Hashable, CombinableStardewRule]]: - if not rules: - return (), frozendict() - other_rules = [] reduced_rules = {} for rule in rules: @@ -174,15 +171,12 @@ def split_rules(rules: Union[Iterable[StardewRule]], return tuple(other_rules), frozendict(reduced_rules) @staticmethod - def reduce(rules: Union[Iterable[CombinableStardewRule]], - reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ + def merge(left: frozendict[Hashable, CombinableStardewRule], + right: frozendict[Hashable, CombinableStardewRule], + reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> frozendict[Hashable, CombinableStardewRule]: - if not rules: - return frozendict() - - reduced_rules = {} - for rule in rules: - key = rule.combination_key + reduced_rules = dict(left) + for key, rule in right.items(): if key not in reduced_rules: reduced_rules[key] = rule continue @@ -191,13 +185,6 @@ def reduce(rules: Union[Iterable[CombinableStardewRule]], return frozendict(reduced_rules) - @staticmethod - def merge(left: frozendict[Hashable, CombinableStardewRule], - right: frozendict[Hashable, CombinableStardewRule], - reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ - -> frozendict[Hashable, CombinableStardewRule]: - return CombinableStardewRule.reduce({*left.values(), *right.values()}, reducer) - def add_into(self, rules: frozendict[Hashable, CombinableStardewRule], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> frozendict[Hashable, CombinableStardewRule]: @@ -267,6 +254,7 @@ def __hash__(self): return hash((self.combinable_rules, self.other_rules)) def simplify(self) -> StardewRule: + # TODO merge simplify + __call__ if self._simplified: return self self.other_rules = frozenset(self.other_rules) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 549bfd94592c..d390fe1d1878 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -10,7 +10,7 @@ from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options number_generations = 25 -default_seed = 58754761123126659868 +default_seeds = [10613921641417078811] * number_generations acceptable_deviation = 4 @@ -71,8 +71,7 @@ def performance_test_multiworld(self, options): acceptable_average_time = self.acceptable_time_per_player * amount_of_players total_time = 0 all_times = [] - seeds = [get_seed() if self.skip_fill else default_seed - for _ in range(number_generations)] + seeds = [get_seed() for _ in range(number_generations)] if self.skip_fill else default_seeds for i, seed in enumerate(seeds): with self.subTest(f"Seed: {seed}"): From 0b3c23b274d34a5673d3a0c6cbb0881dec239d8a Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 01:07:14 -0500 Subject: [PATCH 236/482] fix long tests --- worlds/stardew_valley/logic/logic.py | 7 +++++-- worlds/stardew_valley/test/TestRandomWorlds.py | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 33b0e23bb7ce..be9e0ae82b6c 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -2,13 +2,12 @@ from dataclasses import dataclass -from .buff_logic import BuffLogicMixin -from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from .ability_logic import AbilityLogicMixin from .action_logic import ActionLogicMixin from .arcade_logic import ArcadeLogicMixin from .artisan_logic import ArtisanLogicMixin from .base_logic import LogicRegistry +from .buff_logic import BuffLogicMixin from .building_logic import BuildingLogicMixin from .bundle_logic import BundleLogicMixin from .combat_logic import CombatLogicMixin @@ -55,6 +54,7 @@ from ..strings.ap_names.community_upgrade_names import CommunityUpgrade from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building +from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.decoration_names import Decoration @@ -704,6 +704,9 @@ def has_all_stardrops(self) -> StardewRule: if ModNames.deepwoods in self.options.mods: # Petting the Unicorn number_of_stardrops_to_receive += 1 + if not other_rules: + return self.received("Stardrop", number_of_stardrops_to_receive) + return self.received("Stardrop", number_of_stardrops_to_receive) & And(*other_rules) def has_prismatic_jelly_reward_access(self) -> StardewRule: diff --git a/worlds/stardew_valley/test/TestRandomWorlds.py b/worlds/stardew_valley/test/TestRandomWorlds.py index ab677a869627..db5e0278c06f 100644 --- a/worlds/stardew_valley/test/TestRandomWorlds.py +++ b/worlds/stardew_valley/test/TestRandomWorlds.py @@ -1,14 +1,14 @@ -from typing import Dict import random +from typing import Dict from BaseClasses import MultiWorld from Options import NamedRange, Range -from worlds.stardew_valley.test.long.option_names import options_to_include from worlds.stardew_valley.test import setup_solo_multiworld, SVTestCase -from worlds.stardew_valley.test.checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid +from worlds.stardew_valley.test.checks.goal_checks import assert_goal_world_is_valid from worlds.stardew_valley.test.checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ assert_festivals_give_access_to_deluxe_scarecrow, assert_has_festival_recipes from worlds.stardew_valley.test.checks.world_checks import assert_same_number_items_locations, assert_victory_exists +from worlds.stardew_valley.test.long.option_names import options_to_include def get_option_choices(option) -> Dict[str, int]: From 68282091695a034eb4a8e6cb288bf70effe1ff1d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 26 Nov 2023 15:13:18 -0500 Subject: [PATCH 237/482] - Added missing ginger island tags --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index b1cc58018c48..39b3de17f1ab 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -814,7 +814,7 @@ id,name,classification,groups,mod_name 10610,Water Strainer Recipe,progression,CRAFTSANITY,Archaeology 10611,Wooden Display Recipe,progression,CRAFTSANITY,Archaeology 10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology -10613,Warp Totem: Volcano Recipe,progression,CRAFTSANITY,Archaeology +10613,Warp Totem: Volcano Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Archaeology 10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology 10615,hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology 10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index d9198cbace7e..8a277cf88dc0 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2497,7 +2497,7 @@ id,region,name,tags,mod_name 7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology 7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology 7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology -7417,Farm,Craft Warp Totem: Volcano,CRAFTSANITY,Archaeology +7417,Farm,Craft Warp Totem: Volcano,"CRAFTSANITY,GINGER_ISLAND",Archaeology 7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded @@ -2514,7 +2514,7 @@ id,region,name,tags,mod_name 7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology 7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology 7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology -7467,Farm,Warp Totem: Volcano Recipe,CRAFTSANITY,Archaeology +7467,Farm,Warp Totem: Volcano Recipe,"CRAFTSANITY,GINGER_ISLAND",Archaeology 7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) @@ -2571,7 +2571,7 @@ id,region,name,tags,mod_name 7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded -7721,Beach,Fishsanity: Starfish,FISHSANITY,Stardew Valley Expanded +7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded 7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded @@ -2647,7 +2647,7 @@ id,region,name,tags,mod_name 8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded 8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded 8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded -8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded 8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded From fcfdb5cd961ee3d6d5d4007b3eb2f43212331e29 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 14:21:40 -0500 Subject: [PATCH 238/482] stuff --- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/test/TestGeneration.py | 4 ++-- worlds/stardew_valley/test/__init__.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 75bcbeaa15a8..9c4108f61f0b 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -130,7 +130,7 @@ def set_bundle_rules(bundle_rooms: List[BundleRoom], logic: StardewLogic, multiw if bundle_room.name == CCRoom.abandoned_joja_mart: continue room_location = f"Complete {bundle_room.name}" - MultiWorldRules.set_rule(multiworld.get_location(room_location, player), And(*room_rules)) + MultiWorldRules.add_rule(multiworld.get_location(room_location, player), And(*room_rules)) def set_skills_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 988eb9abeea6..aa6bbe03663c 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -4,7 +4,7 @@ from BaseClasses import ItemClassification, MultiWorld, Item from . import setup_solo_multiworld, SVTestBase, get_minsanity_options, allsanity_options_without_mods, \ allsanity_options_with_mods, minimal_locations_maximal_items, SVTestCase, default_options, minimal_locations_maximal_items_with_island -from .. import locations, items, location_table, options +from .. import items, location_table, options from ..data.villagers_data import all_villagers_by_name, all_villagers_by_mod_by_name from ..items import Group, item_table from ..locations import LocationTags @@ -231,7 +231,7 @@ def test_given_elevator_to_floor_105_when_find_another_elevator_then_has_access_ items_for_115 = self.generate_items_for_mine_115() last_elevator = self.get_item_by_name("Progressive Mine Elevator") self.collect(items_for_115) - floor_115 = self.multiworld.get_region("The Mines - Floor 115", self.player) + floor_115 = self.multiworld.get_region("The Mines - Floor 115", self.player) floor_120 = self.multiworld.get_region("The Mines - Floor 120", self.player) self.assertTrue(floor_115.can_reach(self.multiworld.state)) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 5c8d1d97bec1..80ccc204d3a9 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -161,9 +161,10 @@ def setUpClass(cls) -> None: class SVTestBase(WorldTestBase, SVTestCase): + seed = None def world_setup(self, *args, **kwargs): - super().world_setup(*args, **kwargs) + super().world_setup(seed=self.seed) if self.constructed: self.world = self.multiworld.worlds[self.player] # noqa From e8d6cab68cf42938681b8d4701d6493de455a797 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 16:09:50 -0500 Subject: [PATCH 239/482] simplify while evaluate --- worlds/stardew_valley/stardew_rule.py | 87 ++++++++++++++++--- .../test/TestLogicSimplification.py | 18 ++-- 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index fdd6b6eddb2f..900d010f86ee 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -4,7 +4,7 @@ from dataclasses import dataclass, field from functools import cached_property from itertools import chain -from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple +from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional from frozendict import frozendict @@ -77,10 +77,12 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: class LiteralStardewRule(StardewRule, ABC): + value: bool pass class True_(LiteralStardewRule): # noqa + value = True def __new__(cls, _cache=[]): # noqa # Only one single instance will be ever created. @@ -105,6 +107,7 @@ def get_difficulty(self): class False_(LiteralStardewRule): # noqa + value = False def __new__(cls, _cache=[]): # noqa # Only one single instance will be ever created. @@ -133,8 +136,6 @@ def get_difficulty(self): assert false_ is False_() assert true_ is True_() -_default_combinable_rules = object() - class CombinableStardewRule(StardewRule, ABC): @@ -214,12 +215,16 @@ class AggregatingStardewRule(StardewRule, ABC): other_rules: Union[Iterable[StardewRule], Sized] detailed_unique_rules: Union[Iterable[StardewRule], Sized] + _simplified: bool + _simplified_rules: Set[StardewRule] + _left_to_simplify_rules: Optional[Iterable[StardewRule]] - def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_rules): + def __init__(self, *rules: StardewRule, _combinable_rules=None): self._simplified = False + self._simplified_rules = set() - if _combinable_rules is _default_combinable_rules: + if _combinable_rules is None: assert rules, f"Can't create an aggregating condition without rules" rules, _combinable_rules = CombinableStardewRule.split_rules(rules, self.combine) @@ -227,6 +232,7 @@ def __init__(self, *rules: StardewRule, _combinable_rules=_default_combinable_ru self.combinable_rules = _combinable_rules self.detailed_unique_rules = self.other_rules + self._left_to_simplify_rules = None @property def rules_iterable(self): @@ -241,6 +247,28 @@ def detailed_rules_iterable(self): def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError + def simplify_while_evaluate(self, state: CollectionState, f) -> bool: + # TODO test if inverting would speed up + for rule in chain(self.combinable_rules.values()): + if rule(state) is self.complement.value: + return self.complement.value + + # for rule in self._left_to_simplify_rules: + # simplified = rule.simplify() + # + # if simplified is self.identity or simplified in self._simplified_rules: + # continue + # self._simplified_rules.add(simplified) + # + # if simplified(state) is self.complement.value: + # return self.complement.value + # + # self._simplified = True + # return self.identity.value + + self.simplify() + return f(r(state) for r in self.other_rules) + def __str__(self): return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" @@ -280,6 +308,45 @@ def simplify(self) -> StardewRule: self._simplified = True return self + def simplify2(self) -> StardewRule: + # TODO is this needed now that we're using an iterator ? + if self._simplified: + return self + + self.other_rules = frozenset(self.other_rules) + if self.complement in self.other_rules: + self.other_rules = (self.complement,) + return self.complement + + self._left_to_simplify_rules = iter(self.other_rules) + + for rule in self._left_to_simplify_rules: + simplified = rule.simplify() + + if simplified is self.identity or simplified in self._simplified_rules: + continue + + if simplified is self.complement: + self._simplified = True + self._simplified_rules = {self.complement} + return self.complement + + self._simplified_rules.add(simplified) + + self._simplified = True + + if not self._simplified_rules and not self.combinable_rules: + self._simplified_rules = {self.identity} + return self.identity + + if len(self._simplified_rules) == 1 and not self.combinable_rules: + return next(iter(self._simplified_rules)) + + if not self._simplified_rules and len(self.combinable_rules) == 1: + return next(iter(self.combinable_rules.values())) + + return self + def explain(self, state: CollectionState) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, frozenset(self.detailed_unique_rules)) @@ -290,10 +357,7 @@ class Or(AggregatingStardewRule): symbol = " | " def __call__(self, state: CollectionState) -> bool: - if any(rule(state) for rule in self.combinable_rules.values()): - return True - self.simplify() - return any(rule(state) for rule in self.other_rules) + return self.simplify_while_evaluate(state, any) def __or__(self, other): if other is true_ or other is false_: @@ -322,10 +386,7 @@ class And(AggregatingStardewRule): symbol = " & " def __call__(self, state: CollectionState) -> bool: - if not all(rule(state) for rule in self.combinable_rules.values()): - return False - self.simplify() - return all(rule(state) for rule in self.other_rules) + return self.simplify_while_evaluate(state, all) def __and__(self, other): if other is true_ or other is false_: diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py index 98c45bedd20d..56cb10808e78 100644 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ b/worlds/stardew_valley/test/TestLogicSimplification.py @@ -11,8 +11,7 @@ def test_simplify_true_in_and(self): "Rock": True_(), } summer = Received("Summer", 0, 1) - self.assertEqual((Has("Wood", rules) & summer & Has("Rock", rules)).simplify(), - summer) + self.assertEqual(summer, (Has("Wood", rules) & summer & Has("Rock", rules)).simplify()) def test_simplify_false_in_or(self): rules = { @@ -20,34 +19,33 @@ def test_simplify_false_in_or(self): "Rock": False_(), } summer = Received("Summer", 0, 1) - self.assertEqual((Has("Wood", rules) | summer | Has("Rock", rules)).simplify(), - summer) + self.assertEqual(summer, (Has("Wood", rules) | summer | Has("Rock", rules)).simplify()) def test_simplify_and_in_and(self): rule = And(Received('Summer', 0, 1), Received('Fall', 0, 1)) & And(Received('Winter', 0, 1), Received('Spring', 0, 1)) - self.assertEqual(rule.simplify(), And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1))) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) @skip("This feature has been disabled and that seems to save time") 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))) - self.assertEqual(rule.simplify(), And(Received('Summer', 0, 1), Received('Fall', 0, 1))) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) def test_simplify_or_in_or(self): rule = Or(Received('Summer', 0, 1), Received('Fall', 0, 1)) | Or(Received('Winter', 0, 1), Received('Spring', 0, 1)) - self.assertEqual(rule.simplify(), Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1))) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) @skip("This feature has been disabled and that seems to save time") 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))) - self.assertEqual(rule.simplify(), Or(Received('Summer', 0, 1), Received('Fall', 0, 1))) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) def test_simplify_true_in_or(self): rule = Or(True_(), Received('Summer', 0, 1)) - self.assertEqual(rule.simplify(), True_()) + self.assertEqual(True_(), rule.simplify()) def test_simplify_false_in_and(self): rule = And(False_(), Received('Summer', 0, 1)) - self.assertEqual(rule.simplify(), False_()) + self.assertEqual(False_(), rule.simplify()) class TestHasProgressionPercentSimplification(unittest.TestCase): From 5ded69b1c9fe0e59dce814c3312f31ca4039c0af Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 16:12:55 -0500 Subject: [PATCH 240/482] change comprehension to classic for loop --- worlds/stardew_valley/stardew_rule.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 900d010f86ee..4c9d7a1051d5 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -285,14 +285,19 @@ def simplify(self) -> StardewRule: # TODO merge simplify + __call__ if self._simplified: return self + self.other_rules = frozenset(self.other_rules) if self.complement in self.other_rules: self.other_rules = (self.complement,) return self.complement - simplified_rules = frozenset(simplified - for simplified in (rule.simplify() for rule in self.other_rules) - if simplified is not self.identity) + simplified_rules = set() + + for simplified in (rule.simplify() for rule in self.other_rules): + if simplified is not self.identity: + simplified_rules.add(simplified) + + simplified_rules = frozenset(simplified_rules) if not simplified_rules and not self.combinable_rules: self.other_rules = (self.identity,) From febe00441d1cb1f4e74ef1ca2f79f06aef9c9308 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 16:22:58 -0500 Subject: [PATCH 241/482] check if simplified is in set and shortcircuit complement --- worlds/stardew_valley/stardew_rule.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 4c9d7a1051d5..85ba393209c1 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -293,9 +293,19 @@ def simplify(self) -> StardewRule: simplified_rules = set() - for simplified in (rule.simplify() for rule in self.other_rules): - if simplified is not self.identity: - simplified_rules.add(simplified) + self._left_to_simplify_rules = iter(self.other_rules) + for rule in self._left_to_simplify_rules: + simplified = rule.simplify() + + if simplified is self.identity or simplified in simplified_rules: + continue + + if simplified is self.complement: + self._simplified = True + self._simplified_rules = {self.complement} + return self.complement + + simplified_rules.add(simplified) simplified_rules = frozenset(simplified_rules) From 7a8fbc2c3bb6eacafac961f100ca61f732100e2d Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 16:29:13 -0500 Subject: [PATCH 242/482] use _simplified_rules --- worlds/stardew_valley/stardew_rule.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 85ba393209c1..e132586276ca 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -291,13 +291,13 @@ def simplify(self) -> StardewRule: self.other_rules = (self.complement,) return self.complement - simplified_rules = set() + self._simplified_rules = set() self._left_to_simplify_rules = iter(self.other_rules) for rule in self._left_to_simplify_rules: simplified = rule.simplify() - if simplified is self.identity or simplified in simplified_rules: + if simplified is self.identity or simplified in self._simplified_rules: continue if simplified is self.complement: @@ -305,21 +305,21 @@ def simplify(self) -> StardewRule: self._simplified_rules = {self.complement} return self.complement - simplified_rules.add(simplified) + self._simplified_rules.add(simplified) - simplified_rules = frozenset(simplified_rules) + self._simplified_rules = frozenset(self._simplified_rules) - if not simplified_rules and not self.combinable_rules: + if not self._simplified_rules and not self.combinable_rules: self.other_rules = (self.identity,) return self.identity - if len(simplified_rules) == 1 and not self.combinable_rules: - return next(iter(simplified_rules)) + if len(self._simplified_rules) == 1 and not self.combinable_rules: + return next(iter(self._simplified_rules)) - if not simplified_rules and len(self.combinable_rules) == 1: + if not self._simplified_rules and len(self.combinable_rules) == 1: return next(iter(self.combinable_rules.values())) - self.other_rules = simplified_rules + self.other_rules = self._simplified_rules self._simplified = True return self @@ -334,7 +334,6 @@ def simplify2(self) -> StardewRule: return self.complement self._left_to_simplify_rules = iter(self.other_rules) - for rule in self._left_to_simplify_rules: simplified = rule.simplify() From cd26bac8568b54d41a6dfd00f1875eb217057c4e Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 17:02:29 -0500 Subject: [PATCH 243/482] really evaluate while simplifying --- worlds/stardew_valley/stardew_rule.py | 86 ++++++++++++--------------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index e132586276ca..7cde8a6a397d 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -266,34 +266,15 @@ def simplify_while_evaluate(self, state: CollectionState, f) -> bool: # self._simplified = True # return self.identity.value - self.simplify() - return f(r(state) for r in self.other_rules) - - def __str__(self): - return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" - - def __repr__(self): - return f"({self.symbol.join(repr(rule) for rule in self.detailed_rules_iterable)})" - - def __eq__(self, other): - return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.other_rules == self.other_rules - - def __hash__(self): - return hash((self.combinable_rules, self.other_rules)) - - def simplify(self) -> StardewRule: - # TODO merge simplify + __call__ - if self._simplified: - return self + if self._left_to_simplify_rules is None: + self.other_rules = frozenset(self.other_rules) + if self.complement in self.other_rules: + self._simplified = True + self.other_rules = (self.complement,) + return self.complement.value - self.other_rules = frozenset(self.other_rules) - if self.complement in self.other_rules: - self.other_rules = (self.complement,) - return self.complement + self._left_to_simplify_rules = iter(self.other_rules) - self._simplified_rules = set() - - self._left_to_simplify_rules = iter(self.other_rules) for rule in self._left_to_simplify_rules: simplified = rule.simplify() @@ -303,37 +284,44 @@ def simplify(self) -> StardewRule: if simplified is self.complement: self._simplified = True self._simplified_rules = {self.complement} - return self.complement + return self.complement.value self._simplified_rules.add(simplified) - self._simplified_rules = frozenset(self._simplified_rules) + if simplified(state) is self.complement.value: + return self.complement.value - if not self._simplified_rules and not self.combinable_rules: - self.other_rules = (self.identity,) - return self.identity + self._simplified = True + self.other_rules = frozenset(self._simplified_rules) - if len(self._simplified_rules) == 1 and not self.combinable_rules: - return next(iter(self._simplified_rules)) + return f(r(state) for r in self.other_rules) - if not self._simplified_rules and len(self.combinable_rules) == 1: - return next(iter(self.combinable_rules.values())) + def __str__(self): + return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" - self.other_rules = self._simplified_rules - self._simplified = True - return self + def __repr__(self): + return f"({self.symbol.join(repr(rule) for rule in self.detailed_rules_iterable)})" + + def __eq__(self, other): + return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.other_rules == self.other_rules - def simplify2(self) -> StardewRule: + def __hash__(self): + return hash((self.combinable_rules, self.other_rules)) + + def simplify(self) -> StardewRule: # TODO is this needed now that we're using an iterator ? if self._simplified: return self - self.other_rules = frozenset(self.other_rules) - if self.complement in self.other_rules: - self.other_rules = (self.complement,) - return self.complement + if self._left_to_simplify_rules is None: + self.other_rules = frozenset(self.other_rules) + if self.complement in self.other_rules: + self._simplified = True + self.other_rules = (self.complement,) + return self.complement + + self._left_to_simplify_rules = iter(self.other_rules) - self._left_to_simplify_rules = iter(self.other_rules) for rule in self._left_to_simplify_rules: simplified = rule.simplify() @@ -348,15 +336,15 @@ def simplify2(self) -> StardewRule: self._simplified_rules.add(simplified) self._simplified = True + self.other_rules = frozenset(self._simplified_rules) - if not self._simplified_rules and not self.combinable_rules: - self._simplified_rules = {self.identity} + if not self.other_rules and not self.combinable_rules: return self.identity - if len(self._simplified_rules) == 1 and not self.combinable_rules: - return next(iter(self._simplified_rules)) + if len(self.other_rules) == 1 and not self.combinable_rules: + return next(iter(self.other_rules)) - if not self._simplified_rules and len(self.combinable_rules) == 1: + if not self.other_rules and len(self.combinable_rules) == 1: return next(iter(self.combinable_rules.values())) return self From 0f6302672981dc528b791f0fc39c7f9b78f9dff5 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 17:07:44 -0500 Subject: [PATCH 244/482] return both simplified and value --- worlds/stardew_valley/stardew_rule.py | 37 +++++++++++---------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 7cde8a6a397d..1218bb95ef6b 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -78,7 +78,12 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: class LiteralStardewRule(StardewRule, ABC): value: bool - pass + + def __call__(self, state: CollectionState) -> bool: + return self.value + + def __repr__(self): + return str(self.value) class True_(LiteralStardewRule): # noqa @@ -90,18 +95,12 @@ def __new__(cls, _cache=[]): # noqa _cache.append(super(True_, cls).__new__(cls)) return _cache[0] - def __call__(self, state: CollectionState) -> bool: - return True - def __or__(self, other) -> StardewRule: return self def __and__(self, other) -> StardewRule: return other - def __repr__(self): - return "True" - def get_difficulty(self): return 0 @@ -115,18 +114,12 @@ def __new__(cls, _cache=[]): # noqa _cache.append(super(False_, cls).__new__(cls)) return _cache[0] - def __call__(self, state: CollectionState) -> bool: - return False - def __or__(self, other) -> StardewRule: return other def __and__(self, other) -> StardewRule: return self - def __repr__(self): - return "False" - def get_difficulty(self): return 999999999 @@ -247,11 +240,11 @@ def detailed_rules_iterable(self): def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError - def simplify_while_evaluate(self, state: CollectionState, f) -> bool: + def simplify_while_evaluate(self, state: CollectionState, f) -> Tuple[StardewRule, bool]: # TODO test if inverting would speed up for rule in chain(self.combinable_rules.values()): if rule(state) is self.complement.value: - return self.complement.value + return self, self.complement.value # for rule in self._left_to_simplify_rules: # simplified = rule.simplify() @@ -271,7 +264,7 @@ def simplify_while_evaluate(self, state: CollectionState, f) -> bool: if self.complement in self.other_rules: self._simplified = True self.other_rules = (self.complement,) - return self.complement.value + return self.complement, self.complement.value self._left_to_simplify_rules = iter(self.other_rules) @@ -283,18 +276,18 @@ def simplify_while_evaluate(self, state: CollectionState, f) -> bool: if simplified is self.complement: self._simplified = True - self._simplified_rules = {self.complement} - return self.complement.value + self.other_rules = (self.complement,) + return self.complement, self.complement.value self._simplified_rules.add(simplified) if simplified(state) is self.complement.value: - return self.complement.value + return self, self.complement.value self._simplified = True self.other_rules = frozenset(self._simplified_rules) - return f(r(state) for r in self.other_rules) + return self, f(r(state) for r in self.other_rules) def __str__(self): return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" @@ -359,7 +352,7 @@ class Or(AggregatingStardewRule): symbol = " | " def __call__(self, state: CollectionState) -> bool: - return self.simplify_while_evaluate(state, any) + return self.simplify_while_evaluate(state, any)[1] def __or__(self, other): if other is true_ or other is false_: @@ -388,7 +381,7 @@ class And(AggregatingStardewRule): symbol = " & " def __call__(self, state: CollectionState) -> bool: - return self.simplify_while_evaluate(state, all) + return self.simplify_while_evaluate(state, all)[1] def __and__(self, other): if other is true_ or other is false_: From c257146fb4b50f7faf250e82008499468c79d325 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 17:09:01 -0500 Subject: [PATCH 245/482] rename --- worlds/stardew_valley/stardew_rule.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 1218bb95ef6b..484fa72d907a 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -53,6 +53,9 @@ class StardewRule(ABC): def __call__(self, state: CollectionState) -> bool: raise NotImplementedError + def evaluate_while_simplifying(self, state: CollectionState, f) -> Tuple[StardewRule, bool]: + return self.simplify(), self(state) + def __or__(self, other) -> StardewRule: if other is true_ or other is false_ or type(other) is Or: return other | self @@ -240,7 +243,7 @@ def detailed_rules_iterable(self): def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError - def simplify_while_evaluate(self, state: CollectionState, f) -> Tuple[StardewRule, bool]: + def evaluate_while_simplifying(self, state: CollectionState, f) -> Tuple[StardewRule, bool]: # TODO test if inverting would speed up for rule in chain(self.combinable_rules.values()): if rule(state) is self.complement.value: @@ -352,7 +355,7 @@ class Or(AggregatingStardewRule): symbol = " | " def __call__(self, state: CollectionState) -> bool: - return self.simplify_while_evaluate(state, any)[1] + return self.evaluate_while_simplifying(state, any)[1] def __or__(self, other): if other is true_ or other is false_: @@ -381,7 +384,7 @@ class And(AggregatingStardewRule): symbol = " & " def __call__(self, state: CollectionState) -> bool: - return self.simplify_while_evaluate(state, all)[1] + return self.evaluate_while_simplifying(state, all)[1] def __and__(self, other): if other is true_ or other is false_: From c3b4a24d0302a38880064642cceeb24d68c49ca0 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 18:47:39 -0500 Subject: [PATCH 246/482] spead evaluate_while_simplifying --- worlds/stardew_valley/stardew_rule.py | 98 +++++++++++++++---------- worlds/stardew_valley/test/TestRules.py | 41 ++++++----- 2 files changed, 82 insertions(+), 57 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 484fa72d907a..3c10afba49e5 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -18,6 +18,7 @@ class StardewRuleExplanation: rule: StardewRule state: CollectionState + expected: bool sub_rules: Iterable[StardewRule] = field(default_factory=set) def summary(self, depth=0): @@ -28,7 +29,7 @@ def __str__(self, depth=0): return self.summary(depth) return self.summary(depth) + "\n" + "\n".join(StardewRuleExplanation.__str__(i, depth + 1) - if i.result is False else i.summary(depth + 1) + if i.result is not self.expected else i.summary(depth + 1) for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) def __repr__(self, depth=0): @@ -53,7 +54,7 @@ class StardewRule(ABC): def __call__(self, state: CollectionState) -> bool: raise NotImplementedError - def evaluate_while_simplifying(self, state: CollectionState, f) -> Tuple[StardewRule, bool]: + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self.simplify(), self(state) def __or__(self, other) -> StardewRule: @@ -75,8 +76,8 @@ def get_difficulty(self): def simplify(self) -> StardewRule: return self - def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state) + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, expected) class LiteralStardewRule(StardewRule, ABC): @@ -243,12 +244,25 @@ def detailed_rules_iterable(self): def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError - def evaluate_while_simplifying(self, state: CollectionState, f) -> Tuple[StardewRule, bool]: + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: # TODO test if inverting would speed up for rule in chain(self.combinable_rules.values()): if rule(state) is self.complement.value: return self, self.complement.value + if not self.other_rules: + return self, self.identity.value + + if self._simplified: + for rule in self.other_rules: + if rule(state) is self.complement.value: + return self, self.complement.value + return self, self.identity.value + elif self._simplified_rules: + for rule in self._simplified_rules: + if rule(state) is self.complement.value: + return self, self.complement.value + # for rule in self._left_to_simplify_rules: # simplified = rule.simplify() # @@ -272,7 +286,7 @@ def evaluate_while_simplifying(self, state: CollectionState, f) -> Tuple[Stardew self._left_to_simplify_rules = iter(self.other_rules) for rule in self._left_to_simplify_rules: - simplified = rule.simplify() + simplified, value = rule.evaluate_while_simplifying(state) if simplified is self.identity or simplified in self._simplified_rules: continue @@ -284,13 +298,13 @@ def evaluate_while_simplifying(self, state: CollectionState, f) -> Tuple[Stardew self._simplified_rules.add(simplified) - if simplified(state) is self.complement.value: + if value is self.complement.value: return self, self.complement.value self._simplified = True self.other_rules = frozenset(self._simplified_rules) - return self, f(r(state) for r in self.other_rules) + return self, self.identity.value def __str__(self): return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" @@ -345,8 +359,8 @@ def simplify(self) -> StardewRule: return self - def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, frozenset(self.detailed_unique_rules)) + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, expected, frozenset(self.detailed_unique_rules).union(self.combinable_rules.values())) class Or(AggregatingStardewRule): @@ -355,7 +369,7 @@ class Or(AggregatingStardewRule): symbol = " | " def __call__(self, state: CollectionState) -> bool: - return self.evaluate_while_simplifying(state, any)[1] + return self.evaluate_while_simplifying(state)[1] def __or__(self, other): if other is true_ or other is false_: @@ -384,7 +398,7 @@ class And(AggregatingStardewRule): symbol = " & " def __call__(self, state: CollectionState) -> bool: - return self.evaluate_while_simplifying(state, all)[1] + return self.evaluate_while_simplifying(state)[1] def __and__(self, other): if other is true_ or other is false_: @@ -440,13 +454,7 @@ def __call__(self, state: CollectionState) -> bool: return True return False - def __repr__(self): - return f"Received {self.count} {repr(self.rules)}" - - def get_difficulty(self): - rules_sorted_by_difficulty = sorted(self.rules, key=lambda x: x.get_difficulty()) - easiest_n_rules = rules_sorted_by_difficulty[0:self.count] - return max(rule.get_difficulty() for rule in easiest_n_rules) + # TODO implement evaluate while simplifying def simplify(self): if self._simplified: @@ -457,8 +465,16 @@ def simplify(self): self._simplified = True return self - def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, self.rules) + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, expected, self.rules) + + def get_difficulty(self): + rules_sorted_by_difficulty = sorted(self.rules, key=lambda x: x.get_difficulty()) + easiest_n_rules = rules_sorted_by_difficulty[0:self.count] + return max(rule.get_difficulty() for rule in easiest_n_rules) + + def __repr__(self): + return f"Received {self.count} {repr(self.rules)}" class TotalReceived(StardewRule): @@ -491,14 +507,14 @@ def __call__(self, state: CollectionState) -> bool: return True return False - def __repr__(self): - return f"Received {self.count} {self.items}" + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, expected, [Received(i, self.player, 1) for i in self.items]) def get_difficulty(self): return self.count - def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, [Received(i, self.player, 1) for i in self.items]) + def __repr__(self): + return f"Received {self.count} {self.items}" @dataclass(frozen=True) @@ -546,7 +562,7 @@ def __repr__(self): def get_difficulty(self): return 1 - def explain(self, state: CollectionState) -> StardewRuleExplanation: + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: # FIXME this should be in core if self.resolution_hint == 'Location': spot = state.multiworld.get_location(self.spot, self.player) @@ -556,13 +572,13 @@ def explain(self, state: CollectionState) -> StardewRuleExplanation: spot = state.multiworld.get_entrance(self.spot, self.player) access_rule = spot.access_rule else: - # TODO check entrances rules - access_rule = None + spot = state.multiworld.get_region(self.spot, self.player) + access_rule = Or(*(Reach(e.name, "Entrance", self.player) for e in spot.entrances)) if not isinstance(access_rule, StardewRule): - return StardewRuleExplanation(self, state) + return StardewRuleExplanation(self, state, expected) - return StardewRuleExplanation(self, state, [access_rule]) + return StardewRuleExplanation(self, state, expected, [access_rule]) class Has(StardewRule): @@ -575,9 +591,22 @@ def __init__(self, item: str, other_rules: Dict[str, StardewRule]): self.other_rules = other_rules def __call__(self, state: CollectionState) -> bool: + # TODO eval & simplify self.simplify() return self.other_rules[self.item](state) + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self.other_rules[self.item].evaluate_while_simplifying(state) + + def simplify(self) -> StardewRule: + return self.other_rules[self.item].simplify() + + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: + return StardewRuleExplanation(self, state, expected, [self.other_rules[self.item]]) + + def get_difficulty(self): + return self.other_rules[self.item].get_difficulty() + 1 + def __str__(self): if self.item not in self.other_rules: return f"Has {self.item} -> {MISSING_ITEM}" @@ -588,18 +617,9 @@ def __repr__(self): return f"Has {self.item} -> {MISSING_ITEM}" return f"Has {self.item} -> {repr(self.other_rules[self.item])}" - def get_difficulty(self): - return self.other_rules[self.item].get_difficulty() + 1 - def __hash__(self): return hash(self.item) - def simplify(self) -> StardewRule: - return self.other_rules[self.item].simplify() - - def explain(self, state: CollectionState) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, [self.other_rules[self.item]]) - @dataclass(frozen=True) class HasProgressionPercent(CombinableStardewRule): diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index fc8aaaf1b2a3..328ef2b631b3 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -20,37 +20,37 @@ def test_sturgeon(self): self.multiworld.state.prog_items = {1: Counter()} sturgeon_rule = self.world.logic.has("Sturgeon") - self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state, expected=False)) summer = self.world.create_item("Summer") self.multiworld.state.collect(summer, event=False) - self.assertFalse(sturgeon_rule(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state, expected=False)) 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.assertFalse(sturgeon_rule(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state, expected=False)) fishing_level = self.world.create_item("Fishing Level") self.multiworld.state.collect(fishing_level, event=False) - self.assertFalse(sturgeon_rule(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state, expected=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.multiworld.state.collect(fishing_level, event=False) - self.assertTrue(sturgeon_rule(self.multiworld.state)) + self.assertTrue(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state)) self.remove(summer) - self.assertFalse(sturgeon_rule(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state, expected=False)) winter = self.world.create_item("Winter") self.multiworld.state.collect(winter, event=False) - self.assertTrue(sturgeon_rule(self.multiworld.state)) + self.assertTrue(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state)) self.remove(fishing_rod) - self.assertFalse(sturgeon_rule(self.multiworld.state)) + self.assertFalse(sturgeon_rule(self.multiworld.state), sturgeon_rule.explain(self.multiworld.state, expected=False)) def test_old_master_cannoli(self): self.multiworld.state.prog_items = {1: Counter()} @@ -299,30 +299,35 @@ def test_mine(self): 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.assertTrue(self.world.logic.mine.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) else: - self.assertFalse(self.world.logic.mine.can_mine_in_the_mines_floor_1_40()(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state, expected=False)) + rule = self.world.logic.mine.can_mine_in_the_mines_floor_41_80() if reachable_level > 1: - self.assertTrue(self.world.logic.mine.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) else: - self.assertFalse(self.world.logic.mine.can_mine_in_the_mines_floor_41_80()(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state, expected=False)) + rule = self.world.logic.mine.can_mine_in_the_mines_floor_81_120() if reachable_level > 2: - self.assertTrue(self.world.logic.mine.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) else: - self.assertFalse(self.world.logic.mine.can_mine_in_the_mines_floor_81_120()(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state, expected=False)) + rule = self.world.logic.mine.can_mine_in_the_skull_cavern() if reachable_level > 3: - self.assertTrue(self.world.logic.mine.can_mine_in_the_skull_cavern()(self.multiworld.state)) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) else: - self.assertFalse(self.world.logic.mine.can_mine_in_the_skull_cavern()(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state, expected=False)) + rule = self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern() if reachable_level > 4: - self.assertTrue(self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) else: - self.assertFalse(self.world.logic.ability.can_mine_perfectly_in_the_skull_cavern()(self.multiworld.state)) + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state, expected=False)) class TestMonstersanityProgressiveRules(SVTestBase): From a0dd9088099fc5e98ba73c1b4f0520dd9f224cc0 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 18:52:26 -0500 Subject: [PATCH 247/482] mark empty rules as simplified --- worlds/stardew_valley/stardew_rule.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 3c10afba49e5..df1016bce962 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -218,7 +218,6 @@ class AggregatingStardewRule(StardewRule, ABC): _left_to_simplify_rules: Optional[Iterable[StardewRule]] def __init__(self, *rules: StardewRule, _combinable_rules=None): - self._simplified = False self._simplified_rules = set() if _combinable_rules is None: @@ -226,6 +225,7 @@ def __init__(self, *rules: StardewRule, _combinable_rules=None): rules, _combinable_rules = CombinableStardewRule.split_rules(rules, self.combine) self.other_rules = tuple(rules) + self._simplified = not rules self.combinable_rules = _combinable_rules self.detailed_unique_rules = self.other_rules @@ -250,9 +250,6 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul if rule(state) is self.complement.value: return self, self.complement.value - if not self.other_rules: - return self, self.identity.value - if self._simplified: for rule in self.other_rules: if rule(state) is self.complement.value: From 0feb94cbaaf92d899212ba453e9ba7fe5691e3ad Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 19:00:04 -0500 Subject: [PATCH 248/482] remove comment --- worlds/stardew_valley/stardew_rule.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index df1016bce962..f1f2484c29d9 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -260,19 +260,6 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul if rule(state) is self.complement.value: return self, self.complement.value - # for rule in self._left_to_simplify_rules: - # simplified = rule.simplify() - # - # if simplified is self.identity or simplified in self._simplified_rules: - # continue - # self._simplified_rules.add(simplified) - # - # if simplified(state) is self.complement.value: - # return self.complement.value - # - # self._simplified = True - # return self.identity.value - if self._left_to_simplify_rules is None: self.other_rules = frozenset(self.other_rules) if self.complement in self.other_rules: From 1b7132ca877ef7e04ed8f16ff9bae09314eaf95d Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 21:55:43 -0500 Subject: [PATCH 249/482] remove unused simplify --- worlds/stardew_valley/rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 9c4108f61f0b..579f2a606db8 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -859,9 +859,9 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), logic.has("Fire Quartz")) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), - (logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)).simplify()) + logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), - (logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)).simplify()) + logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)) # MultiWorldRules.add_rule(multiworld.get_location("Analyze: Lantern", player),) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Tendrils", player), logic.region.can_reach(Region.farm)) From 3aec50888e024f1d1f32421a4cfe299e22dd9612 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 26 Nov 2023 22:36:03 -0500 Subject: [PATCH 250/482] add comments to clarify the algo --- worlds/stardew_valley/stardew_rule.py | 18 +++++++++++++++++- worlds/stardew_valley/test/TestRules.py | 1 - 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index f1f2484c29d9..37e0cb3ea685 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -246,20 +246,27 @@ def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> Combin def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: # TODO test if inverting would speed up - for rule in chain(self.combinable_rules.values()): + # Combinable rules are considered already simplified, so we evaluate them right away. + for rule in self.combinable_rules.values(): if rule(state) is self.complement.value: return self, self.complement.value if self._simplified: + # The expression is fully simplified, so we can only evaluate. for rule in self.other_rules: if rule(state) is self.complement.value: return self, self.complement.value return self, self.identity.value + + # Evaluating what has already been simplified. + # The assumption is that the rules that used to evaluate to complement might complement again, so we can leave early. elif self._simplified_rules: for rule in self._simplified_rules: if rule(state) is self.complement.value: return self, self.complement.value + # If the iterator is None, it means we have not start simplifying. + # Otherwise, we will continue simplification where we left. if self._left_to_simplify_rules is None: self.other_rules = frozenset(self.other_rules) if self.complement in self.other_rules: @@ -269,25 +276,32 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul self._left_to_simplify_rules = iter(self.other_rules) + # Start simplification where we left. for rule in self._left_to_simplify_rules: simplified, value = rule.evaluate_while_simplifying(state) + # Identity is removed from the resulting simplification. if simplified is self.identity or simplified in self._simplified_rules: continue + # If we find a complement here, we know the rule will always resolve to its value. + # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. if simplified is self.complement: self._simplified = True self.other_rules = (self.complement,) return self.complement, self.complement.value + # Keep the simplified rule to be reused. self._simplified_rules.add(simplified) + # Now we use the value, to exit early if it evaluates to the complement. if value is self.complement.value: return self, self.complement.value self._simplified = True self.other_rules = frozenset(self._simplified_rules) + # The whole rule has been simplified and evaluated without finding complement. return self, self.identity.value def __str__(self): @@ -300,6 +314,8 @@ def __eq__(self, other): return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.other_rules == self.other_rules def __hash__(self): + # TODO since other_rules will be changed after simplification, a simplified rule will have a different hashcode than its original. + # Ideally, two rules with the same simplification would be equal... return hash((self.combinable_rules, self.other_rules)) def simplify(self) -> StardewRule: diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 328ef2b631b3..d78659680723 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -774,6 +774,5 @@ class TestVanillaSkillLogicSimplification(SVTestBase): def test_skill_logic_has_level_only_uses_one_has_progression_percent(self): rule = self.multiworld.worlds[1].logic.skill.has_level("Farming", 8) - print(rule) self.assertEqual(1, sum(1 for i in rule.rules_iterable if type(i) == HasProgressionPercent)) self.assertIsNotNone(rule.combinable_rules) From 8193d911e7fa98512571b2c84eb47677110ace74 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 27 Nov 2023 08:59:07 -0500 Subject: [PATCH 251/482] another comment --- worlds/stardew_valley/stardew_rule.py | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 37e0cb3ea685..cc9d09f321a5 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -244,6 +244,7 @@ def detailed_rules_iterable(self): def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError + # The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: # TODO test if inverting would speed up # Combinable rules are considered already simplified, so we evaluate them right away. From 603a6290fd5c028490abb0a449b7641fd1167106 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 28 Nov 2023 08:49:22 -0500 Subject: [PATCH 252/482] fix Set changed size issue --- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/stardew_rule.py | 21 ++++++++++++------- .../test/performance/TestPerformance.py | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 579f2a606db8..1f7618adf6f7 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -124,7 +124,7 @@ def set_bundle_rules(bundle_rooms: List[BundleRoom], logic: StardewLogic, multiw room_rules = [] for bundle in bundle_room.bundles: location = multiworld.get_location(bundle.name, player) - bundle_rules = logic.bundle.can_complete_bundle(bundle).simplify() + bundle_rules = logic.bundle.can_complete_bundle(bundle) room_rules.append(bundle_rules) MultiWorldRules.set_rule(location, bundle_rules) if bundle_room.name == CCRoom.abandoned_joja_mart: diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index cc9d09f321a5..a5ccd28e312b 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -4,7 +4,7 @@ from dataclasses import dataclass, field from functools import cached_property from itertools import chain -from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional +from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Optional from frozendict import frozendict @@ -214,11 +214,11 @@ class AggregatingStardewRule(StardewRule, ABC): detailed_unique_rules: Union[Iterable[StardewRule], Sized] _simplified: bool - _simplified_rules: Set[StardewRule] + _simplified_rules: frozenset[StardewRule] _left_to_simplify_rules: Optional[Iterable[StardewRule]] def __init__(self, *rules: StardewRule, _combinable_rules=None): - self._simplified_rules = set() + self._simplified_rules = frozenset() if _combinable_rules is None: assert rules, f"Can't create an aggregating condition without rules" @@ -277,6 +277,7 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul self._left_to_simplify_rules = iter(self.other_rules) + newly_simplified_rules = set() # Start simplification where we left. for rule in self._left_to_simplify_rules: simplified, value = rule.evaluate_while_simplifying(state) @@ -293,14 +294,17 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul return self.complement, self.complement.value # Keep the simplified rule to be reused. - self._simplified_rules.add(simplified) + newly_simplified_rules.add(simplified) # Now we use the value, to exit early if it evaluates to the complement. if value is self.complement.value: + # FIXME I hate that this has to be a frozenset... But otherwise we see errors where Set changed size during iteration. + # This will need more troubleshooting. + self._simplified_rules |= newly_simplified_rules return self, self.complement.value self._simplified = True - self.other_rules = frozenset(self._simplified_rules) + self.other_rules = frozenset(self._simplified_rules | newly_simplified_rules) # The whole rule has been simplified and evaluated without finding complement. return self, self.identity.value @@ -333,6 +337,7 @@ def simplify(self) -> StardewRule: self._left_to_simplify_rules = iter(self.other_rules) + newly_simplified_rules = set() for rule in self._left_to_simplify_rules: simplified = rule.simplify() @@ -341,13 +346,13 @@ def simplify(self) -> StardewRule: if simplified is self.complement: self._simplified = True - self._simplified_rules = {self.complement} + self._simplified_rules = frozenset((self.complement,)) return self.complement - self._simplified_rules.add(simplified) + newly_simplified_rules.add(simplified) self._simplified = True - self.other_rules = frozenset(self._simplified_rules) + self.other_rules = frozenset(self._simplified_rules | newly_simplified_rules) if not self.other_rules and not self.combinable_rules: return self.identity diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index d390fe1d1878..cfbeaefddef2 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -10,7 +10,7 @@ from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options number_generations = 25 -default_seeds = [10613921641417078811] * number_generations +default_seeds = [87876703343494157696] * number_generations acceptable_deviation = 4 From d21d44dc3265a4bfa85e6dd6244df8a925b65422 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 30 Nov 2023 12:14:31 -0500 Subject: [PATCH 253/482] - Cherry picked recipe changes from SVE --- worlds/stardew_valley/data/locations.csv | 180 +++++++++++------------ worlds/stardew_valley/rules.py | 4 +- worlds/stardew_valley/test/TestRules.py | 2 +- 3 files changed, 93 insertions(+), 93 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 8a277cf88dc0..041fb0f4feb2 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1837,86 +1837,86 @@ id,region,name,tags,mod_name 3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", 3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", 3280,Kitchen,Cook Vegetable Medley,"COOKSANITY", -3301,Farm,Learn Recipe Algae Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3302,The Queen of Sauce,Learn Recipe Artichoke Dip,"CHEFSANITY,CHEFSANITY_QOS", -3303,Farm,Learn Recipe Autumn's Bounty,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3304,The Queen of Sauce,Learn Recipe Baked Fish,"CHEFSANITY,CHEFSANITY_QOS", -3305,Farm,Learn Recipe Banana Pudding,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3306,Farm,Learn Recipe Bean Hotpot,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3307,The Queen of Sauce,Learn Recipe Blackberry Cobbler,"CHEFSANITY,CHEFSANITY_QOS", -3308,Farm,Learn Recipe Blueberry Tart,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3309,The Queen of Sauce,Learn Recipe Bread,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -3310,The Queen of Sauce,Learn Recipe Bruschetta,"CHEFSANITY,CHEFSANITY_QOS", -3311,The Queen of Sauce,Learn Recipe Carp Surprise,"CHEFSANITY,CHEFSANITY_QOS", -3312,Farm,Learn Recipe Cheese Cauliflower,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3313,The Queen of Sauce,Learn Recipe Chocolate Cake,"CHEFSANITY,CHEFSANITY_QOS", -3314,Farm,Learn Recipe Chowder,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3315,The Queen of Sauce,Learn Recipe Coleslaw,"CHEFSANITY,CHEFSANITY_QOS", -3316,The Queen of Sauce,Learn Recipe Complete Breakfast,"CHEFSANITY,CHEFSANITY_QOS", -3317,Farm,Learn Recipe Cookies,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3318,The Queen of Sauce,Learn Recipe Crab Cakes,"CHEFSANITY,CHEFSANITY_QOS", -3319,The Queen of Sauce,Learn Recipe Cranberry Candy,"CHEFSANITY,CHEFSANITY_QOS", -3320,Farm,Learn Recipe Cranberry Sauce,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3321,Farm,Learn Recipe Crispy Bass,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3322,Farm,Learn Recipe Dish O' The Sea,"CHEFSANITY,CHEFSANITY_SKILL", -3323,Farm,Learn Recipe Eggplant Parmesan,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3324,Farm,Learn Recipe Escargot,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3325,Farm,Learn Recipe Farmer's Lunch,"CHEFSANITY,CHEFSANITY_SKILL", -3326,The Queen of Sauce,Learn Recipe Fiddlehead Risotto,"CHEFSANITY,CHEFSANITY_QOS", -3327,Farm,Learn Recipe Fish Stew,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3328,Farm,Learn Recipe Fish Taco,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3329,Farm,Learn Recipe Fried Calamari,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3330,Farm,Learn Recipe Fried Eel,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3331,Farm,Learn Recipe Fried Egg,"CHEFSANITY_STARTER", -3332,Farm,Learn Recipe Fried Mushroom,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3333,The Queen of Sauce,Learn Recipe Fruit Salad,"CHEFSANITY,CHEFSANITY_QOS", -3334,Farm,Learn Recipe Ginger Ale,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3335,The Queen of Sauce,Learn Recipe Glazed Yams,"CHEFSANITY,CHEFSANITY_QOS", -3336,The Queen of Sauce,Learn Recipe Hashbrowns,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3337,Farm,Learn Recipe Ice Cream,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3338,The Queen of Sauce,Learn Recipe Lobster Bisque,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -3339,The Queen of Sauce,Learn Recipe Lucky Lunch,"CHEFSANITY,CHEFSANITY_QOS", -3340,The Queen of Sauce,Learn Recipe Maki Roll,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3341,Farm,Learn Recipe Mango Sticky Rice,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3342,The Queen of Sauce,Learn Recipe Maple Bar,"CHEFSANITY,CHEFSANITY_QOS", -3343,Farm,Learn Recipe Miner's Treat,"CHEFSANITY,CHEFSANITY_SKILL", -3344,The Queen of Sauce,Learn Recipe Omelet,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3345,Farm,Learn Recipe Pale Broth,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3346,The Queen of Sauce,Learn Recipe Pancakes,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3347,Farm,Learn Recipe Parsnip Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3348,Farm,Learn Recipe Pepper Poppers,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3349,The Queen of Sauce,Learn Recipe Pink Cake,"CHEFSANITY,CHEFSANITY_QOS", -3350,The Queen of Sauce,Learn Recipe Pizza,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3351,The Queen of Sauce,Learn Recipe Plum Pudding,"CHEFSANITY,CHEFSANITY_QOS", -3352,Farm,Learn Recipe Poi,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3353,The Queen of Sauce,Learn Recipe Poppyseed Muffin,"CHEFSANITY,CHEFSANITY_QOS", -3354,The Queen of Sauce,Learn Recipe Pumpkin Pie,"CHEFSANITY,CHEFSANITY_QOS", -3355,Farm,Learn Recipe Pumpkin Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3356,The Queen of Sauce,Learn Recipe Radish Salad,"CHEFSANITY,CHEFSANITY_QOS", -3357,Farm,Learn Recipe Red Plate,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3358,Farm,Learn Recipe Rhubarb Pie,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3359,Farm,Learn Recipe Rice Pudding,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3360,The Queen of Sauce,Learn Recipe Roasted Hazelnuts,"CHEFSANITY,CHEFSANITY_QOS", -3361,Farm,Learn Recipe Roots Platter,"CHEFSANITY,CHEFSANITY_SKILL", -3362,Farm,Learn Recipe Salad,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3363,Farm,Learn Recipe Salmon Dinner,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3364,Farm,Learn Recipe Sashimi,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3365,Farm,Learn Recipe Seafoam Pudding,"CHEFSANITY,CHEFSANITY_SKILL", -3366,The Queen of Sauce,Learn Recipe Shrimp Cocktail,"CHEFSANITY,CHEFSANITY_QOS", -3367,Farm,Learn Recipe Spaghetti,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3368,Farm,Learn Recipe Spicy Eel,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3369,Farm,Learn Recipe Squid Ink Ravioli,"CHEFSANITY,CHEFSANITY_SKILL", -3370,The Queen of Sauce,Learn Recipe Stir Fry,"CHEFSANITY,CHEFSANITY_QOS", -3371,Farm,Learn Recipe Strange Bun,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3372,Farm,Learn Recipe Stuffing,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3373,Farm,Learn Recipe Super Meal,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3374,Farm,Learn Recipe Survival Burger,"CHEFSANITY,CHEFSANITY_SKILL", -3375,Farm,Learn Recipe Tom Kha Soup,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3376,The Queen of Sauce,Learn Recipe Tortilla,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3377,Saloon,Learn Recipe Triple Shot Espresso,"CHEFSANITY,CHEFSANITY_PURCHASE", -3378,Island Resort,Learn Recipe Tropical Curry,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3379,The Queen of Sauce,Learn Recipe Trout Soup,"CHEFSANITY,CHEFSANITY_QOS", -3380,Farm,Learn Recipe Vegetable Medley,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3331,Farm,Fried Egg Recipe,"CHEFSANITY_STARTER", +3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3401,Farm,Craft Cherry Bomb,"CRAFTSANITY", 3402,Farm,Craft Bomb,"CRAFTSANITY", 3403,Farm,Craft Mega Bomb,"CRAFTSANITY", @@ -2537,16 +2537,16 @@ id,region,name,tags,mod_name 7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded 7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded 7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded -7601,Bear Shop,Learn Recipe Baked Berry Oatmeal,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7602,Bear Shop,Learn Recipe Flower Cookie,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7603,Saloon,Learn Recipe Big Bark Burger,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7604,Adventurer's Guild,Learn Recipe Frog Legs,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7605,Saloon,Learn Recipe Glazed Butterfish,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7606,Saloon,Learn Recipe Mixed Berry Pie,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7607,Adventurer's Guild,Learn Recipe Mushroom Berry Rice,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7608,Adventurer's Guild,Learn Recipe Seaweed Salad,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7609,Sewer,Learn Recipe Void Delight,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7610,Sewer,Learn Recipe Void Salmon Sushi,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7651,Alesia Shop,Purchase Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded 7652,Issac Shop,Purchase Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7653,Issac Shop,Purchase Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 1f7618adf6f7..e678bd8a3e3a 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -729,11 +729,11 @@ def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, mul if chefsanity_option == Chefsanity.option_none: return - chefsanity_prefix = "Learn Recipe " + chefsanity_suffix = " Recipe" for location in locations.locations_by_tag[LocationTags.CHEFSANITY]: if location.name not in all_location_names: continue - recipe_name = location.name[len(chefsanity_prefix):] + recipe_name = location.name[:-len(chefsanity_suffix)] recipe = all_cooking_recipes_by_name[recipe_name] learn_rule = logic.cooking.can_learn_recipe(recipe.source) MultiWorldRules.set_rule(multiworld.get_location(location.name, player), learn_rule) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index d78659680723..0dc5706d9a6d 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -411,7 +411,7 @@ def test_can_learn_qos_recipe(self): self.assertTrue(rule(self.multiworld.state)) def test_get_chefsanity_check_recipe(self): - location = "Learn Recipe Radish Salad" + location = "Radish Salad Recipe" rule = self.world.logic.region.can_reach_location(location) self.assertFalse(rule(self.multiworld.state)) From f2e5b38e62fc5b5b8a88f83baf35feb4cb3f6faa Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 30 Nov 2023 00:13:34 -0500 Subject: [PATCH 254/482] add tests yet to be fixed --- worlds/stardew_valley/stardew_rule.py | 9 +- .../test/TestLogicSimplification.py | 78 ------ worlds/stardew_valley/test/TestStardewRule.py | 252 ++++++++++++++++++ 3 files changed, 257 insertions(+), 82 deletions(-) delete mode 100644 worlds/stardew_valley/test/TestLogicSimplification.py create mode 100644 worlds/stardew_valley/test/TestStardewRule.py diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index a5ccd28e312b..a10456c2830a 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -261,10 +261,9 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul # Evaluating what has already been simplified. # The assumption is that the rules that used to evaluate to complement might complement again, so we can leave early. - elif self._simplified_rules: - for rule in self._simplified_rules: - if rule(state) is self.complement.value: - return self, self.complement.value + for rule in self._simplified_rules: + if rule(state) is self.complement.value: + return self, self.complement.value # If the iterator is None, it means we have not start simplifying. # Otherwise, we will continue simplification where we left. @@ -272,6 +271,7 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul self.other_rules = frozenset(self.other_rules) if self.complement in self.other_rules: self._simplified = True + self.combinable_rules = frozendict() self.other_rules = (self.complement,) return self.complement, self.complement.value @@ -290,6 +290,7 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. if simplified is self.complement: self._simplified = True + self.combinable_rules = frozendict() self.other_rules = (self.complement,) return self.complement, self.complement.value diff --git a/worlds/stardew_valley/test/TestLogicSimplification.py b/worlds/stardew_valley/test/TestLogicSimplification.py deleted file mode 100644 index 56cb10808e78..000000000000 --- a/worlds/stardew_valley/test/TestLogicSimplification.py +++ /dev/null @@ -1,78 +0,0 @@ -import unittest -from unittest import skip - -from ..stardew_rule import Received, Has, False_, And, Or, True_, HasProgressionPercent - - -class TestSimplification(unittest.TestCase): - def test_simplify_true_in_and(self): - rules = { - "Wood": True_(), - "Rock": True_(), - } - summer = Received("Summer", 0, 1) - self.assertEqual(summer, (Has("Wood", rules) & summer & Has("Rock", rules)).simplify()) - - def test_simplify_false_in_or(self): - rules = { - "Wood": False_(), - "Rock": False_(), - } - summer = Received("Summer", 0, 1) - self.assertEqual(summer, (Has("Wood", rules) | summer | Has("Rock", rules)).simplify()) - - def test_simplify_and_in_and(self): - rule = And(Received('Summer', 0, 1), Received('Fall', 0, 1)) & And(Received('Winter', 0, 1), Received('Spring', 0, 1)) - self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) - - @skip("This feature has been disabled and that seems to save time") - 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))) - self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) - - def test_simplify_or_in_or(self): - rule = Or(Received('Summer', 0, 1), Received('Fall', 0, 1)) | Or(Received('Winter', 0, 1), Received('Spring', 0, 1)) - self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) - - @skip("This feature has been disabled and that seems to save time") - 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))) - self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) - - def test_simplify_true_in_or(self): - rule = Or(True_(), Received('Summer', 0, 1)) - self.assertEqual(True_(), rule.simplify()) - - def test_simplify_false_in_and(self): - rule = And(False_(), Received('Summer', 0, 1)) - self.assertEqual(False_(), rule.simplify()) - - -class TestHasProgressionPercentSimplification(unittest.TestCase): - def test_has_progression_percent_and_uses_max(self): - rule = HasProgressionPercent(1, 20) & HasProgressionPercent(1, 10) - self.assertEqual(rule, HasProgressionPercent(1, 20)) - - def test_has_progression_percent_or_uses_min(self): - rule = HasProgressionPercent(1, 20) | HasProgressionPercent(1, 10) - self.assertEqual(rule, HasProgressionPercent(1, 10)) - - def test_and_between_progression_percent_and_other_progression_percent_uses_max(self): - cases = [ - And(HasProgressionPercent(1, 10)) & HasProgressionPercent(1, 20), - HasProgressionPercent(1, 10) & And(HasProgressionPercent(1, 20)), - And(HasProgressionPercent(1, 20)) & And(HasProgressionPercent(1, 10)), - ] - for i, case in enumerate(cases): - with self.subTest(f"{i} {repr(case)}"): - self.assertEqual(case, And(HasProgressionPercent(1, 20))) - - def test_or_between_progression_percent_and_other_progression_percent_uses_max(self): - cases = [ - Or(HasProgressionPercent(1, 10)) | HasProgressionPercent(1, 20), - HasProgressionPercent(1, 10) | Or(HasProgressionPercent(1, 20)), - Or(HasProgressionPercent(1, 20)) | Or(HasProgressionPercent(1, 10)) - ] - for i, case in enumerate(cases): - with self.subTest(f"{i} {repr(case)}"): - self.assertEqual(case, Or(HasProgressionPercent(1, 10))) diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py new file mode 100644 index 000000000000..a95bfe22c6d3 --- /dev/null +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -0,0 +1,252 @@ +import unittest +from unittest import skip +from unittest.mock import MagicMock, Mock + +from ..stardew_rule import Received, Has, False_, And, Or, True_, HasProgressionPercent, false_, true_ + + +class TestSimplification(unittest.TestCase): + def test_simplify_true_in_and(self): + rules = { + "Wood": True_(), + "Rock": True_(), + } + summer = Received("Summer", 0, 1) + self.assertEqual(summer, (Has("Wood", rules) & summer & Has("Rock", rules)).simplify()) + + def test_simplify_false_in_or(self): + rules = { + "Wood": False_(), + "Rock": False_(), + } + summer = Received("Summer", 0, 1) + self.assertEqual(summer, (Has("Wood", rules) | summer | Has("Rock", rules)).simplify()) + + def test_simplify_and_in_and(self): + rule = And(Received('Summer', 0, 1), Received('Fall', 0, 1)) & And(Received('Winter', 0, 1), Received('Spring', 0, 1)) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + + @skip("This feature has been disabled and that seems to save time") + 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))) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) + + def test_simplify_or_in_or(self): + rule = Or(Received('Summer', 0, 1), Received('Fall', 0, 1)) | Or(Received('Winter', 0, 1), Received('Spring', 0, 1)) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + + @skip("This feature has been disabled and that seems to save time") + 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))) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) + + def test_simplify_true_in_or(self): + rule = Or(True_(), Received('Summer', 0, 1)) + self.assertEqual(True_(), rule.simplify()) + + def test_simplify_false_in_and(self): + rule = And(False_(), Received('Summer', 0, 1)) + self.assertEqual(False_(), rule.simplify()) + + +class TestHasProgressionPercentSimplification(unittest.TestCase): + def test_has_progression_percent_and_uses_max(self): + rule = HasProgressionPercent(1, 20) & HasProgressionPercent(1, 10) + self.assertEqual(rule, HasProgressionPercent(1, 20)) + + def test_has_progression_percent_or_uses_min(self): + rule = HasProgressionPercent(1, 20) | HasProgressionPercent(1, 10) + self.assertEqual(rule, HasProgressionPercent(1, 10)) + + def test_and_between_progression_percent_and_other_progression_percent_uses_max(self): + cases = [ + And(HasProgressionPercent(1, 10)) & HasProgressionPercent(1, 20), + HasProgressionPercent(1, 10) & And(HasProgressionPercent(1, 20)), + And(HasProgressionPercent(1, 20)) & And(HasProgressionPercent(1, 10)), + ] + for i, case in enumerate(cases): + with self.subTest(f"{i} {repr(case)}"): + self.assertEqual(case, And(HasProgressionPercent(1, 20))) + + def test_or_between_progression_percent_and_other_progression_percent_uses_max(self): + cases = [ + Or(HasProgressionPercent(1, 10)) | HasProgressionPercent(1, 20), + HasProgressionPercent(1, 10) | Or(HasProgressionPercent(1, 20)), + Or(HasProgressionPercent(1, 20)) | Or(HasProgressionPercent(1, 10)) + ] + for i, case in enumerate(cases): + with self.subTest(f"{i} {repr(case)}"): + self.assertEqual(case, Or(HasProgressionPercent(1, 10))) + + +class TestEvaluateWhileSimplifying(unittest.TestCase): + def test_propagate_evaluate_while_simplifying(self): + expected_result = True + collection_state = MagicMock() + other_rule = MagicMock() + other_rule.evaluate_while_simplifying = Mock(return_value=(other_rule, expected_result)) + rule = And(Or(other_rule)) + + _, actual_result = rule.evaluate_while_simplifying(collection_state) + + other_rule.evaluate_while_simplifying.assert_called_with(collection_state) + self.assertEqual(expected_result, actual_result) + + def test_return_complement_when_its_found(self): + expected_simplified = false_ + expected_result = False + collection_state = MagicMock() + rule = And(expected_simplified) + + actual_simplified, actual_result = rule.evaluate_while_simplifying(collection_state) + + self.assertEqual(expected_result, actual_result) + self.assertEqual(expected_simplified, actual_simplified) + + def test_short_circuit_when_complement_found(self): + collection_state = MagicMock() + other_rule = MagicMock() + rule = Or(true_, ) + + rule.evaluate_while_simplifying(collection_state) + + other_rule.evaluate_while_simplifying.assert_not_called() + + def test_short_circuit_when_combinable_rules_is_false(self): + collection_state = MagicMock() + other_rule = MagicMock() + rule = And(HasProgressionPercent(1, 10), other_rule) + + rule.evaluate_while_simplifying(collection_state) + + other_rule.evaluate_while_simplifying.assert_not_called() + + def test_identity_is_removed_from_other_rules(self): + collection_state = MagicMock() + rule = Or(false_, HasProgressionPercent(1, 10)) + + rule.evaluate_while_simplifying(collection_state) + + self.assertEqual(0, len(rule.other_rules)) + + def test_complement_replaces_combinable_rules(self): + collection_state = MagicMock() + rule = Or(HasProgressionPercent(1, 10), true_) + + rule.evaluate_while_simplifying(collection_state) + + self.assertEqual(0, len(rule.combinable_rules)) + + def test_simplifying_to_complement_propagates_complement(self): + expected_simplified = true_ + expected_result = True + collection_state = MagicMock() + rule = Or(Or(expected_simplified), HasProgressionPercent(1, 10)) + + actual_simplified, actual_result = rule.evaluate_while_simplifying(collection_state) + + self.assertEqual(expected_result, actual_result) + self.assertEqual(expected_simplified, actual_simplified) + self.assertEqual(0, len(rule.combinable_rules)) + + def test_already_simplified_rules_are_not_simplified_again(self): + collection_state = MagicMock() + other_rule = MagicMock() + other_rule.evaluate_while_simplifying = Mock(return_value=(other_rule, False)) + rule = Or(other_rule, HasProgressionPercent(1, 10)) + + rule.evaluate_while_simplifying(collection_state) + other_rule.assert_not_called() + other_rule.evaluate_while_simplifying.reset_mock() + + rule.evaluate_while_simplifying(collection_state) + other_rule.assert_called_with(collection_state) + other_rule.evaluate_while_simplifying.assert_not_called() + + def test_continue_simplification_after_short_circuited(self): + collection_state = MagicMock() + a_rule = MagicMock() + a_rule.evaluate_while_simplifying = Mock(return_value=(a_rule, False)) + another_rule = MagicMock() + another_rule.evaluate_while_simplifying = Mock(return_value=(another_rule, False)) + rule = And(a_rule, another_rule) + + rule.evaluate_while_simplifying(collection_state) + # This test is completely messed up because sets are used internally and order of the rules cannot be ensured. + not_yet_simplified, already_simplified = (another_rule, a_rule) if a_rule.evaluate_while_simplifying.called else (a_rule, another_rule) + not_yet_simplified.evaluate_while_simplifying.assert_not_called() + already_simplified.return_value = True + + rule.evaluate_while_simplifying(collection_state) + not_yet_simplified.evaluate_while_simplifying.assert_called_with(collection_state) + + +@skip("Those two tests validate a bug that has yet to be fixed.") +class TestEvaluateWhileSimplifyingDoubleCalls(unittest.TestCase): + """ + So, there is a situation where a rule kind of calls itself while it's being evaluated, because its evaluation triggers a region cache refresh. + + The region cache check every entrance, so if a rule is also used in an entrances, it can be reevaluated. + """ + + def test_reentry_in_the_first_rule_being_evaluated_does_check_the_rule(self): + collection_state = MagicMock() + internal_rule = MagicMock() + rule = Or(internal_rule) + + called_once = False + internal_call_result = None + + def first_call_to_internal_rule(state): + nonlocal internal_call_result + nonlocal called_once + if called_once: + return internal_rule, True + called_once = True + + _, internal_call_result = rule.evaluate_while_simplifying(state) + internal_rule.evaluate_while_simplifying = Mock(return_value=(internal_rule, True)) + return internal_rule, True + + internal_rule.evaluate_while_simplifying = first_call_to_internal_rule + + rule.evaluate_while_simplifying(collection_state) + + self.assertTrue(called_once) + self.assertTrue(internal_call_result) + + def test_reentry_in_already_simplified_rule_does_not_steal_rule_to_simplified_from_parent_call(self): + collection_state = MagicMock() + an_internal_rule = MagicMock() + an_internal_rule.evaluate_while_simplifying = Mock(return_value=(an_internal_rule, True)) + another_internal_rule = MagicMock() + another_internal_rule.evaluate_while_simplifying = Mock(return_value=(another_internal_rule, True)) + rule = Or(an_internal_rule, another_internal_rule) + + rule.evaluate_while_simplifying(collection_state) + # This test is completely messed up because sets are used internally and order of the rules cannot be ensured. + if an_internal_rule.evaluate_while_simplifying.called: + not_yet_simplified, already_simplified = another_internal_rule, an_internal_rule + else: + not_yet_simplified, already_simplified = an_internal_rule, another_internal_rule + + called_once = False + internal_call_result = None + + def call_to_already_simplified(state): + nonlocal internal_call_result + nonlocal called_once + if called_once: + return False + called_once = True + + _, internal_call_result = rule.evaluate_while_simplifying(state) + return False + + already_simplified.side_effect = call_to_already_simplified + + _, actual_result = rule.evaluate_while_simplifying(collection_state) + + self.assertTrue(called_once) + self.assertTrue(internal_call_result) + self.assertTrue(actual_result) From 6b11856eea32708f73c1406a571b020cf3324859 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 30 Nov 2023 00:16:25 -0500 Subject: [PATCH 255/482] rename for clarity --- worlds/stardew_valley/test/TestStardewRule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index a95bfe22c6d3..88519a27bb41 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -189,7 +189,7 @@ class TestEvaluateWhileSimplifyingDoubleCalls(unittest.TestCase): The region cache check every entrance, so if a rule is also used in an entrances, it can be reevaluated. """ - def test_reentry_in_the_first_rule_being_evaluated_does_check_the_rule(self): + def test_nested_call_in_the_internal_rule_being_evaluated_does_check_the_internal_rule(self): collection_state = MagicMock() internal_rule = MagicMock() rule = Or(internal_rule) @@ -215,7 +215,7 @@ def first_call_to_internal_rule(state): self.assertTrue(called_once) self.assertTrue(internal_call_result) - def test_reentry_in_already_simplified_rule_does_not_steal_rule_to_simplified_from_parent_call(self): + def test_nested_call_to_already_simplified_rule_does_not_steal_rule_to_simplified_from_parent_call(self): collection_state = MagicMock() an_internal_rule = MagicMock() an_internal_rule.evaluate_while_simplifying = Mock(return_value=(an_internal_rule, True)) From 60a3d17a9cfa2648d2ab480a90e2b349240f05cf Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 30 Nov 2023 00:18:31 -0500 Subject: [PATCH 256/482] add example to explain nested calls --- worlds/stardew_valley/test/TestStardewRule.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index 88519a27bb41..f6e3b77a20f5 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -187,6 +187,10 @@ class TestEvaluateWhileSimplifyingDoubleCalls(unittest.TestCase): So, there is a situation where a rule kind of calls itself while it's being evaluated, because its evaluation triggers a region cache refresh. The region cache check every entrance, so if a rule is also used in an entrances, it can be reevaluated. + + For instance, but not limited to + Has Melon -> (Farm & Summer) | Greenhouse -> Greenhouse triggers an update of the region cache + -> Every entrance are evaluated, for instance "can start farming" -> Look that any crop can be grown (calls Has Melon). """ def test_nested_call_in_the_internal_rule_being_evaluated_does_check_the_internal_rule(self): From 748831093b62e32c7c1147fd25c8b49aec263f36 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 30 Nov 2023 21:10:17 -0500 Subject: [PATCH 257/482] - Shorten region rules for always-accessible regions --- worlds/stardew_valley/logic/region_logic.py | 27 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 86bf5b35b783..12697e760bd0 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -2,7 +2,23 @@ from Utils import cache_self1 from .base_logic import BaseLogic, BaseLogicMixin -from ..stardew_rule import StardewRule, And, Or, Reach, Count +from ..options import EntranceRandomization +from ..stardew_rule import StardewRule, And, Or, Reach, Count, True_ +from ..strings.region_names import Region + +main_outside_area = {Region.menu, Region.stardew_valley, Region.farm_house, Region.farm, Region.town, Region.beach, Region.mountain, Region.forest, + Region.bus_stop, Region.backwoods, Region.bus_tunnel, Region.tunnel_entrance} +always_accessible_regions_without_er = {*main_outside_area, Region.community_center, Region.pantry, Region.crafts_room, Region.fish_tank, Region.boiler_room, + Region.vault, Region.bulletin_board, Region.mines, Region.hospital, Region.carpenter, Region.alex_house, + Region.elliott_house, Region.ranch, Region.farm_cave, Region.wizard_tower, Region.tent, Region.pierre_store, + Region.saloon, Region.blacksmith, Region.trailer, Region.museum, Region.mayor_house, Region.haley_house, + Region.sam_house, Region.jojamart, Region.fish_shop} + +always_regions_by_setting = {EntranceRandomization.option_disabled: always_accessible_regions_without_er, + EntranceRandomization.option_pelican_town: always_accessible_regions_without_er, + EntranceRandomization.option_non_progression: always_accessible_regions_without_er, + EntranceRandomization.option_buildings: main_outside_area, + EntranceRandomization.option_chaos: always_accessible_regions_without_er} class RegionLogicMixin(BaseLogicMixin): @@ -15,6 +31,9 @@ class RegionLogic(BaseLogic[RegionLogicMixin]): @cache_self1 def can_reach(self, region_name: str) -> StardewRule: + if region_name in always_regions_by_setting[self.options.entrance_randomization]: + return True_() + return Reach(region_name, "Region", self.player) @cache_self1 @@ -37,6 +56,6 @@ def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule def can_reach_location(self, location_name: str) -> StardewRule: return Reach(location_name, "Location", self.player) - @cache_self1 - def can_reach_entrance(self, entrance_name: str) -> StardewRule: - return Reach(entrance_name, "Entrance", self.player) + # @cache_self1 + # def can_reach_entrance(self, entrance_name: str) -> StardewRule: + # return Reach(entrance_name, "Entrance", self.player) From 95e1698e85e4d508f81d98940be6258e666ad074 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 22:06:47 -0500 Subject: [PATCH 258/482] fix tests --- worlds/stardew_valley/test/mods/TestMods.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index de4f5a5c76a4..b020328976c9 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -1,18 +1,18 @@ -from typing import List, Union -import unittest import random import sys +import unittest +from typing import List, Union from BaseClasses import MultiWorld -from ...mods.mod_data import all_mods from .. import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_without_mods from ..TestOptions import basic_checks from ... import items, Group, ItemClassification -from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions from ...items import item_table, items_by_group from ...locations import location_table +from ...mods.mod_data import all_mods from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems, Chefsanity, \ Shipsanity, Craftsanity +from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld): @@ -41,7 +41,7 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi for option in EntranceRandomization.options: for mod in all_mods: with self.subTest(f"entrance_randomization: {option}, Mod: {mod}"): - multiworld = setup_solo_multiworld({EntranceRandomization.internal_name: option, Mods: mod}) + multiworld = setup_solo_multiworld({EntranceRandomization.internal_name: EntranceRandomization.options[option], Mods: mod}) basic_checks(self, multiworld) check_stray_mod_items(mod, self, multiworld) # if self.skip_extra_tests: From f380b41883e07bf51e1884a1f6dd26c1c989e300 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 30 Nov 2023 23:24:52 -0500 Subject: [PATCH 259/482] copy internal state only when necessary --- worlds/stardew_valley/stardew_rule.py | 274 +++++++++++------- worlds/stardew_valley/test/TestRules.py | 3 +- worlds/stardew_valley/test/TestStardewRule.py | 7 +- 3 files changed, 174 insertions(+), 110 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index a10456c2830a..6e15582ec559 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -1,10 +1,13 @@ from __future__ import annotations +import logging from abc import ABC, abstractmethod +from collections import deque from dataclasses import dataclass, field from functools import cached_property from itertools import chain -from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Optional +from threading import Lock +from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional from frozendict import frozendict @@ -12,6 +15,7 @@ from .items import item_table MISSING_ITEM = "THIS ITEM IS MISSING" +logger = logging.getLogger(__name__) @dataclass @@ -203,47 +207,96 @@ def __or__(self, other): return super().__or__(other) +class _SimplificationState: + original_simplifiable_rules: Tuple[StardewRule, ...] + + rules_to_simplify: deque[StardewRule] + simplified_rules: Set[StardewRule] + lock: Lock + + def __init__(self, simplifiable_rules: Tuple[StardewRule, ...], rules_to_simplify: Optional[deque[StardewRule]] = None, + simplified_rules: Optional[Set[StardewRule]] = None): + if simplified_rules is None: + simplified_rules = set() + + self.original_simplifiable_rules = simplifiable_rules + self.rules_to_simplify = rules_to_simplify + self.simplified_rules = simplified_rules + self.locked = False + + @property + def is_simplified(self): + return self.rules_to_simplify is not None and not self.rules_to_simplify + + def short_circuit(self): + self.rules_to_simplify = deque() + self.simplified_rules = set() + + def acquire_copy(self): + state = _SimplificationState(self.original_simplifiable_rules, self.rules_to_simplify.copy(), self.simplified_rules.copy()) + state.acquire() + return state + + def merge(self, other: _SimplificationState): + # TODO handle WIP simplification + return _SimplificationState(self.original_simplifiable_rules + other.original_simplifiable_rules) + + def add(self, rule: StardewRule): + return _SimplificationState(self.original_simplifiable_rules + (rule,)) + + def acquire(self): + """ + This just set a boolean to True and is absolutely not thread safe. It just works because AP is single-threaded. + """ + if self.locked is True: + return False + + self.locked = True + return True + + def release(self): + assert self.locked + self.locked = False + + class AggregatingStardewRule(StardewRule, ABC): identity: LiteralStardewRule complement: LiteralStardewRule symbol: str combinable_rules: frozendict[Hashable, CombinableStardewRule] - other_rules: Union[Iterable[StardewRule], Sized] - - detailed_unique_rules: Union[Iterable[StardewRule], Sized] - - _simplified: bool - _simplified_rules: frozenset[StardewRule] - _left_to_simplify_rules: Optional[Iterable[StardewRule]] - - def __init__(self, *rules: StardewRule, _combinable_rules=None): - self._simplified_rules = frozenset() + _simplification_state: _SimplificationState + def __init__(self, *rules: StardewRule, _combinable_rules=None, _simplification_state=None): if _combinable_rules is None: assert rules, f"Can't create an aggregating condition without rules" rules, _combinable_rules = CombinableStardewRule.split_rules(rules, self.combine) + _simplification_state = _SimplificationState(rules) - self.other_rules = tuple(rules) - self._simplified = not rules self.combinable_rules = _combinable_rules - - self.detailed_unique_rules = self.other_rules - self._left_to_simplify_rules = None + self.simplification_state = _simplification_state @property - def rules_iterable(self): - return chain(self.other_rules, self.combinable_rules.values()) + def original_rules(self): + return RepeatableChain(self.combinable_rules.values(), self.simplification_state.original_simplifiable_rules) @property - def detailed_rules_iterable(self): - return chain(self.detailed_unique_rules, self.combinable_rules.values()) + def current_rules(self): + if self.simplification_state.rules_to_simplify is None: + return self.original_rules + + return RepeatableChain(self.combinable_rules.values(), self.simplification_state.simplified_rules, self.simplification_state.rules_to_simplify) @staticmethod @abstractmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError + def short_circuit(self): + self.simplification_state.short_circuit() + self.combinable_rules = frozendict() + return self.complement, self.complement.value + # The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: # TODO test if inverting would speed up @@ -252,122 +305,116 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul if rule(state) is self.complement.value: return self, self.complement.value - if self._simplified: + if self.simplification_state.is_simplified: # The expression is fully simplified, so we can only evaluate. - for rule in self.other_rules: + for rule in self.simplification_state.simplified_rules: if rule(state) is self.complement.value: return self, self.complement.value return self, self.identity.value - # Evaluating what has already been simplified. - # The assumption is that the rules that used to evaluate to complement might complement again, so we can leave early. - for rule in self._simplified_rules: - if rule(state) is self.complement.value: - return self, self.complement.value + local_state = self.simplification_state + try: + # Creating a new copy, so we don't modify the rules while we're already evaluating it. + # TODO Both copies will need to be merged later when we come back to the parent call. + if not local_state.acquire(): + local_state = local_state.acquire_copy() + self.simplification_state = local_state + + # Evaluating what has already been simplified. + # The assumption is that the rules that used to evaluate to complement might complement again, so we can leave early. + for rule in local_state.simplified_rules: + if rule(state) is self.complement.value: + return self, self.complement.value - # If the iterator is None, it means we have not start simplifying. - # Otherwise, we will continue simplification where we left. - if self._left_to_simplify_rules is None: - self.other_rules = frozenset(self.other_rules) - if self.complement in self.other_rules: - self._simplified = True - self.combinable_rules = frozendict() - self.other_rules = (self.complement,) - return self.complement, self.complement.value - - self._left_to_simplify_rules = iter(self.other_rules) - - newly_simplified_rules = set() - # Start simplification where we left. - for rule in self._left_to_simplify_rules: - simplified, value = rule.evaluate_while_simplifying(state) - - # Identity is removed from the resulting simplification. - if simplified is self.identity or simplified in self._simplified_rules: - continue + # If the iterator is None, it means we have not start simplifying. + # Otherwise, we will continue simplification where we left. + if local_state.rules_to_simplify is None: + rules_to_simplify = frozenset(local_state.original_simplifiable_rules) + if self.complement in rules_to_simplify: + return self.short_circuit() + local_state.rules_to_simplify = deque(rules_to_simplify) + + # Start simplification where we left. + while local_state.rules_to_simplify: + # FIXME this should peek and only commit when leaving + rule = local_state.rules_to_simplify.pop() + simplified, value = rule.evaluate_while_simplifying(state) + + # Identity is removed from the resulting simplification. + # TODO check if the in reduces performances + if simplified is self.identity or simplified in local_state.simplified_rules: + continue - # If we find a complement here, we know the rule will always resolve to its value. - # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. - if simplified is self.complement: - self._simplified = True - self.combinable_rules = frozendict() - self.other_rules = (self.complement,) - return self.complement, self.complement.value - - # Keep the simplified rule to be reused. - newly_simplified_rules.add(simplified) - - # Now we use the value, to exit early if it evaluates to the complement. - if value is self.complement.value: - # FIXME I hate that this has to be a frozenset... But otherwise we see errors where Set changed size during iteration. - # This will need more troubleshooting. - self._simplified_rules |= newly_simplified_rules - return self, self.complement.value + # If we find a complement here, we know the rule will always resolve to its value. + # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. + if simplified is self.complement: + return self.short_circuit() + # Keep the simplified rule to be reused. + local_state.simplified_rules.add(simplified) - self._simplified = True - self.other_rules = frozenset(self._simplified_rules | newly_simplified_rules) + # Now we use the value, to exit early if it evaluates to the complement. + if value is self.complement.value: + return self, self.complement.value - # The whole rule has been simplified and evaluated without finding complement. - return self, self.identity.value + # The whole rule has been simplified and evaluated without finding complement. + return self, self.identity.value + finally: + local_state.release() def __str__(self): - return f"({self.symbol.join(str(rule) for rule in self.detailed_rules_iterable)})" + return f"({self.symbol.join(str(rule) for rule in self.original_rules)})" def __repr__(self): - return f"({self.symbol.join(repr(rule) for rule in self.detailed_rules_iterable)})" + return f"({self.symbol.join(repr(rule) for rule in self.original_rules)})" def __eq__(self, other): - return isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and self.other_rules == self.other_rules + return (isinstance(other, type(self)) and self.combinable_rules == other.combinable_rules and + self.simplification_state.original_simplifiable_rules == self.simplification_state.original_simplifiable_rules) def __hash__(self): # TODO since other_rules will be changed after simplification, a simplified rule will have a different hashcode than its original. # Ideally, two rules with the same simplification would be equal... - return hash((self.combinable_rules, self.other_rules)) + return hash((self.combinable_rules, self.simplification_state.original_simplifiable_rules)) def simplify(self) -> StardewRule: + logger.debug(f"Unoptimized 'simplified' called on {self}") # TODO is this needed now that we're using an iterator ? - if self._simplified: + if self.simplification_state.is_simplified: return self - if self._left_to_simplify_rules is None: - self.other_rules = frozenset(self.other_rules) - if self.complement in self.other_rules: - self._simplified = True - self.other_rules = (self.complement,) - return self.complement + if self.simplification_state.rules_to_simplify is None: + rules_to_simplify = frozenset(self.simplification_state.original_simplifiable_rules) + if self.complement in rules_to_simplify: + return self.short_circuit()[0] - self._left_to_simplify_rules = iter(self.other_rules) + self.simplification_state.rules_to_simplify = deque(rules_to_simplify) - newly_simplified_rules = set() - for rule in self._left_to_simplify_rules: + # TODO this should lock state + while self.simplification_state.rules_to_simplify: + rule = self.simplification_state.rules_to_simplify.pop() simplified = rule.simplify() - if simplified is self.identity or simplified in self._simplified_rules: + if simplified is self.identity or simplified in self.simplification_state.simplified_rules: continue if simplified is self.complement: - self._simplified = True - self._simplified_rules = frozenset((self.complement,)) - return self.complement + return self.short_circuit()[0] - newly_simplified_rules.add(simplified) + self.simplification_state.simplified_rules.add(simplified) - self._simplified = True - self.other_rules = frozenset(self._simplified_rules | newly_simplified_rules) - - if not self.other_rules and not self.combinable_rules: + if not self.simplification_state.simplified_rules and not self.combinable_rules: return self.identity - if len(self.other_rules) == 1 and not self.combinable_rules: - return next(iter(self.other_rules)) + if len(self.simplification_state.simplified_rules) == 1 and not self.combinable_rules: + return next(iter(self.simplification_state.simplified_rules)) - if not self.other_rules and len(self.combinable_rules) == 1: + if not self.simplification_state.simplified_rules and len(self.combinable_rules) == 1: return next(iter(self.combinable_rules.values())) return self def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, expected, frozenset(self.detailed_unique_rules).union(self.combinable_rules.values())) + return StardewRuleExplanation(self, state, expected, self.original_rules) class Or(AggregatingStardewRule): @@ -383,20 +430,20 @@ def __or__(self, other): return other | self if isinstance(other, CombinableStardewRule): - return Or(*self.other_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) + return Or(_combinable_rules=other.add_into(self.combinable_rules, self.combine), _simplification_state=self.simplification_state) if type(other) is Or: - return Or(*self.other_rules, *other.other_rules, - _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) + return Or(_combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine), + _simplification_state=self.simplification_state.merge(other.simplification_state)) - return Or(*self.other_rules, other, _combinable_rules=self.combinable_rules) + return Or(_combinable_rules=self.combinable_rules, _simplification_state=self.simplification_state.add(other)) @staticmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: return min(left, right, key=lambda x: x.value) def get_difficulty(self): - return min(rule.get_difficulty() for rule in self.rules_iterable) + return min(rule.get_difficulty() for rule in self.original_rules) class And(AggregatingStardewRule): @@ -412,20 +459,20 @@ def __and__(self, other): return other & self if isinstance(other, CombinableStardewRule): - return And(*self.other_rules, _combinable_rules=other.add_into(self.combinable_rules, self.combine)) + return And(_combinable_rules=other.add_into(self.combinable_rules, self.combine), _simplification_state=self.simplification_state) if type(other) is And: - return And(*self.other_rules, *other.other_rules, - _combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine)) + return And(_combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine), + _simplification_state=self.simplification_state.merge(other.simplification_state)) - return And(*self.other_rules, other, _combinable_rules=self.combinable_rules) + return And(_combinable_rules=self.combinable_rules, _simplification_state=self.simplification_state.add(other)) @staticmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: return max(left, right, key=lambda x: x.value) def get_difficulty(self): - return max(rule.get_difficulty() for rule in self.rules_iterable) + return max(rule.get_difficulty() for rule in self.original_rules) class Count(StardewRule): @@ -662,3 +709,20 @@ def __repr__(self): def get_difficulty(self): return self.percent + + +class RepeatableChain(Iterable, Sized): + def __init__(self, *iterable: Union[Iterable, Sized]): + self.iterables = iterable + + def __iter__(self): + return chain.from_iterable(self.iterables) + + def __bool__(self): + return any(sub_iterable for sub_iterable in self.iterables) + + def __len__(self): + return sum(len(iterable) for iterable in self.iterables) + + def __contains__(self, item): + return any(item in it for it in self.iterables) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index 0dc5706d9a6d..dd9c5aabe4ce 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -774,5 +774,4 @@ class TestVanillaSkillLogicSimplification(SVTestBase): 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.rules_iterable if type(i) == HasProgressionPercent)) - self.assertIsNotNone(rule.combinable_rules) + self.assertEqual(1, sum(1 for i in rule.current_rules if type(i) == HasProgressionPercent)) diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index f6e3b77a20f5..c6dde7feb4ff 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -127,7 +127,8 @@ def test_identity_is_removed_from_other_rules(self): rule.evaluate_while_simplifying(collection_state) - self.assertEqual(0, len(rule.other_rules)) + self.assertEqual(1, len(rule.current_rules)) + self.assertIn(HasProgressionPercent(1, 10), rule.current_rules) def test_complement_replaces_combinable_rules(self): collection_state = MagicMock() @@ -135,7 +136,7 @@ def test_complement_replaces_combinable_rules(self): rule.evaluate_while_simplifying(collection_state) - self.assertEqual(0, len(rule.combinable_rules)) + self.assertFalse(rule.current_rules) def test_simplifying_to_complement_propagates_complement(self): expected_simplified = true_ @@ -147,7 +148,7 @@ def test_simplifying_to_complement_propagates_complement(self): self.assertEqual(expected_result, actual_result) self.assertEqual(expected_simplified, actual_simplified) - self.assertEqual(0, len(rule.combinable_rules)) + self.assertFalse(rule.current_rules) def test_already_simplified_rules_are_not_simplified_again(self): collection_state = MagicMock() From 6b11e94be332bb18307ee35f4a1d483109aadf7c Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 00:14:09 -0500 Subject: [PATCH 260/482] now the rules disapearing is really fixed --- worlds/stardew_valley/stardew_rule.py | 51 ++++++++++++------- worlds/stardew_valley/test/TestStardewRule.py | 1 - 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 6e15582ec559..89c41ed2b306 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -232,6 +232,12 @@ def short_circuit(self): self.rules_to_simplify = deque() self.simplified_rules = set() + def try_popleft(self): + try: + self.rules_to_simplify.popleft() + except IndexError: + pass + def acquire_copy(self): state = _SimplificationState(self.original_simplifiable_rules, self.rules_to_simplify.copy(), self.simplified_rules.copy()) state.acquire() @@ -312,6 +318,9 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul return self, self.complement.value return self, self.identity.value + return self.evaluate_while_simplifying_stateful(state) + + def evaluate_while_simplifying_stateful(self, state): local_state = self.simplification_state try: # Creating a new copy, so we don't modify the rules while we're already evaluating it. @@ -336,31 +345,35 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul # Start simplification where we left. while local_state.rules_to_simplify: - # FIXME this should peek and only commit when leaving - rule = local_state.rules_to_simplify.pop() - simplified, value = rule.evaluate_while_simplifying(state) - - # Identity is removed from the resulting simplification. - # TODO check if the in reduces performances - if simplified is self.identity or simplified in local_state.simplified_rules: - continue - - # If we find a complement here, we know the rule will always resolve to its value. - # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. - if simplified is self.complement: - return self.short_circuit() - # Keep the simplified rule to be reused. - local_state.simplified_rules.add(simplified) - - # Now we use the value, to exit early if it evaluates to the complement. - if value is self.complement.value: - return self, self.complement.value + result = self.evaluate_rule_while_simplifying_stateful(local_state, state) + local_state.try_popleft() + if result is not None: + return result # The whole rule has been simplified and evaluated without finding complement. return self, self.identity.value finally: local_state.release() + def evaluate_rule_while_simplifying_stateful(self, local_state, state): + simplified, value = local_state.rules_to_simplify[0].evaluate_while_simplifying(state) + + # Identity is removed from the resulting simplification. + # TODO check if the in reduces performances + if simplified is self.identity or simplified in local_state.simplified_rules: + return + + # If we find a complement here, we know the rule will always resolve to its value. + # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. + if simplified is self.complement: + return self.short_circuit() + # Keep the simplified rule to be reused. + local_state.simplified_rules.add(simplified) + + # Now we use the value, to exit early if it evaluates to the complement. + if value is self.complement.value: + return self, self.complement.value + def __str__(self): return f"({self.symbol.join(str(rule) for rule in self.original_rules)})" diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index c6dde7feb4ff..4d9cc2b5b33b 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -182,7 +182,6 @@ def test_continue_simplification_after_short_circuited(self): not_yet_simplified.evaluate_while_simplifying.assert_called_with(collection_state) -@skip("Those two tests validate a bug that has yet to be fixed.") class TestEvaluateWhileSimplifyingDoubleCalls(unittest.TestCase): """ So, there is a situation where a rule kind of calls itself while it's being evaluated, because its evaluation triggers a region cache refresh. From 615976a6acadfee9aa0ee24d05eaf2383001d831 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 19:06:27 -0500 Subject: [PATCH 261/482] remove wasting checks --- worlds/stardew_valley/stardew_rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 89c41ed2b306..39f0ec38bc4f 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -360,7 +360,7 @@ def evaluate_rule_while_simplifying_stateful(self, local_state, state): # Identity is removed from the resulting simplification. # TODO check if the in reduces performances - if simplified is self.identity or simplified in local_state.simplified_rules: + if simplified is self.identity: return # If we find a complement here, we know the rule will always resolve to its value. From 710559d974f9739d5239e5925c6f8bc5e21c670e Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 19:19:46 -0500 Subject: [PATCH 262/482] move split_rules --- worlds/stardew_valley/stardew_rule.py | 75 +++++++++++++-------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 39f0ec38bc4f..fa09cef79445 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -153,40 +153,6 @@ def value(self): def is_same_rule(self, other: CombinableStardewRule): return self.combination_key == other.combination_key - @staticmethod - def split_rules(rules: Union[Iterable[StardewRule]], - reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ - -> Tuple[Tuple[StardewRule, ...], frozendict[Hashable, CombinableStardewRule]]: - other_rules = [] - reduced_rules = {} - for rule in rules: - if isinstance(rule, CombinableStardewRule): - key = rule.combination_key - if key not in reduced_rules: - reduced_rules[key] = rule - continue - - reduced_rules[key] = reducer(reduced_rules[key], rule) - else: - other_rules.append(rule) - - return tuple(other_rules), frozendict(reduced_rules) - - @staticmethod - def merge(left: frozendict[Hashable, CombinableStardewRule], - right: frozendict[Hashable, CombinableStardewRule], - reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ - -> frozendict[Hashable, CombinableStardewRule]: - reduced_rules = dict(left) - for key, rule in right.items(): - if key not in reduced_rules: - reduced_rules[key] = rule - continue - - reduced_rules[key] = reducer(reduced_rules[key], rule) - - return frozendict(reduced_rules) - def add_into(self, rules: frozendict[Hashable, CombinableStardewRule], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> frozendict[Hashable, CombinableStardewRule]: @@ -276,7 +242,7 @@ class AggregatingStardewRule(StardewRule, ABC): def __init__(self, *rules: StardewRule, _combinable_rules=None, _simplification_state=None): if _combinable_rules is None: assert rules, f"Can't create an aggregating condition without rules" - rules, _combinable_rules = CombinableStardewRule.split_rules(rules, self.combine) + rules, _combinable_rules = self.split_rules(rules) _simplification_state = _SimplificationState(rules) self.combinable_rules = _combinable_rules @@ -293,6 +259,36 @@ def current_rules(self): return RepeatableChain(self.combinable_rules.values(), self.simplification_state.simplified_rules, self.simplification_state.rules_to_simplify) + @classmethod + def split_rules(cls, rules: Union[Iterable[StardewRule]]) -> Tuple[Tuple[StardewRule, ...], frozendict[Hashable, CombinableStardewRule]]: + other_rules = [] + reduced_rules = {} + for rule in rules: + if isinstance(rule, CombinableStardewRule): + key = rule.combination_key + if key not in reduced_rules: + reduced_rules[key] = rule + continue + + reduced_rules[key] = cls.combine(reduced_rules[key], rule) + else: + other_rules.append(rule) + + return tuple(other_rules), frozendict(reduced_rules) + + @classmethod + def merge(cls, left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ + -> frozendict[Hashable, CombinableStardewRule]: + reduced_rules = dict(left) + for key, rule in right.items(): + if key not in reduced_rules: + reduced_rules[key] = rule + continue + + reduced_rules[key] = cls.combine(reduced_rules[key], rule) + + return frozendict(reduced_rules) + @staticmethod @abstractmethod def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: @@ -359,7 +355,6 @@ def evaluate_rule_while_simplifying_stateful(self, local_state, state): simplified, value = local_state.rules_to_simplify[0].evaluate_while_simplifying(state) # Identity is removed from the resulting simplification. - # TODO check if the in reduces performances if simplified is self.identity: return @@ -446,7 +441,7 @@ def __or__(self, other): return Or(_combinable_rules=other.add_into(self.combinable_rules, self.combine), _simplification_state=self.simplification_state) if type(other) is Or: - return Or(_combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine), + return Or(_combinable_rules=self.merge(self.combinable_rules, other.combinable_rules), _simplification_state=self.simplification_state.merge(other.simplification_state)) return Or(_combinable_rules=self.combinable_rules, _simplification_state=self.simplification_state.add(other)) @@ -475,7 +470,7 @@ def __and__(self, other): return And(_combinable_rules=other.add_into(self.combinable_rules, self.combine), _simplification_state=self.simplification_state) if type(other) is And: - return And(_combinable_rules=CombinableStardewRule.merge(self.combinable_rules, other.combinable_rules, self.combine), + return And(_combinable_rules=self.merge(self.combinable_rules, other.combinable_rules), _simplification_state=self.simplification_state.merge(other.simplification_state)) return And(_combinable_rules=self.combinable_rules, _simplification_state=self.simplification_state.add(other)) @@ -725,6 +720,10 @@ def get_difficulty(self): class RepeatableChain(Iterable, Sized): + """ + Essentially a copy of what's in the core, with proper type hinting + """ + def __init__(self, *iterable: Union[Iterable, Sized]): self.iterables = iterable From 4091480013526b741d790ade5959733a82a713f6 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 19:54:49 -0500 Subject: [PATCH 263/482] fix short circuit --- worlds/stardew_valley/stardew_rule.py | 6 +++--- worlds/stardew_valley/test/TestStardewRule.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index fa09cef79445..2630d6db95bb 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -194,9 +194,9 @@ def __init__(self, simplifiable_rules: Tuple[StardewRule, ...], rules_to_simplif def is_simplified(self): return self.rules_to_simplify is not None and not self.rules_to_simplify - def short_circuit(self): + def short_circuit(self, complement: LiteralStardewRule): self.rules_to_simplify = deque() - self.simplified_rules = set() + self.simplified_rules = {complement} def try_popleft(self): try: @@ -295,7 +295,7 @@ def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> Combin raise NotImplementedError def short_circuit(self): - self.simplification_state.short_circuit() + self.simplification_state.short_circuit(self.complement) self.combinable_rules = frozendict() return self.complement, self.complement.value diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index 4d9cc2b5b33b..5b4190c619e5 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -136,7 +136,7 @@ def test_complement_replaces_combinable_rules(self): rule.evaluate_while_simplifying(collection_state) - self.assertFalse(rule.current_rules) + self.assertTrue(rule.current_rules) def test_simplifying_to_complement_propagates_complement(self): expected_simplified = true_ @@ -148,7 +148,7 @@ def test_simplifying_to_complement_propagates_complement(self): self.assertEqual(expected_result, actual_result) self.assertEqual(expected_simplified, actual_simplified) - self.assertFalse(rule.current_rules) + self.assertTrue(rule.current_rules) def test_already_simplified_rules_are_not_simplified_again(self): collection_state = MagicMock() From a8bf46eb1d81362f0646dd828c9edca5d02f6108 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 20:12:55 -0500 Subject: [PATCH 264/482] merge aggregating rules while splitting them --- worlds/stardew_valley/stardew_rule.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 2630d6db95bb..bf1996702caf 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -237,7 +237,7 @@ class AggregatingStardewRule(StardewRule, ABC): symbol: str combinable_rules: frozendict[Hashable, CombinableStardewRule] - _simplification_state: _SimplificationState + simplification_state: _SimplificationState def __init__(self, *rules: StardewRule, _combinable_rules=None, _simplification_state=None): if _combinable_rules is None: @@ -271,15 +271,26 @@ def split_rules(cls, rules: Union[Iterable[StardewRule]]) -> Tuple[Tuple[Stardew continue reduced_rules[key] = cls.combine(reduced_rules[key], rule) - else: - other_rules.append(rule) + continue + + if type(rule) is cls: + other_rules.extend(rule.simplification_state.original_simplifiable_rules) # noqa + reduced_rules = cls.merge_mutable(reduced_rules, rule.combinable_rules) # noqa + continue + + other_rules.append(rule) return tuple(other_rules), frozendict(reduced_rules) @classmethod def merge(cls, left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ -> frozendict[Hashable, CombinableStardewRule]: - reduced_rules = dict(left) + return frozendict(cls.merge_mutable(dict(left), right)) + + @classmethod + def merge_mutable(cls, left: Dict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ + -> Dict[Hashable, CombinableStardewRule]: + reduced_rules = left for key, rule in right.items(): if key not in reduced_rules: reduced_rules[key] = rule @@ -287,7 +298,7 @@ def merge(cls, left: frozendict[Hashable, CombinableStardewRule], right: frozend reduced_rules[key] = cls.combine(reduced_rules[key], rule) - return frozendict(reduced_rules) + return reduced_rules @staticmethod @abstractmethod From df410d44c84ff5b467abe91540beef0c042f6f8d Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 20:35:31 -0500 Subject: [PATCH 265/482] add proper tests for rules building --- worlds/stardew_valley/test/TestStardewRule.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index 5b4190c619e5..6e9fdf13f4e8 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -22,19 +22,30 @@ def test_simplify_false_in_or(self): summer = Received("Summer", 0, 1) self.assertEqual(summer, (Has("Wood", rules) | summer | Has("Rock", rules)).simplify()) - def test_simplify_and_in_and(self): + def test_simplify_and_and_and(self): rule = And(Received('Summer', 0, 1), Received('Fall', 0, 1)) & And(Received('Winter', 0, 1), Received('Spring', 0, 1)) self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + def test_simplify_and_in_and(self): + """ + Those feature of simplifying the rules when they are built have proven to improve the fill speed considerably. + """ + rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), And(Received('Winter', 0, 1), Received('Spring', 0, 1))) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + @skip("This feature has been disabled and that seems to save time") 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))) self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) - def test_simplify_or_in_or(self): + def test_simplify_or_or_or(self): rule = Or(Received('Summer', 0, 1), Received('Fall', 0, 1)) | Or(Received('Winter', 0, 1), Received('Spring', 0, 1)) self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + 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))) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + @skip("This feature has been disabled and that seems to save time") 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))) From c07d62fc418f6323435ecc5a8e6c619c687d2bee Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 21:25:52 -0500 Subject: [PATCH 266/482] cache last short circuiting rule --- worlds/stardew_valley/stardew_rule.py | 35 +++++++++++++++++---------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index bf1996702caf..5d2cc91424e2 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -210,7 +210,6 @@ def acquire_copy(self): return state def merge(self, other: _SimplificationState): - # TODO handle WIP simplification return _SimplificationState(self.original_simplifiable_rules + other.original_simplifiable_rules) def add(self, rule: StardewRule): @@ -238,6 +237,7 @@ class AggregatingStardewRule(StardewRule, ABC): combinable_rules: frozendict[Hashable, CombinableStardewRule] simplification_state: _SimplificationState + _last_complementing_rule: Optional[StardewRule] = None def __init__(self, *rules: StardewRule, _combinable_rules=None, _simplification_state=None): if _combinable_rules is None: @@ -305,24 +305,33 @@ def merge_mutable(cls, left: Dict[Hashable, CombinableStardewRule], right: froze def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> CombinableStardewRule: raise NotImplementedError - def short_circuit(self): + def short_circuit_simplification(self): self.simplification_state.short_circuit(self.complement) self.combinable_rules = frozendict() return self.complement, self.complement.value + def short_circuit_evaluation(self, rule): + self._last_complementing_rule = rule + return self, self.complement.value + # The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - # TODO test if inverting would speed up + # Directly checking last rule that evaluated to complement, in case state has not changed. + if self._last_complementing_rule: + if self._last_complementing_rule(state) is self.complement.value: + return self.short_circuit_evaluation(self._last_complementing_rule) + self._last_complementing_rule = None + # Combinable rules are considered already simplified, so we evaluate them right away. for rule in self.combinable_rules.values(): if rule(state) is self.complement.value: - return self, self.complement.value + return self.short_circuit_evaluation(rule) if self.simplification_state.is_simplified: # The expression is fully simplified, so we can only evaluate. for rule in self.simplification_state.simplified_rules: if rule(state) is self.complement.value: - return self, self.complement.value + return self.short_circuit_evaluation(rule) return self, self.identity.value return self.evaluate_while_simplifying_stateful(state) @@ -331,7 +340,8 @@ def evaluate_while_simplifying_stateful(self, state): local_state = self.simplification_state try: # Creating a new copy, so we don't modify the rules while we're already evaluating it. - # TODO Both copies will need to be merged later when we come back to the parent call. + # After investigation, for millions of call to this method, copy were acquired 425 times. + # Merging simplification state in parent call was deemed useless. if not local_state.acquire(): local_state = local_state.acquire_copy() self.simplification_state = local_state @@ -340,14 +350,14 @@ def evaluate_while_simplifying_stateful(self, state): # The assumption is that the rules that used to evaluate to complement might complement again, so we can leave early. for rule in local_state.simplified_rules: if rule(state) is self.complement.value: - return self, self.complement.value + return self.short_circuit_evaluation(rule) # If the iterator is None, it means we have not start simplifying. # Otherwise, we will continue simplification where we left. if local_state.rules_to_simplify is None: rules_to_simplify = frozenset(local_state.original_simplifiable_rules) if self.complement in rules_to_simplify: - return self.short_circuit() + return self.short_circuit_simplification() local_state.rules_to_simplify = deque(rules_to_simplify) # Start simplification where we left. @@ -370,15 +380,14 @@ def evaluate_rule_while_simplifying_stateful(self, local_state, state): return # If we find a complement here, we know the rule will always resolve to its value. - # TODO need to confirm how often it happens, but we could skip evaluating combinables if the rule has resolved to a complement. if simplified is self.complement: - return self.short_circuit() + return self.short_circuit_simplification() # Keep the simplified rule to be reused. local_state.simplified_rules.add(simplified) # Now we use the value, to exit early if it evaluates to the complement. if value is self.complement.value: - return self, self.complement.value + return self.short_circuit_evaluation(simplified) def __str__(self): return f"({self.symbol.join(str(rule) for rule in self.original_rules)})" @@ -404,7 +413,7 @@ def simplify(self) -> StardewRule: if self.simplification_state.rules_to_simplify is None: rules_to_simplify = frozenset(self.simplification_state.original_simplifiable_rules) if self.complement in rules_to_simplify: - return self.short_circuit()[0] + return self.short_circuit_simplification()[0] self.simplification_state.rules_to_simplify = deque(rules_to_simplify) @@ -417,7 +426,7 @@ def simplify(self) -> StardewRule: continue if simplified is self.complement: - return self.short_circuit()[0] + return self.short_circuit_simplification()[0] self.simplification_state.simplified_rules.add(simplified) From b65ebbb1017c997d63ca142cda580687846138fe Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 1 Dec 2023 22:41:28 -0500 Subject: [PATCH 267/482] fix test --- worlds/stardew_valley/stardew_rule.py | 12 ++++++------ worlds/stardew_valley/test/TestStardewRule.py | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 5d2cc91424e2..e5b0badedb3a 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -237,7 +237,7 @@ class AggregatingStardewRule(StardewRule, ABC): combinable_rules: frozendict[Hashable, CombinableStardewRule] simplification_state: _SimplificationState - _last_complementing_rule: Optional[StardewRule] = None + _last_short_circuiting_rule: Optional[StardewRule] = None def __init__(self, *rules: StardewRule, _combinable_rules=None, _simplification_state=None): if _combinable_rules is None: @@ -311,16 +311,16 @@ def short_circuit_simplification(self): return self.complement, self.complement.value def short_circuit_evaluation(self, rule): - self._last_complementing_rule = rule + self._last_short_circuiting_rule = rule return self, self.complement.value # The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: # Directly checking last rule that evaluated to complement, in case state has not changed. - if self._last_complementing_rule: - if self._last_complementing_rule(state) is self.complement.value: - return self.short_circuit_evaluation(self._last_complementing_rule) - self._last_complementing_rule = None + if self._last_short_circuiting_rule: + if self._last_short_circuiting_rule(state) is self.complement.value: + return self.short_circuit_evaluation(self._last_short_circuiting_rule) + self._last_short_circuiting_rule = None # Combinable rules are considered already simplified, so we evaluate them right away. for rule in self.combinable_rules.values(): diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index 6e9fdf13f4e8..7f384e3e8cd2 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -230,7 +230,7 @@ def first_call_to_internal_rule(state): self.assertTrue(called_once) self.assertTrue(internal_call_result) - def test_nested_call_to_already_simplified_rule_does_not_steal_rule_to_simplified_from_parent_call(self): + def test_nested_call_to_already_simplified_rule_does_not_steal_rule_to_simplify_from_parent_call(self): collection_state = MagicMock() an_internal_rule = MagicMock() an_internal_rule.evaluate_while_simplifying = Mock(return_value=(an_internal_rule, True)) @@ -259,6 +259,7 @@ def call_to_already_simplified(state): return False already_simplified.side_effect = call_to_already_simplified + not_yet_simplified.return_value = True _, actual_result = rule.evaluate_while_simplifying(collection_state) From f6ad3e9dd69174bb399f476777fa2619a8b42ec4 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 2 Dec 2023 12:48:37 -0500 Subject: [PATCH 268/482] count optimizations --- worlds/stardew_valley/stardew_rule.py | 45 ++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index e5b0badedb3a..a3357e338305 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from collections import deque from dataclasses import dataclass, field -from functools import cached_property +from functools import cached_property, cache from itertools import chain from threading import Lock from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional @@ -87,6 +87,9 @@ def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanati class LiteralStardewRule(StardewRule, ABC): value: bool + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self.value + def __call__(self, state: CollectionState) -> bool: return self.value @@ -314,8 +317,11 @@ def short_circuit_evaluation(self, rule): self._last_short_circuiting_rule = rule return self, self.complement.value - # The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + """ + The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. + """ + # Directly checking last rule that evaluated to complement, in case state has not changed. if self._last_short_circuiting_rule: if self._last_short_circuiting_rule(state) is self.complement.value: @@ -506,6 +512,7 @@ def get_difficulty(self): class Count(StardewRule): count: int rules: List[StardewRule] + rules_count: int _simplified: bool def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): @@ -524,26 +531,31 @@ def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], self.rules = rules_list self.count = count + self.rules_count = len(rules_list) self._simplified = False - def __call__(self, state: CollectionState) -> bool: - self.simplify() + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: c = 0 - for r in self.rules: - if r(state): + for i in range(self.rules_count): + self.rules[i], value = self.rules[i].evaluate_while_simplifying(state) + if value: c += 1 + if c >= self.count: - return True - return False + return self, True + if c + self.rules_count - i < self.count: + break - # TODO implement evaluate while simplifying + return self, False + + def __call__(self, state: CollectionState) -> bool: + return self.evaluate_while_simplifying(state)[1] def simplify(self): if self._simplified: return self - simplified_rules = [rule.simplify() for rule in self.rules] - self.rules = simplified_rules + self.rules = [rule.simplify() for rule in self.rules] self._simplified = True return self @@ -551,9 +563,10 @@ def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanati return StardewRuleExplanation(self, state, expected, self.rules) def get_difficulty(self): - rules_sorted_by_difficulty = sorted(self.rules, key=lambda x: x.get_difficulty()) - easiest_n_rules = rules_sorted_by_difficulty[0:self.count] - return max(rule.get_difficulty() for rule in easiest_n_rules) + self.rules = sorted(self.rules, key=lambda x: x.get_difficulty()) + # In an optimal situation, all the simplest rules will be true. Since the rules are sorted, we know that the most difficult rule we might have to do + # is the one at the "self.count". + return self.rules[self.count - 1].get_difficulty() def __repr__(self): return f"Received {self.count} {repr(self.rules)}" @@ -635,6 +648,10 @@ class Reach(StardewRule): resolution_hint: str player: int + @cache + def __new__(cls, *args, **kwargs): + return super().__new__(cls) + def __call__(self, state: CollectionState) -> bool: return state.can_reach(self.spot, self.resolution_hint, self.player) From d0c9580964b2573c61b682daffdf49168787048b Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 2 Dec 2023 13:06:55 -0500 Subject: [PATCH 269/482] add more options to prepare benchmarking --- .../test/performance/TestPerformance.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index cfbeaefddef2..1319b56592ec 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -9,8 +9,7 @@ from worlds import AutoWorld from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options -number_generations = 25 -default_seeds = [87876703343494157696] * number_generations +default_number_generations = 25 acceptable_deviation = 4 @@ -55,6 +54,18 @@ def setUpClass(cls) -> None: if fill_tests_key in os.environ: cls.skip_fill = not bool(os.environ[fill_tests_key]) + fixed_seed_key = "fixed_seed" + if fixed_seed_key in os.environ: + cls.fixed_seed = bool(os.environ[fixed_seed_key]) + else: + cls.fixed_seed = False + + number_generations_key = "number_gen" + if number_generations_key in os.environ: + cls.number_generations = int(os.environ[number_generations_key]) + else: + cls.number_generations = default_number_generations + @classmethod def tearDownClass(cls) -> None: case = None @@ -71,7 +82,7 @@ def performance_test_multiworld(self, options): acceptable_average_time = self.acceptable_time_per_player * amount_of_players total_time = 0 all_times = [] - seeds = [get_seed() for _ in range(number_generations)] if self.skip_fill else default_seeds + seeds = [get_seed() for _ in range(self.number_generations)] if not self.fixed_seed else [87876703343494157696] * self.number_generations for i, seed in enumerate(seeds): with self.subTest(f"Seed: {seed}"): @@ -89,7 +100,7 @@ def performance_test_multiworld(self, options): elapsed_time = time_after - time_before total_time += elapsed_time all_times.append(elapsed_time) - print(f"Multiworld {i + 1}/{number_generations} [{seed}] generated in {elapsed_time:.4f} seconds") + print(f"Multiworld {i + 1}/{self.number_generations} [{seed}] generated in {elapsed_time:.4f} seconds") # tester.assertLessEqual(elapsed_time, acceptable_average_time * acceptable_deviation) self.results.append(PerformanceResults(self, amount_of_players, all_times, acceptable_average_time)) From db80680969a33f952e72fc550d422712964807ee Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 2 Dec 2023 18:23:38 -0500 Subject: [PATCH 270/482] override performance tests for benchmarking --- worlds/stardew_valley/test/__init__.py | 59 ++++++++++++++++++- .../test/performance/TestPerformance.py | 7 ++- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 80ccc204d3a9..43cb27a781f6 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -16,10 +16,30 @@ Cooksanity, Chefsanity, Craftsanity +@cache_argsless +def disable_5_x_x_options(): + return { + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_none, + Craftsanity.internal_name: Craftsanity.option_none + } + + +@cache_argsless +def default_4_x_x_options(): + options = default_options() + options.update(disable_5_x_x_options()) + options.update({ + BundleRandomization.internal_name: BundleRandomization.option_shuffled, + }) + return options + + @cache_argsless def default_options(): - default = {} - return default + return {} @cache_argsless @@ -99,6 +119,41 @@ def minimal_locations_maximal_items_with_island(): return min_max_options +@cache_argsless +def allsanity_4_x_x_options_without_mods(): + options = { + Goal.internal_name: Goal.option_perfection, + BundleRandomization.internal_name: BundleRandomization.option_thematic, + BundlePrice.internal_name: BundlePrice.option_expensive, + SeasonRandomization.internal_name: SeasonRandomization.option_randomized, + Cropsanity.internal_name: Cropsanity.option_enabled, + BackpackProgression.internal_name: BackpackProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive, + SkillProgression.internal_name: SkillProgression.option_progressive, + BuildingProgression.internal_name: BuildingProgression.option_progressive, + FestivalLocations.internal_name: FestivalLocations.option_hard, + ElevatorProgression.internal_name: ElevatorProgression.option_progressive, + ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, + HelpWantedLocations.internal_name: 56, + Fishsanity.internal_name: Fishsanity.option_all, + Museumsanity.internal_name: Museumsanity.option_all, + Monstersanity.internal_name: Monstersanity.option_progressive_goals, + Shipsanity.internal_name: Shipsanity.option_everything, + Cooksanity.internal_name: Cooksanity.option_all, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, + Friendsanity.internal_name: Friendsanity.option_all_with_marriage, + FriendsanityHeartSize.internal_name: 1, + NumberOfMovementBuffs.internal_name: 12, + NumberOfLuckBuffs.internal_name: 12, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false, + TrapItems.internal_name: TrapItems.option_nightmare, + } + options.update(disable_5_x_x_options()) + return options + + @cache_argsless def allsanity_options_without_mods(): allsanity = { diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index 1319b56592ec..b92791fb3e18 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -7,7 +7,8 @@ from BaseClasses import get_seed from Fill import distribute_items_restrictive, balance_multiworld_progression from worlds import AutoWorld -from .. import SVTestCase, minimal_locations_maximal_items, allsanity_options_without_mods, setup_multiworld, default_options +from .. import SVTestCase, minimal_locations_maximal_items, setup_multiworld, default_4_x_x_options, \ + allsanity_4_x_x_options_without_mods default_number_generations = 25 acceptable_deviation = 4 @@ -119,7 +120,7 @@ def size_name(number_players): class TestDefaultOptions(SVPerformanceTestCase): acceptable_time_per_player = 0.04 - options = default_options() + options = default_4_x_x_options() results = [] def test_solo(self): @@ -195,7 +196,7 @@ def test_10_player(self): class TestAllsanityWithoutMods(SVPerformanceTestCase): acceptable_time_per_player = 0.07 - options = allsanity_options_without_mods() + options = allsanity_4_x_x_options_without_mods() results = [] def test_solo(self): From fd75f0ed530a8ed5f82072be4be4c09e007f660b Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 2 Dec 2023 19:40:31 -0500 Subject: [PATCH 271/482] set performance test back to 5.x.x --- worlds/stardew_valley/test/performance/TestPerformance.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index b92791fb3e18..e3d823386702 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -7,8 +7,7 @@ from BaseClasses import get_seed from Fill import distribute_items_restrictive, balance_multiworld_progression from worlds import AutoWorld -from .. import SVTestCase, minimal_locations_maximal_items, setup_multiworld, default_4_x_x_options, \ - allsanity_4_x_x_options_without_mods +from .. import SVTestCase, minimal_locations_maximal_items, setup_multiworld, allsanity_options_without_mods, default_options default_number_generations = 25 acceptable_deviation = 4 @@ -120,7 +119,7 @@ def size_name(number_players): class TestDefaultOptions(SVPerformanceTestCase): acceptable_time_per_player = 0.04 - options = default_4_x_x_options() + options = default_options() results = [] def test_solo(self): @@ -196,7 +195,7 @@ def test_10_player(self): class TestAllsanityWithoutMods(SVPerformanceTestCase): acceptable_time_per_player = 0.07 - options = allsanity_4_x_x_options_without_mods() + options = allsanity_options_without_mods() results = [] def test_solo(self): From 6c0425f728c5980fae332a85096fe85994bc8a9a Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 13:55:33 -0600 Subject: [PATCH 272/482] Fix regions and names --- worlds/stardew_valley/data/items.csv | 1649 +++++++++-------- worlds/stardew_valley/mods/logic/sve_logic.py | 2 +- worlds/stardew_valley/mods/mod_regions.py | 82 +- worlds/stardew_valley/rules.py | 26 +- .../stardew_valley/strings/entrance_names.py | 44 +- worlds/stardew_valley/strings/region_names.py | 17 +- 6 files changed, 940 insertions(+), 880 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 39b3de17f1ab..261ae60ee502 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -1,822 +1,827 @@ -id,name,classification,groups,mod_name -0,Joja Cola,filler,TRASH, -15,Rusty Key,progression,, -16,Dwarvish Translation Guide,progression,, -17,Bridge Repair,progression,COMMUNITY_REWARD, -18,Greenhouse,progression,COMMUNITY_REWARD, -19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, -20,Minecarts Repair,useful,COMMUNITY_REWARD, -21,Bus Repair,progression,COMMUNITY_REWARD, -22,Progressive Movie Theater,progression,COMMUNITY_REWARD, -23,Stardrop,progression,, -24,Progressive Backpack,progression,, -25,Rusty Sword,filler,"WEAPON,DEPRECATED", -26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", -27,Work Boots,filler,"FOOTWEAR,DEPRECATED", -28,Wooden Blade,filler,"WEAPON,DEPRECATED", -29,Iron Dirk,filler,"WEAPON,DEPRECATED", -30,Wind Spire,filler,"WEAPON,DEPRECATED", -31,Femur,filler,"WEAPON,DEPRECATED", -32,Steel Smallsword,filler,"WEAPON,DEPRECATED", -33,Wood Club,filler,"WEAPON,DEPRECATED", -34,Elf Blade,filler,"WEAPON,DEPRECATED", -37,Slingshot,filler,"WEAPON,DEPRECATED", -38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", -39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", -40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", -41,Silver Saber,filler,"WEAPON,DEPRECATED", -42,Pirate's Sword,filler,"WEAPON,DEPRECATED", -43,Crystal Dagger,filler,"WEAPON,DEPRECATED", -44,Cutlass,filler,"WEAPON,DEPRECATED", -45,Iron Edge,filler,"WEAPON,DEPRECATED", -46,Burglar's Shank,filler,"WEAPON,DEPRECATED", -47,Wood Mallet,filler,"WEAPON,DEPRECATED", -48,Master Slingshot,filler,"WEAPON,DEPRECATED", -49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", -50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", -51,Claymore,filler,"WEAPON,DEPRECATED", -52,Templar's Blade,filler,"WEAPON,DEPRECATED", -53,Kudgel,filler,"WEAPON,DEPRECATED", -54,Shadow Dagger,filler,"WEAPON,DEPRECATED", -55,Obsidian Edge,filler,"WEAPON,DEPRECATED", -56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", -57,Wicked Kris,filler,"WEAPON,DEPRECATED", -58,Bone Sword,filler,"WEAPON,DEPRECATED", -59,Ossified Blade,filler,"WEAPON,DEPRECATED", -60,Space Boots,filler,"FOOTWEAR,DEPRECATED", -61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", -62,Steel Falchion,filler,"WEAPON,DEPRECATED", -63,The Slammer,filler,"WEAPON,DEPRECATED", -64,Skull Key,progression,, -65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, -66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, -67,Progressive Axe,progression,PROGRESSIVE_TOOLS, -68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, -69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, -70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, -71,Golden Scythe,useful,, -72,Progressive Mine Elevator,progression,, -73,Farming Level,progression,SKILL_LEVEL_UP, -74,Fishing Level,progression,SKILL_LEVEL_UP, -75,Foraging Level,progression,SKILL_LEVEL_UP, -76,Mining Level,progression,SKILL_LEVEL_UP, -77,Combat Level,progression,SKILL_LEVEL_UP, -78,Earth Obelisk,progression,WIZARD_BUILDING, -79,Water Obelisk,progression,WIZARD_BUILDING, -80,Desert Obelisk,progression,WIZARD_BUILDING, -81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", -82,Junimo Hut,useful,WIZARD_BUILDING, -83,Gold Clock,progression,WIZARD_BUILDING, -84,Progressive Coop,progression,BUILDING, -85,Progressive Barn,progression,BUILDING, -86,Well,useful,BUILDING, -87,Silo,progression,BUILDING, -88,Mill,progression,BUILDING, -89,Progressive Shed,progression,BUILDING, -90,Fish Pond,progression,BUILDING, -91,Stable,useful,BUILDING, -92,Slime Hutch,progression,BUILDING, -93,Shipping Bin,progression,BUILDING, -94,Beach Bridge,progression,, -95,Adventurer's Guild,progression,, -96,Club Card,progression,, -97,Magnifying Glass,progression,, -98,Bear's Knowledge,useful,, -99,Iridium Snake Milk,useful,, -100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, -101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, -102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, -103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, -104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, -105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, -106,Galaxy Sword,filler,"WEAPON,DEPRECATED", -107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", -108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", -109,Movement Speed Bonus,progression,, -110,Luck Bonus,progression,, -111,Lava Katana,filler,"WEAPON,DEPRECATED", -112,Progressive House,progression,, -113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, -114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, -115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, -116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, -117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, -118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, -119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, -120,Traveling Merchant Stock Size,useful,, -121,Traveling Merchant Discount,useful,, -122,Return Scepter,useful,, -123,Progressive Season,progression,, -124,Spring,progression,SEASON, -125,Summer,progression,SEASON, -126,Fall,progression,SEASON, -127,Winter,progression,SEASON, -128,Amaranth Seeds,progression,CROPSANITY, -129,Artichoke Seeds,progression,CROPSANITY, -130,Beet Seeds,progression,CROPSANITY, -131,Jazz Seeds,progression,CROPSANITY, -132,Blueberry Seeds,progression,CROPSANITY, -133,Bok Choy Seeds,progression,CROPSANITY, -134,Cauliflower Seeds,progression,CROPSANITY, -135,Corn Seeds,progression,CROPSANITY, -136,Cranberry Seeds,progression,CROPSANITY, -137,Eggplant Seeds,progression,CROPSANITY, -138,Fairy Seeds,progression,CROPSANITY, -139,Garlic Seeds,progression,CROPSANITY, -140,Grape Starter,progression,CROPSANITY, -141,Bean Starter,progression,CROPSANITY, -142,Hops Starter,progression,CROPSANITY, -143,Pepper Seeds,progression,CROPSANITY, -144,Kale Seeds,progression,CROPSANITY, -145,Melon Seeds,progression,CROPSANITY, -146,Parsnip Seeds,progression,CROPSANITY, -147,Poppy Seeds,progression,CROPSANITY, -148,Potato Seeds,progression,CROPSANITY, -149,Pumpkin Seeds,progression,CROPSANITY, -150,Radish Seeds,progression,CROPSANITY, -151,Red Cabbage Seeds,progression,CROPSANITY, -152,Rhubarb Seeds,progression,CROPSANITY, -153,Starfruit Seeds,progression,CROPSANITY, -154,Strawberry Seeds,progression,CROPSANITY, -155,Spangle Seeds,progression,CROPSANITY, -156,Sunflower Seeds,progression,CROPSANITY, -157,Tomato Seeds,progression,CROPSANITY, -158,Tulip Bulb,progression,CROPSANITY, -159,Rice Shoot,progression,CROPSANITY, -160,Wheat Seeds,progression,CROPSANITY, -161,Yam Seeds,progression,CROPSANITY, -162,Cactus Seeds,progression,CROPSANITY, -163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -164,Ancient Seeds Recipe,progression,MUSEUM, -165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -166,Traveling Merchant Metal Detector,progression,MUSEUM, -167,Alex <3,progression,FRIENDSANITY, -168,Elliott <3,progression,FRIENDSANITY, -169,Harvey <3,progression,FRIENDSANITY, -170,Sam <3,progression,FRIENDSANITY, -171,Sebastian <3,progression,FRIENDSANITY, -172,Shane <3,progression,FRIENDSANITY, -173,Abigail <3,progression,FRIENDSANITY, -174,Emily <3,progression,FRIENDSANITY, -175,Haley <3,progression,FRIENDSANITY, -176,Leah <3,progression,FRIENDSANITY, -177,Maru <3,progression,FRIENDSANITY, -178,Penny <3,progression,FRIENDSANITY, -179,Caroline <3,progression,FRIENDSANITY, -180,Clint <3,progression,FRIENDSANITY, -181,Demetrius <3,progression,FRIENDSANITY, -182,Dwarf <3,progression,FRIENDSANITY, -183,Evelyn <3,progression,FRIENDSANITY, -184,George <3,progression,FRIENDSANITY, -185,Gus <3,progression,FRIENDSANITY, -186,Jas <3,progression,FRIENDSANITY, -187,Jodi <3,progression,FRIENDSANITY, -188,Kent <3,progression,FRIENDSANITY, -189,Krobus <3,progression,FRIENDSANITY, -190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", -191,Lewis <3,progression,FRIENDSANITY, -192,Linus <3,progression,FRIENDSANITY, -193,Marnie <3,progression,FRIENDSANITY, -194,Pam <3,progression,FRIENDSANITY, -195,Pierre <3,progression,FRIENDSANITY, -196,Robin <3,progression,FRIENDSANITY, -197,Sandy <3,progression,FRIENDSANITY, -198,Vincent <3,progression,FRIENDSANITY, -199,Willy <3,progression,FRIENDSANITY, -200,Wizard <3,progression,FRIENDSANITY, -201,Pet <3,progression,FRIENDSANITY, -202,Rarecrow #1,progression,"FESTIVAL,RARECROW", -203,Rarecrow #2,progression,"FESTIVAL,RARECROW", -204,Rarecrow #3,progression,"FESTIVAL,RARECROW", -205,Rarecrow #4,progression,"FESTIVAL,RARECROW", -206,Rarecrow #5,progression,"FESTIVAL,RARECROW", -207,Rarecrow #6,progression,"FESTIVAL,RARECROW", -208,Rarecrow #7,progression,"FESTIVAL,RARECROW", -209,Rarecrow #8,progression,"FESTIVAL,RARECROW", -210,Straw Hat,filler,FESTIVAL, -211,Golden Pumpkin,useful,FESTIVAL, -212,Barbed Hook,useful,FESTIVAL, -213,Dressed Spinner,useful,FESTIVAL, -214,Magnet,useful,FESTIVAL, -215,Sailor's Cap,filler,FESTIVAL, -216,Pearl,useful,FESTIVAL, -217,Cone Hat,filler,FESTIVAL, -218,Iridium Fireplace,filler,FESTIVAL, -219,Lupini: Red Eagle,filler,FESTIVAL, -220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, -221,Lupini: Solar Kingdom,filler,FESTIVAL, -222,Lupini: Clouds,filler,FESTIVAL, -223,Lupini: 1000 Years From Now,filler,FESTIVAL, -224,Lupini: Three Trees,filler,FESTIVAL, -225,Lupini: The Serpent,filler,FESTIVAL, -226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, -227,Lupini: Land Of Clay,filler,FESTIVAL, -228,Special Order Board,progression,SPECIAL_ORDER_BOARD, -229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, -230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, -231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, -232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, -233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, -234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, -235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, -236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, -237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, -239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -260,Boat Repair,progression,GINGER_ISLAND, -261,Open Professor Snail Cave,progression,"GINGER_ISLAND", -262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", -271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", -275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", -276,Weather Report,useful,"TV_CHANNEL", -277,Fortune Teller,useful,"TV_CHANNEL", -278,Livin' Off The Land,useful,"TV_CHANNEL", -279,The Queen of Sauce,progression,"TV_CHANNEL", -280,Fishing Information Broadcasting Service,useful,"TV_CHANNEL", -281,Sinister Signal,useful,"TV_CHANNEL", -282,Dark Talisman,progression,, -283,Ostrich Incubator Recipe,progression,"GINGER_ISLAND", -284,Cute Baby,progression,"BABY", -285,Ugly Baby,progression,"BABY", -286,Deluxe Scarecrow Recipe,progression,"RARECROW", -287,Treehouse,progression,"GINGER_ISLAND", -288,Coffee Bean,progression,CROPSANITY, -289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", -290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", -291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", -292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", -293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -294,Progressive Footwear,useful,"FOOTWEAR", -295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -325,Fairy Dust Recipe,progression,, -326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -328,Deluxe Fertilizer Recipe,progression,"QI_CRAFTING_RECIPE", -329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -331,Jack-O-Lantern Recipe,progression,"FESTIVAL", -332,Fiber Seeds Recipe,progression,"SPECIAL_ORDER_BOARD", -333,Tub o' Flowers Recipe,progression,"FESTIVAL", -334,Quality Bobber Recipe,progression,"SPECIAL_ORDER_BOARD", -335,Moonlight Jellies Banner,filler,FESTIVAL, -336,Starport Decal,filler,FESTIVAL, -337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -370,Fried Egg Recipe,progression,"CHEFSANITY_STARTER", -371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", -417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -425,Gate Recipe,progression,"CRAFTSANITY", -426,Wood Fence Recipe,progression,"CRAFTSANITY", -427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -428,Grass Starter Recipe,progression,"CRAFTSANITY", -429,Wood Floor Recipe,progression,"CRAFTSANITY", -430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", -431,Straw Floor Recipe,progression,"CRAFTSANITY", -432,Weathered Floor Recipe,progression,"CRAFTSANITY", -433,Crystal Floor Recipe,progression,"CRAFTSANITY", -434,Stone Floor Recipe,progression,"CRAFTSANITY", -435,Stone Walkway Floor Recipe,progression,"CRAFTSANITY", -436,Brick Floor Recipe,progression,"CRAFTSANITY", -437,Wood Path Recipe,progression,"CRAFTSANITY", -438,Gravel Path Recipe,progression,"CRAFTSANITY", -439,Cobblestone Path Recipe,progression,"CRAFTSANITY", -440,Stepping Stone Path Recipe,progression,"CRAFTSANITY", -441,Crystal Path Recipe,progression,"CRAFTSANITY", -442,Wedding Ring Recipe,progression,"CRAFTSANITY", -443,Warp Totem: Desert Recipe,progression,"CRAFTSANITY", -444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -445,Torch Recipe,progression,"CRAFTSANITY", -446,Campfire Recipe,progression,"CRAFTSANITY", -447,Wooden Brazier Recipe,progression,"CRAFTSANITY", -448,Stone Brazier Recipe,progression,"CRAFTSANITY", -449,Gold Brazier Recipe,progression,"CRAFTSANITY", -450,Carved Brazier Recipe,progression,"CRAFTSANITY", -451,Stump Brazier Recipe,progression,"CRAFTSANITY", -452,Barrel Brazier Recipe,progression,"CRAFTSANITY", -453,Skull Brazier Recipe,progression,"CRAFTSANITY", -454,Marble Brazier Recipe,progression,"CRAFTSANITY", -455,Wood Lamp-post Recipe,progression,"CRAFTSANITY", -456,Iron Lamp-post Recipe,progression,"CRAFTSANITY", -457,Furnace Recipe,progression,"CRAFTSANITY", -458,Wicked Statue Recipe,progression,"CRAFTSANITY", -459,Chest Recipe,progression,"CRAFTSANITY", -460,Wood Sign Recipe,progression,"CRAFTSANITY", -461,Stone Sign Recipe,progression,"CRAFTSANITY", -462,Standard Farm,progression,"FARM_TYPE", -463,Riverland Farm,progression,"FARM_TYPE", -464,Forest Farm,progression,"FARM_TYPE", -465,Hill-top Farm,progression,"FARM_TYPE", -466,Wilderness Farm,progression,"FARM_TYPE", -467,Four Corners Farm,progression,"FARM_TYPE", -468,Beach Farm,progression,"FARM_TYPE", -469,Railroad Boulder Removed,progression,, -4001,Burnt,trap,TRAP, -4002,Darkness,trap,TRAP, -4003,Frozen,trap,TRAP, -4004,Jinxed,trap,TRAP, -4005,Nauseated,trap,TRAP, -4006,Slimed,trap,TRAP, -4007,Weakness,trap,TRAP, -4008,Taxes,trap,TRAP, -4009,Random Teleport,trap,TRAP, -4010,The Crows,trap,TRAP, -4011,Monsters,trap,TRAP, -4012,Entrance Reshuffle,trap,"TRAP,DEPRECATED", -4013,Debris,trap,TRAP, -4014,Shuffle,trap,TRAP, -4015,Temporary Winter,trap,"TRAP,DEPRECATED", -4016,Pariah,trap,TRAP, -4017,Drought,trap,TRAP, -5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", -5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", -5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", -5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", -5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", -5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", -5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", -5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", -5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", -5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM", -5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", -5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", -5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", -5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", -5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", -5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", -5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", -5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", -5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", -5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", -5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", -5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", -5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", -5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", -5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", -5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", -5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", -5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", -5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", -5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5207,Fiber Seeds,filler,RESOURCE_PACK, -5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5210,Quality Bobber,filler,RESOURCE_PACK, -5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", -5212,Monster Musk,filler,RESOURCE_PACK, -5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5216,Scarecrow,filler,RESOURCE_PACK, -5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", -5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", -5236,Aquatic Sanctuary,filler,RESOURCE_PACK, -5242,Exotic Double Bed,filler,RESOURCE_PACK, -5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", -5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", -5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5262,Slime Incubator,useful,"RESOURCE_PACK", -5263,Slime Egg-Press,useful,"RESOURCE_PACK", -5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill -10002,Magic Level,progression,SKILL_LEVEL_UP,Magic -10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill -10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology -10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill -10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill -10007,Tractor Garage,useful,,Tractor Mod -10008,Woods Obelisk,progression,,DeepWoods -10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic -10010,Spell: Till,useful,MAGIC_SPELL,Magic -10011,Spell: Water,progression,MAGIC_SPELL,Magic -10012,Spell: Blink,progression,MAGIC_SPELL,Magic -10013,Spell: Evac,useful,MAGIC_SPELL,Magic -10014,Spell: Haste,filler,MAGIC_SPELL,Magic -10015,Spell: Heal,progression,MAGIC_SPELL,Magic -10016,Spell: Buff,useful,MAGIC_SPELL,Magic -10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic -10018,Spell: Fireball,progression,MAGIC_SPELL,Magic -10019,Spell: Frostbite,progression,MAGIC_SPELL,Magic -10020,Spell: Teleport,progression,MAGIC_SPELL,Magic -10021,Spell: Lantern,filler,MAGIC_SPELL,Magic -10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic -10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic -10024,Spell: Descend,progression,MAGIC_SPELL,Magic -10025,Spell: Meteor,progression,MAGIC_SPELL,Magic -10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic -10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic -10028,Spell: Spirit,progression,MAGIC_SPELL,Magic -10029,Spell: Rewind,useful,MAGIC_SPELL,Magic -10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC -10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas -10103,Alec <3,progression,FRIENDSANITY,Alec Revisited -10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba -10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene -10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick -10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) -10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC -10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC -10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley -10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded -10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded -10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded -10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded -10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded -10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded -10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded -10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded -10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded -10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods -10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator -10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded -10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10503,Iridium Bomb,progression,,Stardew Valley Expanded -10504,Krobus' Protection,useful,,Stardew Valley Expanded -10505,Kittyfish Spell,progression,,Stardew Valley Expanded -10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded -10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded -10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded -10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded -10511,Fable Reef Portal,progression,"GINGER_ISLAND",Stardew Valley Expanded -10512,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10513,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10514,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10515,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded -10601,Magic Elixir Recipe,progression,CRAFTSANITY,Magic -10602,Travel Core Recipe,progression,CRAFTSANITY,Magic -10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10606,Glass Bazier Recipe,progression,CRAFTSANITY,Archaeology -10607,Glass Path Recipe,progression,CRAFTSANITY,Archaeology -10608,Glass Fence Recipe,progression,CRAFTSANITY,Archaeology -10609,Bone Path Recipe,progression,CRAFTSANITY,Archaeology -10610,Water Strainer Recipe,progression,CRAFTSANITY,Archaeology -10611,Wooden Display Recipe,progression,CRAFTSANITY,Archaeology -10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology -10613,Warp Totem: Volcano Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Archaeology -10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology -10615,hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology -10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology -10617,Ancient Battery Creator Recipe,progression,CRAFTSANITY,Archaeology - +id,name,classification,groups,mod_name +0,Joja Cola,filler,TRASH, +15,Rusty Key,progression,, +16,Dwarvish Translation Guide,progression,, +17,Bridge Repair,progression,COMMUNITY_REWARD, +18,Greenhouse,progression,COMMUNITY_REWARD, +19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, +20,Minecarts Repair,useful,COMMUNITY_REWARD, +21,Bus Repair,progression,COMMUNITY_REWARD, +22,Progressive Movie Theater,progression,COMMUNITY_REWARD, +23,Stardrop,progression,, +24,Progressive Backpack,progression,, +25,Rusty Sword,filler,"WEAPON,DEPRECATED", +26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", +27,Work Boots,filler,"FOOTWEAR,DEPRECATED", +28,Wooden Blade,filler,"WEAPON,DEPRECATED", +29,Iron Dirk,filler,"WEAPON,DEPRECATED", +30,Wind Spire,filler,"WEAPON,DEPRECATED", +31,Femur,filler,"WEAPON,DEPRECATED", +32,Steel Smallsword,filler,"WEAPON,DEPRECATED", +33,Wood Club,filler,"WEAPON,DEPRECATED", +34,Elf Blade,filler,"WEAPON,DEPRECATED", +37,Slingshot,filler,"WEAPON,DEPRECATED", +38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", +39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", +40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", +41,Silver Saber,filler,"WEAPON,DEPRECATED", +42,Pirate's Sword,filler,"WEAPON,DEPRECATED", +43,Crystal Dagger,filler,"WEAPON,DEPRECATED", +44,Cutlass,filler,"WEAPON,DEPRECATED", +45,Iron Edge,filler,"WEAPON,DEPRECATED", +46,Burglar's Shank,filler,"WEAPON,DEPRECATED", +47,Wood Mallet,filler,"WEAPON,DEPRECATED", +48,Master Slingshot,filler,"WEAPON,DEPRECATED", +49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", +50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", +51,Claymore,filler,"WEAPON,DEPRECATED", +52,Templar's Blade,filler,"WEAPON,DEPRECATED", +53,Kudgel,filler,"WEAPON,DEPRECATED", +54,Shadow Dagger,filler,"WEAPON,DEPRECATED", +55,Obsidian Edge,filler,"WEAPON,DEPRECATED", +56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", +57,Wicked Kris,filler,"WEAPON,DEPRECATED", +58,Bone Sword,filler,"WEAPON,DEPRECATED", +59,Ossified Blade,filler,"WEAPON,DEPRECATED", +60,Space Boots,filler,"FOOTWEAR,DEPRECATED", +61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", +62,Steel Falchion,filler,"WEAPON,DEPRECATED", +63,The Slammer,filler,"WEAPON,DEPRECATED", +64,Skull Key,progression,, +65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, +66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, +67,Progressive Axe,progression,PROGRESSIVE_TOOLS, +68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, +69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, +70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, +71,Golden Scythe,useful,, +72,Progressive Mine Elevator,progression,, +73,Farming Level,progression,SKILL_LEVEL_UP, +74,Fishing Level,progression,SKILL_LEVEL_UP, +75,Foraging Level,progression,SKILL_LEVEL_UP, +76,Mining Level,progression,SKILL_LEVEL_UP, +77,Combat Level,progression,SKILL_LEVEL_UP, +78,Earth Obelisk,progression,WIZARD_BUILDING, +79,Water Obelisk,progression,WIZARD_BUILDING, +80,Desert Obelisk,progression,WIZARD_BUILDING, +81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", +82,Junimo Hut,useful,WIZARD_BUILDING, +83,Gold Clock,progression,WIZARD_BUILDING, +84,Progressive Coop,progression,BUILDING, +85,Progressive Barn,progression,BUILDING, +86,Well,useful,BUILDING, +87,Silo,progression,BUILDING, +88,Mill,progression,BUILDING, +89,Progressive Shed,progression,BUILDING, +90,Fish Pond,progression,BUILDING, +91,Stable,useful,BUILDING, +92,Slime Hutch,progression,BUILDING, +93,Shipping Bin,progression,BUILDING, +94,Beach Bridge,progression,, +95,Adventurer's Guild,progression,, +96,Club Card,progression,, +97,Magnifying Glass,progression,, +98,Bear's Knowledge,useful,, +99,Iridium Snake Milk,useful,, +100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, +101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, +102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, +103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, +104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, +105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, +106,Galaxy Sword,filler,"WEAPON,DEPRECATED", +107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", +108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", +109,Movement Speed Bonus,progression,, +110,Luck Bonus,progression,, +111,Lava Katana,filler,"WEAPON,DEPRECATED", +112,Progressive House,progression,, +113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, +114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, +115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, +116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, +117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, +118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, +119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, +120,Traveling Merchant Stock Size,useful,, +121,Traveling Merchant Discount,useful,, +122,Return Scepter,useful,, +123,Progressive Season,progression,, +124,Spring,progression,SEASON, +125,Summer,progression,SEASON, +126,Fall,progression,SEASON, +127,Winter,progression,SEASON, +128,Amaranth Seeds,progression,CROPSANITY, +129,Artichoke Seeds,progression,CROPSANITY, +130,Beet Seeds,progression,CROPSANITY, +131,Jazz Seeds,progression,CROPSANITY, +132,Blueberry Seeds,progression,CROPSANITY, +133,Bok Choy Seeds,progression,CROPSANITY, +134,Cauliflower Seeds,progression,CROPSANITY, +135,Corn Seeds,progression,CROPSANITY, +136,Cranberry Seeds,progression,CROPSANITY, +137,Eggplant Seeds,progression,CROPSANITY, +138,Fairy Seeds,progression,CROPSANITY, +139,Garlic Seeds,progression,CROPSANITY, +140,Grape Starter,progression,CROPSANITY, +141,Bean Starter,progression,CROPSANITY, +142,Hops Starter,progression,CROPSANITY, +143,Pepper Seeds,progression,CROPSANITY, +144,Kale Seeds,progression,CROPSANITY, +145,Melon Seeds,progression,CROPSANITY, +146,Parsnip Seeds,progression,CROPSANITY, +147,Poppy Seeds,progression,CROPSANITY, +148,Potato Seeds,progression,CROPSANITY, +149,Pumpkin Seeds,progression,CROPSANITY, +150,Radish Seeds,progression,CROPSANITY, +151,Red Cabbage Seeds,progression,CROPSANITY, +152,Rhubarb Seeds,progression,CROPSANITY, +153,Starfruit Seeds,progression,CROPSANITY, +154,Strawberry Seeds,progression,CROPSANITY, +155,Spangle Seeds,progression,CROPSANITY, +156,Sunflower Seeds,progression,CROPSANITY, +157,Tomato Seeds,progression,CROPSANITY, +158,Tulip Bulb,progression,CROPSANITY, +159,Rice Shoot,progression,CROPSANITY, +160,Wheat Seeds,progression,CROPSANITY, +161,Yam Seeds,progression,CROPSANITY, +162,Cactus Seeds,progression,CROPSANITY, +163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +164,Ancient Seeds Recipe,progression,MUSEUM, +165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +166,Traveling Merchant Metal Detector,progression,MUSEUM, +167,Alex <3,progression,FRIENDSANITY, +168,Elliott <3,progression,FRIENDSANITY, +169,Harvey <3,progression,FRIENDSANITY, +170,Sam <3,progression,FRIENDSANITY, +171,Sebastian <3,progression,FRIENDSANITY, +172,Shane <3,progression,FRIENDSANITY, +173,Abigail <3,progression,FRIENDSANITY, +174,Emily <3,progression,FRIENDSANITY, +175,Haley <3,progression,FRIENDSANITY, +176,Leah <3,progression,FRIENDSANITY, +177,Maru <3,progression,FRIENDSANITY, +178,Penny <3,progression,FRIENDSANITY, +179,Caroline <3,progression,FRIENDSANITY, +180,Clint <3,progression,FRIENDSANITY, +181,Demetrius <3,progression,FRIENDSANITY, +182,Dwarf <3,progression,FRIENDSANITY, +183,Evelyn <3,progression,FRIENDSANITY, +184,George <3,progression,FRIENDSANITY, +185,Gus <3,progression,FRIENDSANITY, +186,Jas <3,progression,FRIENDSANITY, +187,Jodi <3,progression,FRIENDSANITY, +188,Kent <3,progression,FRIENDSANITY, +189,Krobus <3,progression,FRIENDSANITY, +190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", +191,Lewis <3,progression,FRIENDSANITY, +192,Linus <3,progression,FRIENDSANITY, +193,Marnie <3,progression,FRIENDSANITY, +194,Pam <3,progression,FRIENDSANITY, +195,Pierre <3,progression,FRIENDSANITY, +196,Robin <3,progression,FRIENDSANITY, +197,Sandy <3,progression,FRIENDSANITY, +198,Vincent <3,progression,FRIENDSANITY, +199,Willy <3,progression,FRIENDSANITY, +200,Wizard <3,progression,FRIENDSANITY, +201,Pet <3,progression,FRIENDSANITY, +202,Rarecrow #1,progression,"FESTIVAL,RARECROW", +203,Rarecrow #2,progression,"FESTIVAL,RARECROW", +204,Rarecrow #3,progression,"FESTIVAL,RARECROW", +205,Rarecrow #4,progression,"FESTIVAL,RARECROW", +206,Rarecrow #5,progression,"FESTIVAL,RARECROW", +207,Rarecrow #6,progression,"FESTIVAL,RARECROW", +208,Rarecrow #7,progression,"FESTIVAL,RARECROW", +209,Rarecrow #8,progression,"FESTIVAL,RARECROW", +210,Straw Hat,filler,FESTIVAL, +211,Golden Pumpkin,useful,FESTIVAL, +212,Barbed Hook,useful,FESTIVAL, +213,Dressed Spinner,useful,FESTIVAL, +214,Magnet,useful,FESTIVAL, +215,Sailor's Cap,filler,FESTIVAL, +216,Pearl,useful,FESTIVAL, +217,Cone Hat,filler,FESTIVAL, +218,Iridium Fireplace,filler,FESTIVAL, +219,Lupini: Red Eagle,filler,FESTIVAL, +220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, +221,Lupini: Solar Kingdom,filler,FESTIVAL, +222,Lupini: Clouds,filler,FESTIVAL, +223,Lupini: 1000 Years From Now,filler,FESTIVAL, +224,Lupini: Three Trees,filler,FESTIVAL, +225,Lupini: The Serpent,filler,FESTIVAL, +226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, +227,Lupini: Land Of Clay,filler,FESTIVAL, +228,Special Order Board,progression,SPECIAL_ORDER_BOARD, +229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, +230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, +231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, +232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, +233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, +234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, +235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, +236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, +237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, +239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +260,Boat Repair,progression,GINGER_ISLAND, +261,Open Professor Snail Cave,progression,"GINGER_ISLAND", +262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", +271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", +275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", +276,Weather Report,useful,"TV_CHANNEL", +277,Fortune Teller,useful,"TV_CHANNEL", +278,Livin' Off The Land,useful,"TV_CHANNEL", +279,The Queen of Sauce,progression,"TV_CHANNEL", +280,Fishing Information Broadcasting Service,useful,"TV_CHANNEL", +281,Sinister Signal,useful,"TV_CHANNEL", +282,Dark Talisman,progression,, +283,Ostrich Incubator Recipe,progression,"GINGER_ISLAND", +284,Cute Baby,progression,"BABY", +285,Ugly Baby,progression,"BABY", +286,Deluxe Scarecrow Recipe,progression,"RARECROW", +287,Treehouse,progression,"GINGER_ISLAND", +288,Coffee Bean,progression,CROPSANITY, +289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +294,Progressive Footwear,useful,"FOOTWEAR", +295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" +308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +325,Fairy Dust Recipe,progression,, +326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +328,Deluxe Fertilizer Recipe,progression,"QI_CRAFTING_RECIPE", +329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +331,Jack-O-Lantern Recipe,progression,"FESTIVAL", +332,Fiber Seeds Recipe,progression,"SPECIAL_ORDER_BOARD", +333,Tub o' Flowers Recipe,progression,"FESTIVAL", +334,Quality Bobber Recipe,progression,"SPECIAL_ORDER_BOARD", +335,Moonlight Jellies Banner,filler,FESTIVAL, +336,Starport Decal,filler,FESTIVAL, +337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +370,Fried Egg Recipe,progression,"CHEFSANITY_STARTER", +371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", +417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +425,Gate Recipe,progression,"CRAFTSANITY", +426,Wood Fence Recipe,progression,"CRAFTSANITY", +427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +428,Grass Starter Recipe,progression,"CRAFTSANITY", +429,Wood Floor Recipe,progression,"CRAFTSANITY", +430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", +431,Straw Floor Recipe,progression,"CRAFTSANITY", +432,Weathered Floor Recipe,progression,"CRAFTSANITY", +433,Crystal Floor Recipe,progression,"CRAFTSANITY", +434,Stone Floor Recipe,progression,"CRAFTSANITY", +435,Stone Walkway Floor Recipe,progression,"CRAFTSANITY", +436,Brick Floor Recipe,progression,"CRAFTSANITY", +437,Wood Path Recipe,progression,"CRAFTSANITY", +438,Gravel Path Recipe,progression,"CRAFTSANITY", +439,Cobblestone Path Recipe,progression,"CRAFTSANITY", +440,Stepping Stone Path Recipe,progression,"CRAFTSANITY", +441,Crystal Path Recipe,progression,"CRAFTSANITY", +442,Wedding Ring Recipe,progression,"CRAFTSANITY", +443,Warp Totem: Desert Recipe,progression,"CRAFTSANITY", +444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +445,Torch Recipe,progression,"CRAFTSANITY", +446,Campfire Recipe,progression,"CRAFTSANITY", +447,Wooden Brazier Recipe,progression,"CRAFTSANITY", +448,Stone Brazier Recipe,progression,"CRAFTSANITY", +449,Gold Brazier Recipe,progression,"CRAFTSANITY", +450,Carved Brazier Recipe,progression,"CRAFTSANITY", +451,Stump Brazier Recipe,progression,"CRAFTSANITY", +452,Barrel Brazier Recipe,progression,"CRAFTSANITY", +453,Skull Brazier Recipe,progression,"CRAFTSANITY", +454,Marble Brazier Recipe,progression,"CRAFTSANITY", +455,Wood Lamp-post Recipe,progression,"CRAFTSANITY", +456,Iron Lamp-post Recipe,progression,"CRAFTSANITY", +457,Furnace Recipe,progression,"CRAFTSANITY", +458,Wicked Statue Recipe,progression,"CRAFTSANITY", +459,Chest Recipe,progression,"CRAFTSANITY", +460,Wood Sign Recipe,progression,"CRAFTSANITY", +461,Stone Sign Recipe,progression,"CRAFTSANITY", +462,Standard Farm,progression,"FARM_TYPE", +463,Riverland Farm,progression,"FARM_TYPE", +464,Forest Farm,progression,"FARM_TYPE", +465,Hill-top Farm,progression,"FARM_TYPE", +466,Wilderness Farm,progression,"FARM_TYPE", +467,Four Corners Farm,progression,"FARM_TYPE", +468,Beach Farm,progression,"FARM_TYPE", +469,Railroad Boulder Removed,progression,, +4001,Burnt,trap,TRAP, +4002,Darkness,trap,TRAP, +4003,Frozen,trap,TRAP, +4004,Jinxed,trap,TRAP, +4005,Nauseated,trap,TRAP, +4006,Slimed,trap,TRAP, +4007,Weakness,trap,TRAP, +4008,Taxes,trap,TRAP, +4009,Random Teleport,trap,TRAP, +4010,The Crows,trap,TRAP, +4011,Monsters,trap,TRAP, +4012,Entrance Reshuffle,trap,"TRAP,DEPRECATED", +4013,Debris,trap,TRAP, +4014,Shuffle,trap,TRAP, +4015,Temporary Winter,trap,"TRAP,DEPRECATED", +4016,Pariah,trap,TRAP, +4017,Drought,trap,TRAP, +5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", +5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", +5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", +5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", +5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", +5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", +5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", +5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", +5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", +5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM", +5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", +5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", +5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", +5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", +5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", +5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", +5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", +5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", +5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", +5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", +5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", +5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", +5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", +5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", +5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", +5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", +5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", +5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", +5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", +5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5207,Fiber Seeds,filler,RESOURCE_PACK, +5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5210,Quality Bobber,filler,RESOURCE_PACK, +5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", +5212,Monster Musk,filler,RESOURCE_PACK, +5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5216,Scarecrow,filler,RESOURCE_PACK, +5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", +5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", +5236,Aquatic Sanctuary,filler,RESOURCE_PACK, +5242,Exotic Double Bed,filler,RESOURCE_PACK, +5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", +5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", +5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5262,Slime Incubator,useful,"RESOURCE_PACK", +5263,Slime Egg-Press,useful,"RESOURCE_PACK", +5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill +10002,Magic Level,progression,SKILL_LEVEL_UP,Magic +10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill +10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology +10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill +10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill +10007,Tractor Garage,useful,,Tractor Mod +10008,Woods Obelisk,progression,,DeepWoods +10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic +10010,Spell: Till,useful,MAGIC_SPELL,Magic +10011,Spell: Water,progression,MAGIC_SPELL,Magic +10012,Spell: Blink,progression,MAGIC_SPELL,Magic +10013,Spell: Evac,useful,MAGIC_SPELL,Magic +10014,Spell: Haste,filler,MAGIC_SPELL,Magic +10015,Spell: Heal,progression,MAGIC_SPELL,Magic +10016,Spell: Buff,useful,MAGIC_SPELL,Magic +10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic +10018,Spell: Fireball,progression,MAGIC_SPELL,Magic +10019,Spell: Frostbite,progression,MAGIC_SPELL,Magic +10020,Spell: Teleport,progression,MAGIC_SPELL,Magic +10021,Spell: Lantern,filler,MAGIC_SPELL,Magic +10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic +10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic +10024,Spell: Descend,progression,MAGIC_SPELL,Magic +10025,Spell: Meteor,progression,MAGIC_SPELL,Magic +10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic +10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic +10028,Spell: Spirit,progression,MAGIC_SPELL,Magic +10029,Spell: Rewind,useful,MAGIC_SPELL,Magic +10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC +10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas +10103,Alec <3,progression,FRIENDSANITY,Alec Revisited +10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba +10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene +10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick +10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) +10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC +10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC +10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley +10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded +10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded +10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded +10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded +10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded +10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded +10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded +10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded +10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods +10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator +10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded +10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10503,Iridium Bomb,progression,,Stardew Valley Expanded +10504,Krobus' Protection,useful,,Stardew Valley Expanded +10505,Kittyfish Spell,progression,,Stardew Valley Expanded +10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded +10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded +10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded +10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded +10513,Fable Reef Portal,progression,"GINGER_ISLAND",Stardew Valley Expanded +10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10517,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded +10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded +10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded +10520,Morgan's Schooling,progression,,Stardew Valley Expanded +10601,Magic Elixir Recipe,progression,CRAFTSANITY,Magic +10602,Travel Core Recipe,progression,CRAFTSANITY,Magic +10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10606,Glass Bazier Recipe,progression,CRAFTSANITY,Archaeology +10607,Glass Path Recipe,progression,CRAFTSANITY,Archaeology +10608,Glass Fence Recipe,progression,CRAFTSANITY,Archaeology +10609,Bone Path Recipe,progression,CRAFTSANITY,Archaeology +10610,Water Strainer Recipe,progression,CRAFTSANITY,Archaeology +10611,Wooden Display Recipe,progression,CRAFTSANITY,Archaeology +10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology +10613,Warp Totem: Volcano Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Archaeology +10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology +10615,hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology +10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology +10617,Ancient Battery Creator Recipe,progression,CRAFTSANITY,Archaeology + diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 0e8bdf7dafce..5e349a33f4f0 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -42,5 +42,5 @@ def initialize_rules(self): def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", - "Nexus: Outpost Runes"] + "Nexus: Outpost Runes", "Nexus: Farm Runes", "Nexus: Wizard Runes"] return Or(*(self.logic.received(rune) for rune in rune_list)) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 7d0df7525008..03d736157ac3 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -133,12 +133,27 @@ stardew_valley_expanded_regions = [ RegionData(Region.backwoods, [SVEEntrance.backwoods_to_grove]), + RegionData(SVERegion.enchanted_grove, [SVEEntrance.grove_to_outpost_warp, SVEEntrance.grove_to_wizard_warp, + SVEEntrance.grove_to_farm_warp, SVEEntrance.grove_to_guild_warp, SVEEntrance.grove_to_junimo_warp, + SVEEntrance.grove_to_spring_warp, SVEEntrance.grove_to_aurora_warp]), + RegionData(SVERegion.grove_farm_warp, [SVEEntrance.farm_warp_to_farm]), + RegionData(SVERegion.grove_aurora_warp, [SVEEntrance.aurora_warp_to_aurora]), + RegionData(SVERegion.grove_guild_warp, [SVEEntrance.guild_warp_to_guild]), + RegionData(SVERegion.grove_junimo_warp, [SVEEntrance.junimo_warp_to_junimo]), + RegionData(SVERegion.grove_spring_warp, [SVEEntrance.spring_warp_to_spring]), + RegionData(SVERegion.grove_outpost_warp, [SVEEntrance.outpost_warp_to_outpost]), + RegionData(SVERegion.grove_wizard_warp, [SVEEntrance.wizard_warp_to_wizard]), + RegionData(SVERegion.galmoran_outpost, [SVEEntrance.outpost_to_badlands_entrance, SVEEntrance.use_alesia_shop, + SVEEntrance.use_issac_shop]), + RegionData(SVERegion.badlands_entrance, [SVEEntrance.badlands_entrance_to_badlands]), + RegionData(SVERegion.crimson_badlands, [SVEEntrance.badlands_to_cave]), + RegionData(SVERegion.badlands_cave), RegionData(Region.bus_stop, [SVEEntrance.bus_stop_to_shed]), RegionData(SVERegion.grandpas_shed, [SVEEntrance.grandpa_shed_to_interior, SVEEntrance.grandpa_shed_to_town]), - RegionData(SVERegion.grandpas_shed_interior, [SVEEntrance.to_grandpa_upstairs]), + RegionData(SVERegion.grandpas_shed_interior, [SVEEntrance.grandpa_interior_to_upstairs]), RegionData(SVERegion.grandpas_shed_upstairs), RegionData(Region.forest, - [SVEEntrance.forest_to_fairhaven, SVEEntrance.forest_to_west, SVEEntrance.forest_to_junimo, + [SVEEntrance.forest_to_fairhaven, SVEEntrance.forest_to_west, SVEEntrance.forest_to_lost_woods, SVEEntrance.forest_to_bmv, SVEEntrance.forest_to_marnie_shed]), RegionData(SVERegion.marnies_shed), RegionData(SVERegion.fairhaven_farm), @@ -152,12 +167,16 @@ RegionData(SVERegion.shearwater), RegionData(Region.mountain, [SVEEntrance.mountain_to_guild_summit]), RegionData(SVERegion.guild_summit, [SVEEntrance.guild_to_interior, SVEEntrance.guild_to_mines, - SVEEntrance.summit_to_boat]), - RegionData(SVERegion.marlon_boat, [SVEEntrance.boat_to_highlands]), - RegionData(Region.railroad, [SVEEntrance.to_susan_house, SVEEntrance.enter_summit]), + SVEEntrance.summit_to_highlands]), + RegionData(Region.railroad, [SVEEntrance.to_susan_house, SVEEntrance.enter_summit, SVEEntrance.railroad_to_grampleton_station]), + RegionData(SVERegion.grampleton_station, [SVEEntrance.grampleton_station_to_grampleton_suburbs]), + RegionData(SVERegion.grampleton_suburbs, [SVEEntrance.grampleton_suburbs_to_scarlett_house]), + RegionData(SVERegion.scarlett_house), RegionData(Region.wizard_basement, [SVEEntrance.wizard_to_fable_reef]), RegionData(SVERegion.fable_reef, [SVEEntrance.fable_reef_to_guild]), - RegionData(SVERegion.first_slash_guild), + RegionData(SVERegion.first_slash_guild, [SVEEntrance.first_slash_guild_to_hallway]), + RegionData(SVERegion.first_slash_hallway, [SVEEntrance.first_slash_hallway_to_room]), + RegionData(SVERegion.first_slash_spare_room), RegionData(SVERegion.highlands, [SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave]), RegionData(SVERegion.highlands_cavern, [SVEEntrance.to_dwarf_prison]), RegionData(SVERegion.dwarf_prison), @@ -168,18 +187,12 @@ RegionData(SVERegion.aurora_vineyard_basement), RegionData(Region.secret_woods, [SVEEntrance.secret_woods_to_west]), RegionData(SVERegion.bear_shop), - RegionData(SVERegion.sprite_spring), + RegionData(SVERegion.sprite_spring, [SVEEntrance.sprite_spring_to_cave]), + RegionData(SVERegion.sprite_spring_cave), + RegionData(SVERegion.lost_woods, [SVEEntrance.lost_woods_to_junimo_woods]), RegionData(SVERegion.junimo_woods, [SVEEntrance.use_purple_junimo]), RegionData(SVERegion.purple_junimo_shop), - RegionData(SVERegion.enchanted_grove, [SVEEntrance.grove_to_outpost, SVEEntrance.grove_to_wizard, - SVEEntrance.grove_to_farm, SVEEntrance.grove_to_guild, SVEEntrance.grove_to_junimo, - SVEEntrance.grove_to_spring, SVEEntrance.grove_to_aurora]), - RegionData(SVERegion.galmoran_outpost, [SVEEntrance.outpost_to_badlands_entrance, SVEEntrance.use_alesia_shop, - SVEEntrance.use_issac_shop, SVEEntrance.to_outpost_roof]), - RegionData(SVERegion.outpost_roof), - RegionData(SVERegion.badlands_entrance, [SVEEntrance.badlands_entrance_to_badlands]), - RegionData(SVERegion.crimson_badlands, [SVEEntrance.badlands_to_cave]), - RegionData(SVERegion.badlands_cave), + RegionData(SVERegion.alesia_shop), RegionData(SVERegion.issac_shop), RegionData(SVERegion.summit), @@ -198,25 +211,31 @@ ConnectionData(SVEEntrance.town_to_bridge, SVERegion.shearwater), ConnectionData(SVEEntrance.plot_to_bridge, SVERegion.shearwater), ConnectionData(SVEEntrance.bus_stop_to_shed, SVERegion.grandpas_shed), - ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior, flag=RandomizationFlag.NON_PROGRESSION| RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.to_grandpa_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.boat_to_highlands, SVERegion.highlands, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands), ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.grove_to_outpost, SVERegion.galmoran_outpost, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.grove_to_wizard, Region.wizard_basement, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.grove_to_aurora, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp), + ConnectionData(SVEEntrance.outpost_warp_to_outpost, SVERegion.galmoran_outpost, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_wizard_warp, SVERegion.grove_wizard_warp), + ConnectionData(SVEEntrance.wizard_warp_to_wizard, Region.wizard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_aurora_warp, SVERegion.grove_aurora_warp), + ConnectionData(SVEEntrance.aurora_warp_to_aurora, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_farm_warp, SVERegion.grove_farm_warp), ConnectionData(SVEEntrance.to_aurora_basement, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.grove_to_farm, Region.farm, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.grove_to_guild, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.grove_to_junimo, SVERegion.junimo_woods, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.farm_warp_to_farm, Region.farm, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_guild_warp, SVERegion.grove_guild_warp), + ConnectionData(SVEEntrance.guild_warp_to_guild, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_junimo_warp, SVERegion.grove_junimo_warp), + ConnectionData(SVEEntrance.junimo_warp_to_junimo, SVERegion.junimo_woods, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), - ConnectionData(SVEEntrance.grove_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.grove_to_spring_warp, SVERegion.grove_spring_warp), + ConnectionData(SVEEntrance.spring_warp_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.to_outpost_roof, SVERegion.outpost_roof, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.NON_PROGRESSION), @@ -226,7 +245,8 @@ ConnectionData(SVEEntrance.forest_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.secret_woods_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.forest_to_junimo, SVERegion.junimo_woods, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_to_lost_woods, SVERegion.lost_woods, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.lost_woods_to_junimo_woods, SVERegion.junimo_woods), ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.NON_PROGRESSION), @@ -240,6 +260,12 @@ ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop), ConnectionData(SVEEntrance.use_issac_shop, SVERegion.issac_shop), ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.railroad_to_grampleton_station, SVERegion.grampleton_station), + ConnectionData(SVEEntrance.grampleton_station_to_grampleton_suburbs, SVERegion.grampleton_suburbs), + ConnectionData(SVEEntrance.grampleton_suburbs_to_scarlett_house, SVERegion.scarlett_house, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.first_slash_guild_to_hallway, SVERegion.first_slash_hallway, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS) ] vanilla_connections_to_remove_by_mod = { diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index e678bd8a3e3a..f03476b509ee 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -893,8 +893,8 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.sve not in world_options.mods: return - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_to_junimo, player), - logic.received("Abandoned House Outskirts Clean-up")) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_to_lost_woods, player), + logic.bundle.can_complete_community_center) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), logic.received("Iridium Bomb")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), @@ -907,23 +907,23 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.received("Fable Reef Portal")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_aurora, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.aurora_warp_to_aurora, player), logic.received("Nexus: Aurora Vineyard Runes")) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_farm, player), - logic.mod.sve.has_any_rune()) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_guild, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.farm_warp_to_farm, player), + logic.received("Nexus: Farm Runes")) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.guild_warp_to_guild, player), logic.received("Nexus: Adventurer's Guild Runes")) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_junimo, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.junimo_warp_to_junimo, player), logic.received("Nexus: Junimo Woods Runes")) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_spring, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.spring_warp_to_spring, player), logic.received("Nexus: Sprite Spring Runes")) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_outpost, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.outpost_warp_to_outpost, player), logic.received("Nexus: Outpost Runes")) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grove_to_wizard, player), - logic.mod.sve.has_any_rune()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_warp_to_wizard, player), + logic.received("Nexus: Wizard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), logic.relationship.has_hearts(ModNPC.apples, 10)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.to_grandpa_upstairs, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), logic.quest.can_complete_quest(ModQuest.GrandpasShed)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) @@ -939,7 +939,7 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.summit_to_boat, player), + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.summit_to_highlands, player), logic.received("Marlon's Boat Paddle")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), logic.received("Fable Reef Portal")) diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 1bf2ec203460..cb41c13ed3cb 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -260,21 +260,29 @@ class RileyEntrance: class SVEEntrance: backwoods_to_grove = "Backwoods to Enchanted Grove" - grove_to_outpost = "Enchanted Grove to Galmoran Outpost" - grove_to_wizard = "Enchanted Grove to Wizard's Tower" - grove_to_aurora = "Enchanted Grove to Aurora Vineyard Basement" - grove_to_farm = "Enchanted Grove to Farm" - grove_to_guild = "Enchanted Grove to Adventurer's Guild Summit" - grove_to_junimo = "Enchanted Grove to Junimo Woods" - grove_to_spring = "Enchanted Grove to Sprite Springs" - wizard_to_fable_reef = "Wizard's Basement to Fable Reef" + grove_to_outpost_warp = "Enchanted Grove to Grove Outpost Warp" + outpost_warp_to_outpost = "Grove Outpost Warp to Galmoran Outpost" + grove_to_wizard_warp = "Enchanted Grove to Grove Wizard Warp" + wizard_warp_to_wizard = "Grove Wizard Warp to Wizard Basement" + grove_to_aurora_warp = "Enchanted Grove to Grove Aurora Vineyard Warp" + aurora_warp_to_aurora = "Grove Aurora Vineyard Warp to Aurora Vineyard Basement" + grove_to_farm_warp = "Enchanted Grove to Grove Farm Warp" + farm_warp_to_farm = "Grove Farm Warp to Farm" + grove_to_guild_warp = "Enchanted Grove to Grove Adventurer's Guild Warp" + guild_warp_to_guild = "Grove Adventurer's Guild Warp to Adventurer's Guild Summit" + grove_to_junimo_warp = "Enchanted Grove to Grove Junimo Woods Warp" + junimo_warp_to_junimo = "Grove Junimo Woods Warp to Junimo Woods" + grove_to_spring_warp = "Enchanted Grove to Grove Sprite Spring Warp" + spring_warp_to_spring = "Grove Sprite Spring Warp to Sprite Spring" + wizard_to_fable_reef = "Wizard Basement to Fable Reef" bus_stop_to_shed = "Bus Stop to Grandpa's Shed" grandpa_shed_to_interior = "Grandpa's Shed to Grandpa's Shed Interior" grandpa_shed_to_town = "Grandpa's Shed to Town" - to_grandpa_upstairs = "Grandpa's Shed to Grandpa's Shed Upstairs" + grandpa_interior_to_upstairs = "Grandpa's Shed Interior to Grandpa's Shed Upstairs" forest_to_fairhaven = "Forest to Fairhaven Farm" forest_to_west = "Forest to Forest West" - forest_to_junimo = "Forest to Junimo Woods" + forest_to_lost_woods = "Forest to Lost Woods" + lost_woods_to_junimo_woods = "Lost Woods to Junimo Woods" use_purple_junimo = "Talk to Purple Junimo" forest_to_bmv = "Forest to Blue Moon Vineyard" forest_to_marnie_shed = "Forest to Marnie's Shed" @@ -284,13 +292,13 @@ class SVEEntrance: town_to_plot = "Town to Unclaimed Plot" bmv_to_sophia = "Blue Moon Vineyard to Sophia's House" bmv_to_beach = "Blue Moon Vineyard to Beach" - jenkins_to_cellar = "Jenkins' House to Jenkins' Cellar" + jenkins_to_cellar = "Jenkins' Residence to Jenkins' Cellar" plot_to_bridge = "Unclaimed Plot to Shearwater Bridge" mountain_to_guild_summit = "Mountain to Adventurer's Guild Summit" guild_to_interior = "Adventurer's Guild Summit to Adventurer's Guild" guild_to_mines = "Adventurer's Guild Summit to The Mines" summit_to_boat = "Adventurer's Guild Summit to Marlon's Boat" - boat_to_highlands = "Marlon's Boat to Highlands" + summit_to_highlands = "Adventurer's Guild Summit to Highlands" to_aurora_basement = "Aurora Vineyard to Aurora Vineyard Basement" outpost_to_badlands_entrance = "Galmoran Outpost to Badlands Entrance" use_alesia_shop = "Talk to Alesia" @@ -301,14 +309,20 @@ class SVEEntrance: enter_summit = "Railroad to Summit" fable_reef_to_guild = "Fable Reef to First Slash Guild" highlands_to_lance = "Highlands to Lance's House Main" - highlands_to_cave = "Highlands to Highlands Cave" - to_dwarf_prison = "Highlands Cave to Dwarf Prison" + highlands_to_cave = "Highlands to Highlands Cavern" + to_dwarf_prison = "Highlands Cavern to Highlands Cavern Prison" lance_ladder_to_highlands = "Lance's House Ladder to Highlands" - forest_west_to_spring = "Forest West to Sprite Springs" + forest_west_to_spring = "Forest West to Sprite Spring" west_to_aurora = "Forest West to Aurora Vineyard" use_bear_shop = "Talk to Bear Shop" secret_woods_to_west = "Secret Woods to Forest West" to_outpost_roof = "Galmoran Outpost to Galmoran Outpost Roof" + railroad_to_grampleton_station = "Railroad to Grampleton Station" + grampleton_station_to_grampleton_suburbs = "Grampleton Station to Grampleton Suburbs" + grampleton_suburbs_to_scarlett_house = "Grampleton Suburbs to Scarlett's House" + first_slash_guild_to_hallway = "First Slash Guild to First Slash Hallway" + first_slash_hallway_to_room = "First Slash Hallway to First Slash Spare Room" + sprite_spring_to_cave = "Sprite Spring to Sprite Spring Cave" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 1bbeeedd98b4..9674f0879e55 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -220,8 +220,16 @@ class RileyRegion: class SVERegion: grandpas_shed = "Grandpa's Shed" + grandpas_shed_front_door = "Grandpa's Shed Front Door" grandpas_shed_interior = "Grandpa's Shed Interior" grandpas_shed_upstairs = "Grandpa's Shed Upstairs" + grove_outpost_warp = "Grove Outpost Warp" + grove_wizard_warp = "Grove Wizard Warp" + grove_farm_warp = "Grove Farm Warp" + grove_aurora_warp = "Grove Aurora Vineyard Warp" + grove_guild_warp = "Grove Adventurer's Guild Warp" + grove_junimo_warp = "Grove Junimo Woods Warp" + grove_spring_warp = "Grove Sprite Spring Warp" marnies_shed = "Marnie's Shed" fairhaven_farm = "Fairhaven Farm" blue_moon_vineyard = "Blue Moon Vineyard" @@ -235,13 +243,14 @@ class SVERegion: first_slash_guild = "First Slash Guild" highlands = "Highlands" highlands_cavern = "Highlands Cavern" - dwarf_prison = "Drawf Prison" + dwarf_prison = "Highlands Cavern Prison" lances_house = "Lance's House" forest_west = "Forest West" aurora_vineyard = "Aurora Vineyard" aurora_vineyard_basement = "Aurora Vineyard Basement" bear_shop = "Bear Shop" sprite_spring = "Sprite Spring" + lost_woods = "Lost Woods" junimo_woods = "Junimo Woods" purple_junimo_shop = "Purple Junimo Shop" enchanted_grove = "Enchanted Grove" @@ -255,4 +264,10 @@ class SVERegion: marlon_boat = "Marlon's Boat" badlands_cave = "Badlands Cave" outpost_roof = "Galmoran Outpost Roof" + grampleton_station = "Grampleton Station" + grampleton_suburbs = "Grampleton Suburbs" + scarlett_house = "Scarlett's House" + first_slash_hallway = "First Slash Hallway" + first_slash_spare_room = "First Slash Spare Room" + sprite_spring_cave = "Sprite Spring Cave" From 63db7ea8b38545ac750225b767f13cc9f880c56f Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:05:16 -0600 Subject: [PATCH 273/482] Add SVE Quest Iterable --- worlds/stardew_valley/items.py | 11 ++++------- worlds/stardew_valley/mods/logic/quests_logic.py | 2 +- .../strings/ap_names/mods/mod_items.py | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 worlds/stardew_valley/strings/ap_names/mods/mod_items.py diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 4809ef8fff8c..b3d14d8a5838 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -17,6 +17,7 @@ from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff from .strings.ap_names.event_names import Event +from .strings.ap_names.mods.mod_items import SVEQuestItem from .strings.villager_names import NPC, ModNPC from .strings.wallet_item_names import Wallet @@ -571,15 +572,11 @@ def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true if ModNames.sve not in options.mods: return - items.append(item_factory("Iridium Bomb")) - items.append(item_factory("Krobus' Protection")) - items.append(item_factory("Kittyfish Spell")) - items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP]]) + items.extend([item_factory(item) for item in SVEQuestItem.sve_quest_items]) + items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP] if item.mod_name == ModNames.sve]) if exclude_ginger_island: return - items.append(item_factory("Diamond Wand")) - items.append(item_factory("Marlon's Boat Paddle")) - items.append(item_factory("Fable Reef Portal")) + items.extend([item_factory(item) for item in SVEQuestItem.sve_quest_items_ginger_island]) def create_unique_filler_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random, diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index c41c4cb46409..34733f825aeb 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -72,7 +72,7 @@ def _get_sve_quest_rules(self): ModQuest.RailroadBoulder: self.logic.received(Wallet.skull_key) & self.logic.has((Ore.iridium, Material.coal)) & self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad), ModQuest.GrandpasShed: self.logic.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & - self.logic.region.can_reach(SVERegion.grandpas_shed_interior), + self.logic.region.can_reach(SVERegion.grandpas_shed), ModQuest.MarlonsBoat: self.logic.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py new file mode 100644 index 000000000000..1a16c4ab9267 --- /dev/null +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -0,0 +1,16 @@ +from typing import List + + +class SVEQuestItem: + aurora_vineyard_tablet = "Aurora Vineyard Tablet" + iridium_bomb = "Iridium Bomb" + void_soul = "Krobus' Protection" + kittyfish_spell = "Kittyfish Spell" + scarlett_job_offer = "Scarlett's Job Offer" + morgan_schooling = "Morgan's Schooling" + diamond_wand = "Diamond Wand" + marlon_boat_paddle = "Marlon's Boat Paddle" + fable_reef_portal = "Fable Reef Portal" + + sve_quest_items: List[str] = [aurora_vineyard_tablet, iridium_bomb, void_soul, kittyfish_spell, scarlett_job_offer, morgan_schooling] + sve_quest_items_ginger_island: List[str] = [diamond_wand, marlon_boat_paddle, fable_reef_portal] From 9b75d2cc2964032ae734612e362a033622b75449 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:08:15 -0600 Subject: [PATCH 274/482] Fix craftables --- worlds/stardew_valley/data/craftable_data.py | 2 +- worlds/stardew_valley/data/items.csv | 6 +- worlds/stardew_valley/data/locations.csv | 5546 ++++++++--------- worlds/stardew_valley/mods/logic/sve_logic.py | 11 + worlds/stardew_valley/rules.py | 4 +- .../stardew_valley/strings/craftable_names.py | 6 +- 6 files changed, 2794 insertions(+), 2781 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 5c836c7f7bd0..4bce46432ec8 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -269,7 +269,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, glass_path = skill_recipe(ModFloor.glass_path, ModSkill.archaeology, 1, {Artifact.glass_shards: 1}, ModNames.archaeology) glass_fence = skill_recipe(ModCraftable.glass_fence, ModSkill.archaeology, 1, {Artifact.glass_shards: 5}, ModNames.archaeology) bone_path = skill_recipe(ModFloor.bone_path, ModSkill.archaeology, 3, {Fossil.bone_fragment: 1}, ModNames.archaeology) -water_strainer = skill_recipe(ModCraftable.water_strainer, ModSkill.archaeology, 4, {Material.wood: 40, MetalBar.copper: 4}, ModNames.archaeology) +water_shifter = skill_recipe(ModCraftable.water_shifter, ModSkill.archaeology, 4, {Material.wood: 40, MetalBar.copper: 4}, ModNames.archaeology) wooden_display = skill_recipe(ModCraftable.wooden_display, ModSkill.archaeology, 2, {Material.wood: 25}, ModNames.archaeology) hardwood_display = skill_recipe(ModCraftable.hardwood_display, ModSkill.archaeology, 7, {Material.hardwood: 10}, ModNames.archaeology) volcano_totem = skill_recipe(ModConsumable.volcano_totem, ModSkill.archaeology, 9, {Material.cinder_shard: 5, Artifact.rare_disc: 1, Artifact.dwarf_gadget: 1}, diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 261ae60ee502..adc5af611263 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -816,12 +816,12 @@ id,name,classification,groups,mod_name 10607,Glass Path Recipe,progression,CRAFTSANITY,Archaeology 10608,Glass Fence Recipe,progression,CRAFTSANITY,Archaeology 10609,Bone Path Recipe,progression,CRAFTSANITY,Archaeology -10610,Water Strainer Recipe,progression,CRAFTSANITY,Archaeology +10610,Water Shifter Recipe,progression,CRAFTSANITY,Archaeology 10611,Wooden Display Recipe,progression,CRAFTSANITY,Archaeology 10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology -10613,Warp Totem: Volcano Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Archaeology +10613,Dwarf Gadget: Infinite Volcano Simulation Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Archaeology 10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology 10615,hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology 10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology -10617,Ancient Battery Creator Recipe,progression,CRAFTSANITY,Archaeology +10617,Ancient Battery Production Station Recipe,progression,CRAFTSANITY,Archaeology diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 041fb0f4feb2..c0b2f42c6739 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1,2773 +1,2773 @@ -id,region,name,tags,mod_name -1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", -32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", -34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", -35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", -37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", -40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -80,Vault,"500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -84,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -85,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -87,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -88,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -92,Vault,"Gambler's Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -93,Vault,"Carnival Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -94,Vault,"Walnut Hunter Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -95,Vault,"Qi's Helper Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -101,Pierre's General Store,Large Pack,BACKPACK, -102,Pierre's General Store,Deluxe Pack,BACKPACK, -103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", -202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", -203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", -204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", -205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", -206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", -207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", -208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", -209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", -210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", -211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", -212,Quarry Mine,Grim Reaper statue,MANDATORY, -213,The Mines,The Mines Entrance Cutscene,MANDATORY, -214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, -215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, -216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, -217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, -218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, -219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, -220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, -221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, -222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, -223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, -224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, -225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, -226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, -227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, -228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, -229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, -230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, -231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, -232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, -233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, -234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, -235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, -236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, -237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, -251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", -301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", -302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", -303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", -304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", -305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", -306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", -307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", -308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", -309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", -310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", -311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", -332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", -333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", -334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", -335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", -336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", -337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", -338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", -339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", -340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", -341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, -402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, -403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, -404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, -405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, -406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, -407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, -408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, -409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, -410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, -411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, -412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, -413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, -414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, -415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, -416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, -417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, -418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, -501,Town,Introductions,"MANDATORY,QUEST", -502,Town,How To Win Friends,"MANDATORY,QUEST", -503,Farm,Getting Started,"MANDATORY,QUEST", -504,Farm,Raising Animals,"MANDATORY,QUEST", -505,Farm,Advancement,"MANDATORY,QUEST", -506,Museum,Archaeology,"MANDATORY,QUEST", -507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", -508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", -509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", -510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", -511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", -512,Sam's House,Jodi's Request,"MANDATORY,QUEST", -513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", -514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", -515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", -516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", -517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", -518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", -519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", -520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", -521,Alex's House,Knee Therapy,"MANDATORY,QUEST", -522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", -523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", -524,Desert,The Mysterious Qi,"MANDATORY,QUEST", -525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", -526,Town,A Winter Mystery,"MANDATORY,QUEST", -527,Secret Woods,Strange Note,"MANDATORY,QUEST", -528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", -529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", -530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", -531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", -532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", -533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", -534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", -535,Sam's House,Fish Casserole,"MANDATORY,QUEST", -536,Fishing,Catch A Squid,"MANDATORY,QUEST", -537,Saloon,Fish Stew,"MANDATORY,QUEST", -538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", -539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", -540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", -541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", -542,Alex's House,Granny's Gift,"MANDATORY,QUEST", -543,Desert,Exotic Spirits,"MANDATORY,QUEST", -544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", -545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Mutant Bug Lair,Dark Talisman,"MANDATORY,QUEST", -547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", -548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", -601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", -602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", -603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", -604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", -605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", -606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", -607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", -608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", -609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", -610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", -611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", -612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", -613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", -614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", -615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", -616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", -617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", -618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", -619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", -620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", -621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", -701,Secret Woods,Old Master Cannoli,MANDATORY, -702,Beach,Beach Bridge Repair,MANDATORY, -703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,"BABY", -705,Farmhouse,Have Another Baby,"BABY", -706,Farmhouse,Spouse Stardrop,, -707,Sewer,Krobus Stardrop,"MANDATORY", -801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, -802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, -803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, -804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, -805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, -806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, -807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, -808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, -811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, -821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, -822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, -823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, -824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, -825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, -826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, -827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, -828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, -841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, -842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, -843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, -844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, -845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, -846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, -847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, -848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, -849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, -850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, -851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, -852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, -853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, -854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, -855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, -856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, -857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, -858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, -859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, -860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, -861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, -862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, -863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, -864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, -865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, -866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, -867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, -868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, -869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, -870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, -871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, -872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, -901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", -902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", -903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", -911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", -912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", -913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", -921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", -942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", -943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", -951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", -952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", -953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", -961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", -962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", -963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", -1001,Fishing,Fishsanity: Carp,FISHSANITY, -1002,Fishing,Fishsanity: Herring,FISHSANITY, -1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, -1004,Fishing,Fishsanity: Anchovy,FISHSANITY, -1005,Fishing,Fishsanity: Sardine,FISHSANITY, -1006,Fishing,Fishsanity: Sunfish,FISHSANITY, -1007,Fishing,Fishsanity: Perch,FISHSANITY, -1008,Fishing,Fishsanity: Chub,FISHSANITY, -1009,Fishing,Fishsanity: Bream,FISHSANITY, -1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, -1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, -1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, -1013,Fishing,Fishsanity: Walleye,FISHSANITY, -1014,Fishing,Fishsanity: Shad,FISHSANITY, -1015,Fishing,Fishsanity: Bullhead,FISHSANITY, -1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, -1017,Fishing,Fishsanity: Salmon,FISHSANITY, -1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, -1019,Fishing,Fishsanity: Tilapia,FISHSANITY, -1020,Fishing,Fishsanity: Woodskip,FISHSANITY, -1021,Fishing,Fishsanity: Flounder,FISHSANITY, -1022,Fishing,Fishsanity: Halibut,FISHSANITY, -1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", -1024,Fishing,Fishsanity: Slimejack,FISHSANITY, -1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, -1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, -1027,Fishing,Fishsanity: Pike,FISHSANITY, -1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, -1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", -1030,Fishing,Fishsanity: Albacore,FISHSANITY, -1031,Fishing,Fishsanity: Sandfish,FISHSANITY, -1032,Fishing,Fishsanity: Stonefish,FISHSANITY, -1033,Fishing,Fishsanity: Tuna,FISHSANITY, -1034,Fishing,Fishsanity: Eel,FISHSANITY, -1035,Fishing,Fishsanity: Catfish,FISHSANITY, -1036,Fishing,Fishsanity: Squid,FISHSANITY, -1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, -1038,Fishing,Fishsanity: Dorado,FISHSANITY, -1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, -1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, -1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, -1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", -1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, -1044,Fishing,Fishsanity: Lingcod,FISHSANITY, -1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, -1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, -1047,Fishing,Fishsanity: Octopus,FISHSANITY, -1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, -1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, -1050,Fishing,Fishsanity: Blobfish,FISHSANITY, -1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, -1052,Fishing,Fishsanity: Angler,FISHSANITY, -1053,Fishing,Fishsanity: Legend,FISHSANITY, -1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, -1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, -1056,Town,Fishsanity: Crayfish,FISHSANITY, -1057,Town,Fishsanity: Snail,FISHSANITY, -1058,Town,Fishsanity: Periwinkle,FISHSANITY, -1059,Beach,Fishsanity: Lobster,FISHSANITY, -1060,Beach,Fishsanity: Clam,FISHSANITY, -1061,Beach,Fishsanity: Crab,FISHSANITY, -1062,Beach,Fishsanity: Cockle,FISHSANITY, -1063,Beach,Fishsanity: Mussel,FISHSANITY, -1064,Beach,Fishsanity: Shrimp,FISHSANITY, -1065,Beach,Fishsanity: Oyster,FISHSANITY, -1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, -1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, -1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, -1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, -1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, -1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, -1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, -1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, -1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, -1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, -1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, -1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, -1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, -1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, -1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, -1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, -1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, -1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, -1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, -1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, -1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, -1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, -1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, -1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, -1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, -1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, -1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, -1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, -1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, -1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, -1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, -1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, -1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, -1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, -1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, -1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, -1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, -1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, -1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, -1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, -1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, -1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, -1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, -1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, -1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, -1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, -1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", -1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, -1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, -1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, -1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, -1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, -1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, -1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, -1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, -1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, -1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, -1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, -1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, -1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, -1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, -1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, -1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, -1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, -1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, -1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, -1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, -1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, -1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, -1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, -1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, -1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, -1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, -1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, -1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, -1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, -1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, -1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, -1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, -1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, -1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, -1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, -1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, -1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, -1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, -1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, -1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, -1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, -1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, -1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, -1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, -1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, -1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, -1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, -1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, -1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, -1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, -1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, -1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, -1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, -1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, -1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, -1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, -1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, -1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, -1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, -1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, -1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, -1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, -1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, -1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, -1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, -1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, -1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, -1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, -1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, -1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, -1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, -1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, -1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, -1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, -1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, -1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, -1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, -1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, -1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, -1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, -1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, -1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, -1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, -1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, -1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, -1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, -1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, -1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, -1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, -1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, -1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, -1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, -1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, -1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, -1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, -1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, -1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, -1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, -1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, -1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, -1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, -1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, -1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, -1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, -1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, -1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, -1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, -1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, -1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, -1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, -1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, -1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, -1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, -1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, -1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, -1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, -1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, -1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, -1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, -1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, -1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, -1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, -1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, -1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, -1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, -1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, -1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, -1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, -1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, -1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, -1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, -1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, -1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, -1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, -1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, -1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, -1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, -1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, -1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, -1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, -1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, -1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, -1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, -1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, -1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, -1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, -1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, -1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, -1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, -1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, -1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, -1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, -1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, -1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, -1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, -1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, -1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, -1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, -1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, -1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, -1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, -1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, -1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, -1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, -1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, -1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, -1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, -1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, -1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, -1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, -1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, -1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, -1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, -1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, -1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, -1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, -1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, -1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, -1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, -1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, -1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, -1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, -1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, -1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, -1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, -1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, -1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, -1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, -1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, -1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, -1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, -1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, -1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, -1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, -1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, -1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, -1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, -1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, -1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, -1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, -1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, -1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, -1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, -1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, -1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, -1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, -1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, -1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, -1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, -1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, -1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, -1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, -1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, -1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, -1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, -1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, -1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, -1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, -1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, -1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, -1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, -1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, -1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, -1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, -1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, -1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, -1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, -1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, -1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, -1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, -1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, -1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, -1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, -1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, -1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, -1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, -1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, -1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, -1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, -1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, -1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, -1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, -1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, -1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, -1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, -1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, -1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, -1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, -1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, -1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, -1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, -1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, -1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, -1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, -1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, -1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, -1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, -1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, -1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, -1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, -1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, -1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, -1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, -1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, -1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, -1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, -1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, -1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, -1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, -1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, -1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, -1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, -1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, -1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, -1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, -1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, -1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, -1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, -1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, -1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, -1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, -1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, -1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, -1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, -1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, -1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, -1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, -1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, -1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, -1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, -1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, -1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, -1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, -1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, -1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, -1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, -1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, -1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, -1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, -1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, -1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, -1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, -1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, -1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, -1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, -1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, -1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, -1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, -1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, -1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, -1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, -1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, -1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, -1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, -1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, -1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, -1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, -1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, -1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, -1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, -1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, -1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, -1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, -1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, -1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, -1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, -1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, -1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, -1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, -1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, -1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, -1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, -1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, -1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, -1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, -1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, -1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, -1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, -1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, -1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, -1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, -1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, -1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, -1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, -1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY", -1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY", -1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY", -1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY", -1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY", -1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY", -1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY", -1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY", -1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY", -1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY", -1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", -1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", -1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", -1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", -1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", -1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", -1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", -1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", -1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", -1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", -1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, -1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, -1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, -1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, -1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, -1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, -1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, -1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, -1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, -1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, -1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, -1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, -1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, -1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, -1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, -1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, -1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, -1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, -1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, -1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, -1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, -1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, -1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, -1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, -1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, -1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, -1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, -1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, -1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, -1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, -1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, -1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, -1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, -1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, -1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, -1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, -1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, -1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, -1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, -1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, -1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, -1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, -1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, -1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, -1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, -1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, -1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, -1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, -1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, -1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, -1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, -1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, -1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, -1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, -1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, -1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, -1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, -1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, -1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, -1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, -1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, -1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, -1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, -1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, -1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, -1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, -1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, -1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, -1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, -1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, -1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, -1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, -1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, -1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, -1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, -1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, -1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, -1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, -1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, -1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, -1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, -1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, -1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, -1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, -1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, -1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, -1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, -1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, -1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, -1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, -1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, -1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, -1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, -1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, -1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, -1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, -1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, -1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, -1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, -1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, -1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, -1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, -1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, -1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, -1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, -1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, -1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, -1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, -1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, -1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, -1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, -1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, -1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, -1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, -1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, -1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, -1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, -1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, -1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, -2001,Egg Festival,Egg Hunt Victory,FESTIVAL, -2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, -2003,Flower Dance,Dance with someone,FESTIVAL, -2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, -2005,Luau,Luau Soup,FESTIVAL, -2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, -2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, -2008,Stardew Valley Fair,Grange Display,FESTIVAL, -2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, -2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, -2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, -2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, -2013,Festival of Ice,Win Fishing Competition,FESTIVAL, -2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, -2015,Night Market,Mermaid Pearl,FESTIVAL, -2016,Night Market,Cone Hat,FESTIVAL_HARD, -2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, -2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, -2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, -2020,Night Market,Lupini: Red Eagle,FESTIVAL, -2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, -2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, -2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, -2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, -2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, -2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, -2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, -2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, -2029,Feast of the Winter Star,Secret Santa,FESTIVAL, -2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, -2031,Farm,Collect All Rarecrows,FESTIVAL, -2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, -2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, -2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, -2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, -2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, -2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, -2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, -2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, -2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, -2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, -2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, -2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, -2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, -2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, -2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, -2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, -2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, -2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, -2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, -2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", -2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, -2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, -2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, -2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", -2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", -2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", -2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", -2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", -2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", -2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", -2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", -2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", -2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, -2216,Field Office,Complete Island Field Office,GINGER_ISLAND, -2301,Farming,Harvest Amaranth,"CROPSANITY", -2302,Farming,Harvest Artichoke,"CROPSANITY", -2303,Farming,Harvest Beet,"CROPSANITY", -2304,Farming,Harvest Blue Jazz,"CROPSANITY", -2305,Farming,Harvest Blueberry,"CROPSANITY", -2306,Farming,Harvest Bok Choy,"CROPSANITY", -2307,Farming,Harvest Cauliflower,"CROPSANITY", -2308,Farming,Harvest Corn,"CROPSANITY", -2309,Farming,Harvest Cranberries,"CROPSANITY", -2310,Farming,Harvest Eggplant,"CROPSANITY", -2311,Farming,Harvest Fairy Rose,"CROPSANITY", -2312,Farming,Harvest Garlic,"CROPSANITY", -2313,Farming,Harvest Grape,"CROPSANITY", -2314,Farming,Harvest Green Bean,"CROPSANITY", -2315,Farming,Harvest Hops,"CROPSANITY", -2316,Farming,Harvest Hot Pepper,"CROPSANITY", -2317,Farming,Harvest Kale,"CROPSANITY", -2318,Farming,Harvest Melon,"CROPSANITY", -2319,Farming,Harvest Parsnip,"CROPSANITY", -2320,Farming,Harvest Poppy,"CROPSANITY", -2321,Farming,Harvest Potato,"CROPSANITY", -2322,Farming,Harvest Pumpkin,"CROPSANITY", -2323,Farming,Harvest Radish,"CROPSANITY", -2324,Farming,Harvest Red Cabbage,"CROPSANITY", -2325,Farming,Harvest Rhubarb,"CROPSANITY", -2326,Farming,Harvest Starfruit,"CROPSANITY", -2327,Farming,Harvest Strawberry,"CROPSANITY", -2328,Farming,Harvest Summer Spangle,"CROPSANITY", -2329,Farming,Harvest Sunflower,"CROPSANITY", -2330,Farming,Harvest Tomato,"CROPSANITY", -2331,Farming,Harvest Tulip,"CROPSANITY", -2332,Farming,Harvest Unmilled Rice,"CROPSANITY", -2333,Farming,Harvest Wheat,"CROPSANITY", -2334,Farming,Harvest Yam,"CROPSANITY", -2335,Farming,Harvest Cactus Fruit,"CROPSANITY", -2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", -2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farming,Harvest Sweet Gem Berry,"CROPSANITY", -2339,Farming,Harvest Apple,"CROPSANITY", -2340,Farming,Harvest Apricot,"CROPSANITY", -2341,Farming,Harvest Cherry,"CROPSANITY", -2342,Farming,Harvest Orange,"CROPSANITY", -2343,Farming,Harvest Pomegranate,"CROPSANITY", -2344,Farming,Harvest Peach,"CROPSANITY", -2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", -2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farming,Harvest Coffee Bean,"CROPSANITY", -2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2416,Shipping,Shipsanity: Anchor,SHIPSANITY, -2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, -2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, -2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, -2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, -2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, -2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, -2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, -2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, -2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, -2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, -2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, -2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, -2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, -2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, -2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, -2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, -2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, -2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, -2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, -2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, -2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, -2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, -2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, -2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, -2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, -2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, -2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, -2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, -2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, -2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, -2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, -2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, -2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2454,Shipping,Shipsanity: Coffee,SHIPSANITY, -2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, -2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, -2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, -2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, -2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, -2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, -2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, -2479,Shipping,Shipsanity: Bread,SHIPSANITY, -2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, -2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, -2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, -2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, -2484,Shipping,Shipsanity: Chowder,SHIPSANITY, -2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, -2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Shipping,Shipsanity: Cookies,SHIPSANITY, -2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, -2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, -2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, -2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, -2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, -2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, -2494,Shipping,Shipsanity: Escargot,SHIPSANITY, -2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, -2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, -2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, -2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, -2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, -2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, -2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, -2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, -2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, -2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, -2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, -2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, -2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, -2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, -2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, -2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, -2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, -2512,Shipping,Shipsanity: Omelet,SHIPSANITY, -2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, -2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, -2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, -2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, -2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, -2518,Shipping,Shipsanity: Pizza,SHIPSANITY, -2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, -2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, -2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, -2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, -2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, -2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, -2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, -2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, -2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, -2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, -2529,Shipping,Shipsanity: Salad,SHIPSANITY, -2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, -2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, -2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, -2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, -2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, -2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, -2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, -2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, -2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, -2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, -2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, -2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, -2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, -2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, -2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, -2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, -2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, -2547,Shipping,Shipsanity: Bait,SHIPSANITY, -2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, -2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, -2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, -2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, -2552,Shipping,Shipsanity: Bomb,SHIPSANITY, -2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, -2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, -2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, -2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, -2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, -2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, -2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,"SHIPSANITY", -2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, -2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, -2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, -2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, -2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, -2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, -2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, -2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, -2569,Shipping,Shipsanity: Gate,SHIPSANITY, -2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, -2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, -2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, -2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, -2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, -2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, -2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, -2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, -2578,Shipping,Shipsanity: Magnet,SHIPSANITY, -2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, -2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, -2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, -2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, -2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, -2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, -2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, -2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, -2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, -2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, -2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, -2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, -2591,Shipping,Shipsanity: Spinner,SHIPSANITY, -2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, -2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, -2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, -2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, -2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, -2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, -2598,Shipping,Shipsanity: Torch,SHIPSANITY, -2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, -2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, -2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, -2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, -2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, -2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", -2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Shipping,Shipsanity: Weathered Floor,"SHIPSANITY", -2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, -2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, -2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, -2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, -2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", -2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", -2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", -2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", -2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", -2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", -2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", -2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", -2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", -2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", -2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", -2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", -2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", -2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", -2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", -2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", -2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", -2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", -2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", -2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", -2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", -2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", -2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", -2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", -2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", -2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", -2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", -2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", -2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", -2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", -2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", -2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", -2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", -2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", -2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", -2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", -2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", -2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", -2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", -2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", -2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", -2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", -2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", -2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", -2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", -2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", -2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", -2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", -2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", -2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", -2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", -2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", -2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", -2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", -2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", -2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, -2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2755,Shipping,Shipsanity: Oil,SHIPSANITY, -2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2757,Shipping,Shipsanity: Rice,SHIPSANITY, -2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2760,Shipping,Shipsanity: Sugar,SHIPSANITY, -2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, -2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, -2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, -2765,Shipping,Shipsanity: Alamite,SHIPSANITY, -2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, -2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, -2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, -2769,Shipping,Shipsanity: Baryte,SHIPSANITY, -2770,Shipping,Shipsanity: Basalt,SHIPSANITY, -2771,Shipping,Shipsanity: Bixite,SHIPSANITY, -2772,Shipping,Shipsanity: Calcite,SHIPSANITY, -2773,Shipping,Shipsanity: Celestine,SHIPSANITY, -2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2776,Shipping,Shipsanity: Diamond,SHIPSANITY, -2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, -2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, -2779,Shipping,Shipsanity: Emerald,SHIPSANITY, -2780,Shipping,Shipsanity: Esperite,SHIPSANITY, -2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, -2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, -2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, -2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, -2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, -2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, -2787,Shipping,Shipsanity: Geminite,SHIPSANITY, -2788,Shipping,Shipsanity: Geode,SHIPSANITY, -2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, -2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2791,Shipping,Shipsanity: Granite,SHIPSANITY, -2792,Shipping,Shipsanity: Helvite,SHIPSANITY, -2793,Shipping,Shipsanity: Hematite,SHIPSANITY, -2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2796,Shipping,Shipsanity: Jade,SHIPSANITY, -2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, -2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, -2799,Shipping,Shipsanity: Jasper,SHIPSANITY, -2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, -2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, -2802,Shipping,Shipsanity: Limestone,SHIPSANITY, -2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, -2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, -2805,Shipping,Shipsanity: Malachite,SHIPSANITY, -2806,Shipping,Shipsanity: Marble,SHIPSANITY, -2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, -2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, -2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, -2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, -2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, -2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, -2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, -2814,Shipping,Shipsanity: Opal,SHIPSANITY, -2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, -2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, -2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, -2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, -2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, -2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, -2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, -2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, -2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, -2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, -2825,Shipping,Shipsanity: Quartz,SHIPSANITY, -2826,Shipping,Shipsanity: Ruby,SHIPSANITY, -2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, -2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, -2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, -2830,Shipping,Shipsanity: Slate,SHIPSANITY, -2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, -2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, -2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, -2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, -2835,Shipping,Shipsanity: Topaz,SHIPSANITY, -2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, -2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", -2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, -2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, -2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, -2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, -2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, -2848,Shipping,Shipsanity: Hay,SHIPSANITY, -2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, -2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, -2851,Shipping,Shipsanity: Pearl,SHIPSANITY, -2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, -2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, -2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, -2855,Shipping,Shipsanity: White Algae,SHIPSANITY, -2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, -2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, -2858,Shipping,Shipsanity: Acorn,SHIPSANITY, -2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, -2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, -2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, -2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, -2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, -2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, -2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, -2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, -2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, -2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, -2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, -2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, -2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, -2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, -2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, -2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, -2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, -2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, -2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, -2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, -2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, -2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, -2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, -2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, -2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, -2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, -2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, -2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, -2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, -2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, -2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, -2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, -2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, -2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, -2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, -2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, -2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, -2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, -2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, -2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, -2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, -2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, -2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, -2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, -2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, -2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, -2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, -2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, -2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, -2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, -2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, -2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, -2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, -2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, -2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, -2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, -2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, -2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, -2918,Shipping,Shipsanity: Trash,SHIPSANITY, -2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, -2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", -2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", -2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", -2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", -2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", -2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", -2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", -2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", -2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", -2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", -2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", -2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", -2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", -2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", -2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", -2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", -2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", -2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", -2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", -2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", -2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", -2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Shipping,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", -2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", -2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", -2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", -2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", -2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", -3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", -3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", -3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", -3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", -3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", -3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", -3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", -3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", -3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", -3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", -3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3201,Kitchen,Cook Algae Soup,"COOKSANITY", -3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", -3203,Kitchen,Cook Autumn's Bounty,"COOKSANITY", -3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", -3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", -3206,Kitchen,Cook Bean Hotpot,"COOKSANITY", -3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", -3208,Kitchen,Cook Blueberry Tart,"COOKSANITY", -3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", -3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", -3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", -3212,Kitchen,Cook Cheese Cauliflower,"COOKSANITY", -3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", -3214,Kitchen,Cook Chowder,"COOKSANITY", -3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", -3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", -3217,Kitchen,Cook Cookies,"COOKSANITY", -3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", -3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", -3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY", -3221,Kitchen,Cook Crispy Bass,"COOKSANITY", -3222,Kitchen,Cook Dish O' The Sea,"COOKSANITY", -3223,Kitchen,Cook Eggplant Parmesan,"COOKSANITY", -3224,Kitchen,Cook Escargot,"COOKSANITY", -3225,Kitchen,Cook Farmer's Lunch,"COOKSANITY", -3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", -3227,Kitchen,Cook Fish Stew,"COOKSANITY", -3228,Kitchen,Cook Fish Taco,"COOKSANITY", -3229,Kitchen,Cook Fried Calamari,"COOKSANITY", -3230,Kitchen,Cook Fried Eel,"COOKSANITY", -3231,Kitchen,Cook Fried Egg,"COOKSANITY", -3232,Kitchen,Cook Fried Mushroom,"COOKSANITY", -3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", -3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", -3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", -3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", -3237,Kitchen,Cook Ice Cream,"COOKSANITY", -3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", -3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", -3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", -3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", -3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", -3243,Kitchen,Cook Miner's Treat,"COOKSANITY", -3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", -3245,Kitchen,Cook Pale Broth,"COOKSANITY", -3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", -3247,Kitchen,Cook Parsnip Soup,"COOKSANITY", -3248,Kitchen,Cook Pepper Poppers,"COOKSANITY", -3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", -3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", -3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", -3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", -3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", -3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", -3255,Kitchen,Cook Pumpkin Soup,"COOKSANITY", -3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", -3257,Kitchen,Cook Red Plate,"COOKSANITY", -3258,Kitchen,Cook Rhubarb Pie,"COOKSANITY", -3259,Kitchen,Cook Rice Pudding,"COOKSANITY", -3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", -3261,Kitchen,Cook Roots Platter,"COOKSANITY", -3262,Kitchen,Cook Salad,"COOKSANITY", -3263,Kitchen,Cook Salmon Dinner,"COOKSANITY", -3264,Kitchen,Cook Sashimi,"COOKSANITY", -3265,Kitchen,Cook Seafoam Pudding,"COOKSANITY", -3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", -3267,Kitchen,Cook Spaghetti,"COOKSANITY", -3268,Kitchen,Cook Spicy Eel,"COOKSANITY", -3269,Kitchen,Cook Squid Ink Ravioli,"COOKSANITY", -3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", -3271,Kitchen,Cook Strange Bun,"COOKSANITY", -3272,Kitchen,Cook Stuffing,"COOKSANITY", -3273,Kitchen,Cook Super Meal,"COOKSANITY", -3274,Kitchen,Cook Survival Burger,"COOKSANITY", -3275,Kitchen,Cook Tom Kha Soup,"COOKSANITY", -3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", -3277,Kitchen,Cook Triple Shot Espresso,"COOKSANITY", -3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", -3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", -3280,Kitchen,Cook Vegetable Medley,"COOKSANITY", -3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3331,Farm,Fried Egg Recipe,"CHEFSANITY_STARTER", -3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", -3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3401,Farm,Craft Cherry Bomb,"CRAFTSANITY", -3402,Farm,Craft Bomb,"CRAFTSANITY", -3403,Farm,Craft Mega Bomb,"CRAFTSANITY", -3404,Farm,Craft Gate,"CRAFTSANITY", -3405,Farm,Craft Wood Fence,"CRAFTSANITY", -3406,Farm,Craft Stone Fence,"CRAFTSANITY", -3407,Farm,Craft Iron Fence,"CRAFTSANITY", -3408,Farm,Craft Hardwood Fence,"CRAFTSANITY", -3409,Farm,Craft Sprinkler,"CRAFTSANITY", -3410,Farm,Craft Quality Sprinkler,"CRAFTSANITY", -3411,Farm,Craft Iridium Sprinkler,"CRAFTSANITY", -3412,Farm,Craft Bee House,"CRAFTSANITY", -3413,Farm,Craft Cask,"CRAFTSANITY", -3414,Farm,Craft Cheese Press,"CRAFTSANITY", -3415,Farm,Craft Keg,"CRAFTSANITY", -3416,Farm,Craft Loom,"CRAFTSANITY", -3417,Farm,Craft Mayonnaise Machine,"CRAFTSANITY", -3418,Farm,Craft Oil Maker,"CRAFTSANITY", -3419,Farm,Craft Preserves Jar,"CRAFTSANITY", -3420,Farm,Craft Basic Fertilizer,"CRAFTSANITY", -3421,Farm,Craft Quality Fertilizer,"CRAFTSANITY", -3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY", -3423,Farm,Craft Speed-Gro,"CRAFTSANITY", -3424,Farm,Craft Deluxe Speed-Gro,"CRAFTSANITY", -3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", -3426,Farm,Craft Basic Retaining Soil,"CRAFTSANITY", -3427,Farm,Craft Quality Retaining Soil,"CRAFTSANITY", -3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", -3429,Farm,Craft Tree Fertilizer,"CRAFTSANITY", -3430,Farm,Craft Spring Seeds,"CRAFTSANITY", -3431,Farm,Craft Summer Seeds,"CRAFTSANITY", -3432,Farm,Craft Fall Seeds,"CRAFTSANITY", -3433,Farm,Craft Winter Seeds,"CRAFTSANITY", -3434,Farm,Craft Ancient Seeds,"CRAFTSANITY", -3435,Farm,Craft Grass Starter,"CRAFTSANITY", -3436,Farm,Craft Tea Sapling,"CRAFTSANITY", -3437,Farm,Craft Fiber Seeds,"CRAFTSANITY", -3438,Farm,Craft Wood Floor,"CRAFTSANITY", -3439,Farm,Craft Rustic Plank Floor,"CRAFTSANITY", -3440,Farm,Craft Straw Floor,"CRAFTSANITY", -3441,Farm,Craft Weathered Floor,"CRAFTSANITY", -3442,Farm,Craft Crystal Floor,"CRAFTSANITY", -3443,Farm,Craft Stone Floor,"CRAFTSANITY", -3444,Farm,Craft Stone Walkway Floor,"CRAFTSANITY", -3445,Farm,Craft Brick Floor,"CRAFTSANITY", -3446,Farm,Craft Wood Path,"CRAFTSANITY", -3447,Farm,Craft Gravel Path,"CRAFTSANITY", -3448,Farm,Craft Cobblestone Path,"CRAFTSANITY", -3449,Farm,Craft Stepping Stone Path,"CRAFTSANITY", -3450,Farm,Craft Crystal Path,"CRAFTSANITY", -3451,Farm,Craft Spinner,"CRAFTSANITY", -3452,Farm,Craft Trap Bobber,"CRAFTSANITY", -3453,Farm,Craft Cork Bobber,"CRAFTSANITY", -3454,Farm,Craft Quality Bobber,"CRAFTSANITY", -3455,Farm,Craft Treasure Hunter,"CRAFTSANITY", -3456,Farm,Craft Dressed Spinner,"CRAFTSANITY", -3457,Farm,Craft Barbed Hook,"CRAFTSANITY", -3458,Farm,Craft Magnet,"CRAFTSANITY", -3459,Farm,Craft Bait,"CRAFTSANITY", -3460,Farm,Craft Wild Bait,"CRAFTSANITY", -3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", -3462,Farm,Craft Crab Pot,"CRAFTSANITY", -3463,Farm,Craft Sturdy Ring,"CRAFTSANITY", -3464,Farm,Craft Warrior Ring,"CRAFTSANITY", -3465,Farm,Craft Ring of Yoba,"CRAFTSANITY", -3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", -3467,Farm,Craft Glowstone Ring,"CRAFTSANITY", -3468,Farm,Craft Iridium Band,"CRAFTSANITY", -3469,Farm,Craft Wedding Ring,"CRAFTSANITY", -3470,Farm,Craft Field Snack,"CRAFTSANITY", -3471,Farm,Craft Bug Steak,"CRAFTSANITY", -3472,Farm,Craft Life Elixir,"CRAFTSANITY", -3473,Farm,Craft Oil of Garlic,"CRAFTSANITY", -3474,Farm,Craft Monster Musk,"CRAFTSANITY", -3475,Farm,Craft Fairy Dust,"CRAFTSANITY", -3476,Farm,Craft Warp Totem: Beach,"CRAFTSANITY", -3477,Farm,Craft Warp Totem: Mountains,"CRAFTSANITY", -3478,Farm,Craft Warp Totem: Farm,"CRAFTSANITY", -3479,Farm,Craft Warp Totem: Desert,"CRAFTSANITY", -3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", -3481,Farm,Craft Rain Totem,"CRAFTSANITY", -3482,Farm,Craft Torch,"CRAFTSANITY", -3483,Farm,Craft Campfire,"CRAFTSANITY", -3484,Farm,Craft Wooden Brazier,"CRAFTSANITY", -3485,Farm,Craft Stone Brazier,"CRAFTSANITY", -3486,Farm,Craft Gold Brazier,"CRAFTSANITY", -3487,Farm,Craft Carved Brazier,"CRAFTSANITY", -3488,Farm,Craft Stump Brazier,"CRAFTSANITY", -3489,Farm,Craft Barrel Brazier,"CRAFTSANITY", -3490,Farm,Craft Skull Brazier,"CRAFTSANITY", -3491,Farm,Craft Marble Brazier,"CRAFTSANITY", -3492,Farm,Craft Wood Lamp-post,"CRAFTSANITY", -3493,Farm,Craft Iron Lamp-post,"CRAFTSANITY", -3494,Farm,Craft Jack-O-Lantern,"CRAFTSANITY", -3495,Farm,Craft Bone Mill,"CRAFTSANITY", -3496,Farm,Craft Charcoal Kiln,"CRAFTSANITY", -3497,Farm,Craft Crystalarium,"CRAFTSANITY", -3498,Farm,Craft Furnace,"CRAFTSANITY", -3499,Farm,Craft Geode Crusher,"CRAFTSANITY", -3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", -3501,Farm,Craft Lightning Rod,"CRAFTSANITY", -3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", -3503,Farm,Craft Recycling Machine,"CRAFTSANITY", -3504,Farm,Craft Seed Maker,"CRAFTSANITY", -3505,Farm,Craft Slime Egg-Press,"CRAFTSANITY", -3506,Farm,Craft Slime Incubator,"CRAFTSANITY", -3507,Farm,Craft Solar Panel,"CRAFTSANITY", -3508,Farm,Craft Tapper,"CRAFTSANITY", -3509,Farm,Craft Worm Bin,"CRAFTSANITY", -3510,Farm,Craft Tub o' Flowers,"CRAFTSANITY", -3511,Farm,Craft Wicked Statue,"CRAFTSANITY", -3512,Farm,Craft Flute Block,"CRAFTSANITY", -3513,Farm,Craft Drum Block,"CRAFTSANITY", -3514,Farm,Craft Chest,"CRAFTSANITY", -3515,Farm,Craft Stone Chest,"CRAFTSANITY", -3516,Farm,Craft Wood Sign,"CRAFTSANITY", -3517,Farm,Craft Stone Sign,"CRAFTSANITY", -3518,Farm,Craft Dark Sign,"CRAFTSANITY", -3519,Farm,Craft Garden Pot,"CRAFTSANITY", -3520,Farm,Craft Scarecrow,"CRAFTSANITY", -3521,Farm,Craft Deluxe Scarecrow,"CRAFTSANITY", -3522,Farm,Craft Staircase,"CRAFTSANITY", -3523,Farm,Craft Explosive Ammo,"CRAFTSANITY", -3524,Farm,Craft Transmute (Fe),"CRAFTSANITY", -3525,Farm,Craft Transmute (Au),"CRAFTSANITY", -3526,Farm,Craft Mini-Jukebox,"CRAFTSANITY", -3527,Farm,Craft Mini-Obelisk,"CRAFTSANITY", -3528,Farm,Craft Farm Computer,"CRAFTSANITY", -3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", -3530,Farm,Craft Cookout Kit,"CRAFTSANITY", -3551,Pierre's General Store,Grass Starter Recipe,"CRAFTSANITY", -3552,Carpenter Shop,Wood Floor Recipe,"CRAFTSANITY", -3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", -3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", -3555,Mines Dwarf Shop,Weathered Floor Recipe,"CRAFTSANITY", -3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY", -3557,Carpenter Shop,Stone Floor Recipe,"CRAFTSANITY", -3558,Carpenter Shop,Stone Walkway Floor Recipe,"CRAFTSANITY", -3559,Carpenter Shop,Brick Floor Recipe,"CRAFTSANITY", -3560,Carpenter Shop,Stepping Stone Path Recipe,"CRAFTSANITY", -3561,Carpenter Shop,Crystal Path Recipe,"CRAFTSANITY", -3562,Traveling Cart,Wedding Ring Recipe,"CRAFTSANITY", -3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", -3564,Carpenter Shop,Wooden Brazier Recipe,"CRAFTSANITY", -3565,Carpenter Shop,Stone Brazier Recipe,"CRAFTSANITY", -3566,Carpenter Shop,Gold Brazier Recipe,"CRAFTSANITY", -3567,Carpenter Shop,Carved Brazier Recipe,"CRAFTSANITY", -3568,Carpenter Shop,Stump Brazier Recipe,"CRAFTSANITY", -3569,Carpenter Shop,Barrel Brazier Recipe,"CRAFTSANITY", -3570,Carpenter Shop,Skull Brazier Recipe,"CRAFTSANITY", -3571,Carpenter Shop,Marble Brazier Recipe,"CRAFTSANITY", -3572,Carpenter Shop,Wood Lamp-post Recipe,"CRAFTSANITY", -3573,Carpenter Shop,Iron Lamp-post Recipe,"CRAFTSANITY", -3574,Sewer,Wicked Statue Recipe,"CRAFTSANITY", -5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic -5502,Magic Altar,Analyze: Till,MANDATORY,Magic -5503,Magic Altar,Analyze: Water,MANDATORY,Magic -5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic -5505,Magic Altar,Analyze: Evac,MANDATORY,Magic -5506,Magic Altar,Analyze: Haste,MANDATORY,Magic -5507,Magic Altar,Analyze: Heal,MANDATORY,Magic -5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic -5509,Magic Altar,Analyze: Descend,MANDATORY,Magic -5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic -5511,Magic Altar,Analyze: Frostbite,MANDATORY,Magic -5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic -5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic -5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic -5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic -5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic -5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic -5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic -5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic -5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic -5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic -6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas -6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas -6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas -6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas -6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas -6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas -6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas -6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas -6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas -6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas -6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas -6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas -6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas -6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas -6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba -6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba -6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba -6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba -6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba -6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba -6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba -6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba -6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba -6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba -6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) -6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) -6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) -6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) -6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) -6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) -6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) -6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) -6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) -6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) -6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC -6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC -6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC -6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC -6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC -6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC -6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC -6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC -6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC -6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC -6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC -6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC -6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC -6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC -6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick -6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick -6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick -6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick -6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick -6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick -6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick -6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick -6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick -6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick -6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick -6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick -6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick -6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick -6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC -6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC -6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC -6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC -6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC -6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC -6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC -6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC -6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC -6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC -6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC -6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC -6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC -6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC -6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited -6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited -6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited -6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited -6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited -6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited -6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited -6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited -6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited -6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited -6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited -6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited -6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited -6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited -6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene -6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene -6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene -6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene -6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene -6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene -6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene -6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene -6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene -6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene -6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene -6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene -6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene -6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene -6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC -6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC -6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC -6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC -6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC -6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC -6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC -6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC -6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC -6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC -6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley -6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley -6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley -6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley -6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley -6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley -6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley -6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley -6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley -6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley -6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley -6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley -6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley -6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley -6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded -6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded -6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded -6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded -6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded -6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded -6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded -6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded -6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded -6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded -6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded -6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded -6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded -6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded -6153,Highlands,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6154,Highlands,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6155,Highlands,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6156,Highlands,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6157,Highlands,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6158,Highlands,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6159,Highlands,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6160,Highlands,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6161,Highlands,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6162,Highlands,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6163,Highlands,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded -6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded -6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded -6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded -6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded -6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded -6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded -6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded -6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded -6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded -6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded -6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded -6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded -6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded -6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded -6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded -6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded -6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded -6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded -6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded -6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded -6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded -6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded -6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded -6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded -6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded -6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded -6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded -6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded -6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded -6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded -6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded -6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded -6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded -6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded -6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded -6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded -6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded -6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded -6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded -6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded -6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded -6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded -6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded -6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded -6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded -6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded -6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded -6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded -6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded -6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded -6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded -6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded -6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded -6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded -6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded -6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded -6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded -6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded -6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded -6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded -6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded -6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded -6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded -6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded -6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded -6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded -6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded -6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6273,Blue Moon Vineyard,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded -6274,Blue Moon Vineyard,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded -6275,Blue Moon Vineyard,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded -6276,Blue Moon Vineyard,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded -6277,Blue Moon Vineyard,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded -6278,Blue Moon Vineyard,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded -6279,Blue Moon Vineyard,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded -6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded -6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded -6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded -6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded -6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded -6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded -6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded -6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded -6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded -6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded -6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded -6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded -6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded -7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack -7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod -7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods -7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods -7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods -7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods -7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods -7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods -7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods -7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods -7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods -7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods -7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods -7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods -7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods -7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods -7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods -7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods -7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods -7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator -7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator -7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator -7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator -7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator -7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator -7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator -7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic -7402,Farm,Craft Travel Core,CRAFTSANITY,Magic -7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded -7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded -7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded -7406,Farm,Craft Glass Path,CRAFTSANITY,Archaeology -7407,Farm,Craft Bone Path,CRAFTSANITY,Archaeology -7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology -7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology -7410,Farm,Craft Water Strainer,CRAFTSANITY,Archaeology -7411,Farm,Craft Grinder,CRAFTSANITY,Archaeology -7412,Farm,Craft Ancient Battery Creator,CRAFTSANITY,Archaeology -7413,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology -7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology -7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology -7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology -7417,Farm,Craft Warp Totem: Volcano,"CRAFTSANITY,GINGER_ISLAND",Archaeology -7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic -7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic -7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7454,Issac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology -7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology -7458,Farm,Glass Bazier Recipe,CRAFTSANITY,Archaeology -7459,Farm,Glass Fence Recipe,CRAFTSANITY,Archaeology -7460,Farm,Water Strainer Recipe,CRAFTSANITY,Archaeology -7461,Farm,Grinder Recipe,CRAFTSANITY,Archaeology -7462,Farm,Ancient Battery Creator Recipe,CRAFTSANITY,Archaeology -7463,Farm,Preservation Chamber Recipe,CRAFTSANITY,Archaeology -7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology -7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology -7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology -7467,Farm,Warp Totem: Volcano Recipe,"CRAFTSANITY,GINGER_ISLAND",Archaeology -7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) -7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC -7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC -7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC -7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded -7509,Grandpa's Shed Interior,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded -7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded -7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded -7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded -7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded -7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded -7554,Kitchen,Cook Frog Legs,"COOKSANITY",Stardew Valley Expanded -7555,Kitchen,Cook Glazed Butterfish,"COOKSANITY",Stardew Valley Expanded -7556,Kitchen,Cook Mixed Berry Pie,"COOKSANITY",Stardew Valley Expanded -7557,Kitchen,Cook Mushroom Berry Rice,"COOKSANITY",Stardew Valley Expanded -7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded -7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded -7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded -7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7651,Alesia Shop,Purchase Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7652,Issac Shop,Purchase Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7653,Issac Shop,Purchase Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded -7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded -7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded -7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded -7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7706,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7708,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded -7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded -7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded -7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded -7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded -7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded -7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded -7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded -7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded -7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded -7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded -7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded -7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded -8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic -8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic -8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded -8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded -8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded -8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded -8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded -8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded -8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded -8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded -8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded -8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded -8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded -8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded -8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded -8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded -8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded -8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded -8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded -8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded -8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded -8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded -8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded -8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded -8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded -8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded -8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded -8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded -8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology -8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology -8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology -8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology -8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology -8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology -8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology -8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology -8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology -8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology -8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology -8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology -8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology -8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology -8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology -8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology -8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology -8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology -8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology -8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology -8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology -8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology -8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology -8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology -8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology -8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology -8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology -8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology -8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology -8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology -8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology -8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology -8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology -8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology -8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology -8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology -8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology -8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology -8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology -8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology -8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology -8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology -8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology -8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology -8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology -8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology -8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology -8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology -8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology -8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology -8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology -8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology -8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology -8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology -8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology -8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology -8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology -8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology -8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology -8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology -8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology -8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology -8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology -8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology -8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology -8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology -8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology -8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology -8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology -8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology -8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology -8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology -8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology -8201,Shipping,Shipsanity: Warp Totem: Volcano,"SHIPSANITY,GINGER_ISLAND",Archaeology -8202,Shipping,Shipsanity: Water Strainer,SHIPSANITY,Archaeology +id,region,name,tags,mod_name +1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", +32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", +34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", +35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", +37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +80,Vault,"500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +84,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +85,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +87,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +88,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,"Gambler's Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,"Carnival Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,"Walnut Hunter Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,"Qi's Helper Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +101,Pierre's General Store,Large Pack,BACKPACK, +102,Pierre's General Store,Deluxe Pack,BACKPACK, +103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", +202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", +203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", +204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", +205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", +206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", +207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", +208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", +209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", +210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", +211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", +212,Quarry Mine,Grim Reaper statue,MANDATORY, +213,The Mines,The Mines Entrance Cutscene,MANDATORY, +214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, +215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, +216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, +217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, +218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, +219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, +220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, +221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, +222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, +223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, +224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, +225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, +226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, +227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, +228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, +229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, +230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, +231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, +232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, +233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, +234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, +235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, +236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, +237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, +251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", +301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", +302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", +303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", +304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", +305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", +306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", +307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", +308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", +309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", +310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", +311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", +332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", +333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", +334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", +335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", +336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", +337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", +338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", +339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", +340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", +341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, +402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, +403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, +404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, +405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, +406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, +407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, +408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, +409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, +410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, +411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, +412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, +413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, +414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, +415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, +416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, +417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, +418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, +501,Town,Introductions,"MANDATORY,QUEST", +502,Town,How To Win Friends,"MANDATORY,QUEST", +503,Farm,Getting Started,"MANDATORY,QUEST", +504,Farm,Raising Animals,"MANDATORY,QUEST", +505,Farm,Advancement,"MANDATORY,QUEST", +506,Museum,Archaeology,"MANDATORY,QUEST", +507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", +508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", +509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", +510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", +511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", +512,Sam's House,Jodi's Request,"MANDATORY,QUEST", +513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", +514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", +515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", +516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", +517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", +518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", +519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", +520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", +521,Alex's House,Knee Therapy,"MANDATORY,QUEST", +522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", +524,Desert,The Mysterious Qi,"MANDATORY,QUEST", +525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", +526,Town,A Winter Mystery,"MANDATORY,QUEST", +527,Secret Woods,Strange Note,"MANDATORY,QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", +529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", +530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", +531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", +532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", +533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", +534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", +535,Sam's House,Fish Casserole,"MANDATORY,QUEST", +536,Fishing,Catch A Squid,"MANDATORY,QUEST", +537,Saloon,Fish Stew,"MANDATORY,QUEST", +538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", +539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", +540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", +541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", +542,Alex's House,Granny's Gift,"MANDATORY,QUEST", +543,Desert,Exotic Spirits,"MANDATORY,QUEST", +544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", +545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", +546,Mutant Bug Lair,Dark Talisman,"MANDATORY,QUEST", +547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", +548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", +601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", +602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", +603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", +604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", +605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", +606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", +607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", +608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", +609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", +610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", +611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", +612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", +613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", +614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", +615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", +616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", +617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", +618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", +619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", +620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", +621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", +701,Secret Woods,Old Master Cannoli,MANDATORY, +702,Beach,Beach Bridge Repair,MANDATORY, +703,Desert,Galaxy Sword Shrine,MANDATORY, +704,Farmhouse,Have a Baby,"BABY", +705,Farmhouse,Have Another Baby,"BABY", +706,Farmhouse,Spouse Stardrop,, +707,Sewer,Krobus Stardrop,"MANDATORY", +801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, +802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, +803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, +804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, +805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, +806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, +807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, +808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, +811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, +812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, +821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, +822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, +823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, +824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, +825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, +826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, +827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, +828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, +841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, +842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, +843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, +844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, +845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, +846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, +847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, +848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, +849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, +850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, +851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, +852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, +853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, +854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, +855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, +856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, +857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, +858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, +859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, +860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, +861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, +862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, +863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, +864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, +865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, +866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, +867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, +868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, +869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, +870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, +871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, +872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, +901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", +902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", +903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", +911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", +912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", +913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", +921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", +942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", +943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", +951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", +952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", +953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", +961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", +962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", +963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", +1001,Fishing,Fishsanity: Carp,FISHSANITY, +1002,Fishing,Fishsanity: Herring,FISHSANITY, +1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, +1004,Fishing,Fishsanity: Anchovy,FISHSANITY, +1005,Fishing,Fishsanity: Sardine,FISHSANITY, +1006,Fishing,Fishsanity: Sunfish,FISHSANITY, +1007,Fishing,Fishsanity: Perch,FISHSANITY, +1008,Fishing,Fishsanity: Chub,FISHSANITY, +1009,Fishing,Fishsanity: Bream,FISHSANITY, +1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, +1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, +1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, +1013,Fishing,Fishsanity: Walleye,FISHSANITY, +1014,Fishing,Fishsanity: Shad,FISHSANITY, +1015,Fishing,Fishsanity: Bullhead,FISHSANITY, +1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, +1017,Fishing,Fishsanity: Salmon,FISHSANITY, +1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, +1019,Fishing,Fishsanity: Tilapia,FISHSANITY, +1020,Fishing,Fishsanity: Woodskip,FISHSANITY, +1021,Fishing,Fishsanity: Flounder,FISHSANITY, +1022,Fishing,Fishsanity: Halibut,FISHSANITY, +1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", +1024,Fishing,Fishsanity: Slimejack,FISHSANITY, +1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, +1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, +1027,Fishing,Fishsanity: Pike,FISHSANITY, +1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, +1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", +1030,Fishing,Fishsanity: Albacore,FISHSANITY, +1031,Fishing,Fishsanity: Sandfish,FISHSANITY, +1032,Fishing,Fishsanity: Stonefish,FISHSANITY, +1033,Fishing,Fishsanity: Tuna,FISHSANITY, +1034,Fishing,Fishsanity: Eel,FISHSANITY, +1035,Fishing,Fishsanity: Catfish,FISHSANITY, +1036,Fishing,Fishsanity: Squid,FISHSANITY, +1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, +1038,Fishing,Fishsanity: Dorado,FISHSANITY, +1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, +1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, +1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, +1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", +1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, +1044,Fishing,Fishsanity: Lingcod,FISHSANITY, +1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, +1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, +1047,Fishing,Fishsanity: Octopus,FISHSANITY, +1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, +1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, +1050,Fishing,Fishsanity: Blobfish,FISHSANITY, +1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, +1052,Fishing,Fishsanity: Angler,FISHSANITY, +1053,Fishing,Fishsanity: Legend,FISHSANITY, +1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, +1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, +1056,Town,Fishsanity: Crayfish,FISHSANITY, +1057,Town,Fishsanity: Snail,FISHSANITY, +1058,Town,Fishsanity: Periwinkle,FISHSANITY, +1059,Beach,Fishsanity: Lobster,FISHSANITY, +1060,Beach,Fishsanity: Clam,FISHSANITY, +1061,Beach,Fishsanity: Crab,FISHSANITY, +1062,Beach,Fishsanity: Cockle,FISHSANITY, +1063,Beach,Fishsanity: Mussel,FISHSANITY, +1064,Beach,Fishsanity: Shrimp,FISHSANITY, +1065,Beach,Fishsanity: Oyster,FISHSANITY, +1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, +1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, +1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, +1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, +1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, +1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, +1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, +1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, +1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, +1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, +1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, +1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, +1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, +1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, +1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, +1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, +1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, +1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, +1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, +1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, +1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, +1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, +1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, +1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, +1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, +1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, +1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, +1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, +1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, +1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, +1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, +1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, +1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, +1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, +1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, +1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, +1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, +1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, +1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, +1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, +1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, +1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, +1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, +1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, +1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, +1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, +1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", +1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, +1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, +1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, +1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, +1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, +1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, +1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, +1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, +1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, +1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, +1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, +1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, +1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, +1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, +1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, +1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, +1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, +1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, +1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, +1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, +1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, +1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, +1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, +1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, +1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, +1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, +1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, +1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, +1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, +1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, +1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, +1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, +1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, +1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, +1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, +1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, +1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, +1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, +1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, +1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, +1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, +1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, +1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, +1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, +1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, +1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, +1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, +1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, +1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, +1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, +1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, +1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, +1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, +1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, +1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, +1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, +1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, +1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, +1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, +1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, +1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, +1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, +1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, +1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, +1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, +1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, +1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, +1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, +1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, +1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, +1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, +1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, +1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, +1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, +1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, +1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, +1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, +1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, +1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, +1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, +1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, +1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, +1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, +1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, +1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, +1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, +1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, +1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, +1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, +1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, +1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, +1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, +1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, +1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, +1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, +1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, +1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, +1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, +1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, +1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, +1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, +1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, +1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, +1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, +1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, +1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, +1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, +1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, +1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, +1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, +1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, +1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, +1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, +1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, +1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, +1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, +1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, +1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, +1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, +1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, +1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, +1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, +1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, +1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, +1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, +1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, +1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, +1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, +1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, +1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, +1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, +1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, +1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, +1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, +1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, +1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, +1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, +1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, +1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, +1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, +1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, +1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, +1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, +1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, +1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, +1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, +1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, +1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, +1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, +1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, +1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, +1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, +1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, +1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, +1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, +1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, +1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, +1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, +1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, +1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, +1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, +1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, +1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, +1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, +1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, +1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, +1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, +1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, +1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, +1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, +1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, +1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, +1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, +1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, +1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, +1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, +1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, +1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, +1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, +1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, +1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, +1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, +1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, +1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, +1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, +1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, +1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, +1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, +1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, +1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, +1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, +1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, +1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, +1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, +1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, +1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, +1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, +1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, +1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, +1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, +1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, +1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, +1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, +1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, +1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, +1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, +1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, +1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, +1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, +1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, +1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, +1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, +1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, +1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, +1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, +1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, +1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, +1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, +1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, +1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, +1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, +1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, +1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, +1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, +1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, +1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, +1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, +1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, +1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, +1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, +1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, +1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, +1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, +1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, +1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, +1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, +1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, +1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, +1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, +1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, +1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, +1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, +1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, +1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, +1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, +1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, +1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, +1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, +1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, +1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, +1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, +1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, +1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, +1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, +1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, +1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, +1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, +1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, +1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, +1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, +1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, +1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, +1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, +1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, +1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, +1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, +1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, +1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, +1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, +1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, +1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, +1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, +1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, +1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, +1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, +1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, +1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, +1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, +1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, +1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, +1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, +1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, +1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, +1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, +1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, +1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, +1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, +1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, +1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, +1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, +1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, +1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, +1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, +1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, +1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, +1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, +1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, +1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, +1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, +1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, +1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, +1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, +1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, +1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, +1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, +1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, +1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, +1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, +1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, +1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, +1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, +1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, +1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, +1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, +1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, +1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, +1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, +1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, +1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, +1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, +1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, +1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, +1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, +1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, +1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, +1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, +1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, +1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, +1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, +1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, +1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, +1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, +1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, +1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, +1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, +1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, +1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, +1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, +1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, +1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, +1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, +1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, +1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, +1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, +1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, +1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY", +1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY", +1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY", +1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY", +1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY", +1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY", +1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY", +1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY", +1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY", +1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY", +1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", +1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", +1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", +1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", +1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", +1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", +1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", +1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", +1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", +1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", +1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, +1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, +1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, +1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, +1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, +1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, +1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, +1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, +1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, +1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, +1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, +1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, +1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, +1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, +1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, +1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, +1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, +1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, +1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, +1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, +1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, +1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, +1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, +1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, +1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, +1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, +1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, +1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, +1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, +1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, +1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, +1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, +1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, +1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, +1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, +1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, +1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, +1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, +1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, +1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, +1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, +1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, +1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, +1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, +1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, +1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, +1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, +1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, +1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, +1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, +1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, +1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, +1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, +1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, +1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, +1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, +1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, +1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, +1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, +1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, +1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, +1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, +1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, +1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, +1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, +1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, +1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, +1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, +1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, +1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, +1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, +1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, +1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, +1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, +1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, +1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, +1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, +1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, +1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, +1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, +1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, +1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, +1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, +1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, +1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, +1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, +1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, +1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, +1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, +1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, +1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, +1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, +1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, +1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, +1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, +1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, +1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, +1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, +1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, +1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, +1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, +1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, +1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, +1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, +1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, +1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, +1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, +1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, +1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, +1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, +1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, +1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, +1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, +1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, +1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, +1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, +1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, +1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, +1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, +2001,Egg Festival,Egg Hunt Victory,FESTIVAL, +2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, +2003,Flower Dance,Dance with someone,FESTIVAL, +2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, +2005,Luau,Luau Soup,FESTIVAL, +2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, +2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, +2008,Stardew Valley Fair,Grange Display,FESTIVAL, +2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, +2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, +2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, +2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, +2013,Festival of Ice,Win Fishing Competition,FESTIVAL, +2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, +2015,Night Market,Mermaid Pearl,FESTIVAL, +2016,Night Market,Cone Hat,FESTIVAL_HARD, +2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, +2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, +2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, +2020,Night Market,Lupini: Red Eagle,FESTIVAL, +2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, +2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, +2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, +2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, +2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, +2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, +2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, +2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, +2029,Feast of the Winter Star,Secret Santa,FESTIVAL, +2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, +2031,Farm,Collect All Rarecrows,FESTIVAL, +2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, +2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, +2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, +2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, +2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, +2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, +2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, +2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, +2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, +2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, +2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, +2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, +2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, +2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, +2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, +2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, +2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, +2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, +2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, +2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", +2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, +2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, +2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, +2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", +2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", +2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", +2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", +2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", +2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", +2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", +2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", +2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", +2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, +2216,Field Office,Complete Island Field Office,GINGER_ISLAND, +2301,Farming,Harvest Amaranth,"CROPSANITY", +2302,Farming,Harvest Artichoke,"CROPSANITY", +2303,Farming,Harvest Beet,"CROPSANITY", +2304,Farming,Harvest Blue Jazz,"CROPSANITY", +2305,Farming,Harvest Blueberry,"CROPSANITY", +2306,Farming,Harvest Bok Choy,"CROPSANITY", +2307,Farming,Harvest Cauliflower,"CROPSANITY", +2308,Farming,Harvest Corn,"CROPSANITY", +2309,Farming,Harvest Cranberries,"CROPSANITY", +2310,Farming,Harvest Eggplant,"CROPSANITY", +2311,Farming,Harvest Fairy Rose,"CROPSANITY", +2312,Farming,Harvest Garlic,"CROPSANITY", +2313,Farming,Harvest Grape,"CROPSANITY", +2314,Farming,Harvest Green Bean,"CROPSANITY", +2315,Farming,Harvest Hops,"CROPSANITY", +2316,Farming,Harvest Hot Pepper,"CROPSANITY", +2317,Farming,Harvest Kale,"CROPSANITY", +2318,Farming,Harvest Melon,"CROPSANITY", +2319,Farming,Harvest Parsnip,"CROPSANITY", +2320,Farming,Harvest Poppy,"CROPSANITY", +2321,Farming,Harvest Potato,"CROPSANITY", +2322,Farming,Harvest Pumpkin,"CROPSANITY", +2323,Farming,Harvest Radish,"CROPSANITY", +2324,Farming,Harvest Red Cabbage,"CROPSANITY", +2325,Farming,Harvest Rhubarb,"CROPSANITY", +2326,Farming,Harvest Starfruit,"CROPSANITY", +2327,Farming,Harvest Strawberry,"CROPSANITY", +2328,Farming,Harvest Summer Spangle,"CROPSANITY", +2329,Farming,Harvest Sunflower,"CROPSANITY", +2330,Farming,Harvest Tomato,"CROPSANITY", +2331,Farming,Harvest Tulip,"CROPSANITY", +2332,Farming,Harvest Unmilled Rice,"CROPSANITY", +2333,Farming,Harvest Wheat,"CROPSANITY", +2334,Farming,Harvest Yam,"CROPSANITY", +2335,Farming,Harvest Cactus Fruit,"CROPSANITY", +2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", +2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", +2338,Farming,Harvest Sweet Gem Berry,"CROPSANITY", +2339,Farming,Harvest Apple,"CROPSANITY", +2340,Farming,Harvest Apricot,"CROPSANITY", +2341,Farming,Harvest Cherry,"CROPSANITY", +2342,Farming,Harvest Orange,"CROPSANITY", +2343,Farming,Harvest Pomegranate,"CROPSANITY", +2344,Farming,Harvest Peach,"CROPSANITY", +2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", +2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", +2347,Farming,Harvest Coffee Bean,"CROPSANITY", +2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Shipping,Shipsanity: Anchor,SHIPSANITY, +2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, +2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, +2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, +2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, +2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, +2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, +2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, +2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Shipping,Shipsanity: Coffee,SHIPSANITY, +2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, +2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, +2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Shipping,Shipsanity: Bread,SHIPSANITY, +2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, +2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Shipping,Shipsanity: Chowder,SHIPSANITY, +2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, +2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Shipping,Shipsanity: Cookies,SHIPSANITY, +2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Shipping,Shipsanity: Escargot,SHIPSANITY, +2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, +2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, +2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, +2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, +2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, +2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, +2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, +2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Shipping,Shipsanity: Omelet,SHIPSANITY, +2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, +2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, +2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, +2518,Shipping,Shipsanity: Pizza,SHIPSANITY, +2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, +2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, +2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, +2529,Shipping,Shipsanity: Salad,SHIPSANITY, +2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, +2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, +2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, +2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, +2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, +2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, +2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, +2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, +2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, +2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Shipping,Shipsanity: Bait,SHIPSANITY, +2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Shipping,Shipsanity: Bomb,SHIPSANITY, +2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, +2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, +2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, +2560,Shipping,Shipsanity: Crystal Floor,"SHIPSANITY", +2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, +2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, +2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, +2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, +2569,Shipping,Shipsanity: Gate,SHIPSANITY, +2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, +2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, +2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, +2578,Shipping,Shipsanity: Magnet,SHIPSANITY, +2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, +2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, +2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Shipping,Shipsanity: Spinner,SHIPSANITY, +2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, +2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, +2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, +2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, +2598,Shipping,Shipsanity: Torch,SHIPSANITY, +2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", +2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Shipping,Shipsanity: Weathered Floor,"SHIPSANITY", +2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, +2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, +2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, +2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, +2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, +2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Shipping,Shipsanity: Oil,SHIPSANITY, +2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Shipping,Shipsanity: Rice,SHIPSANITY, +2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Shipping,Shipsanity: Sugar,SHIPSANITY, +2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, +2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, +2765,Shipping,Shipsanity: Alamite,SHIPSANITY, +2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, +2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, +2769,Shipping,Shipsanity: Baryte,SHIPSANITY, +2770,Shipping,Shipsanity: Basalt,SHIPSANITY, +2771,Shipping,Shipsanity: Bixite,SHIPSANITY, +2772,Shipping,Shipsanity: Calcite,SHIPSANITY, +2773,Shipping,Shipsanity: Celestine,SHIPSANITY, +2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Shipping,Shipsanity: Diamond,SHIPSANITY, +2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, +2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Shipping,Shipsanity: Emerald,SHIPSANITY, +2780,Shipping,Shipsanity: Esperite,SHIPSANITY, +2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, +2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Shipping,Shipsanity: Geminite,SHIPSANITY, +2788,Shipping,Shipsanity: Geode,SHIPSANITY, +2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Shipping,Shipsanity: Granite,SHIPSANITY, +2792,Shipping,Shipsanity: Helvite,SHIPSANITY, +2793,Shipping,Shipsanity: Hematite,SHIPSANITY, +2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Shipping,Shipsanity: Jade,SHIPSANITY, +2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, +2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, +2799,Shipping,Shipsanity: Jasper,SHIPSANITY, +2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, +2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Shipping,Shipsanity: Limestone,SHIPSANITY, +2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, +2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, +2805,Shipping,Shipsanity: Malachite,SHIPSANITY, +2806,Shipping,Shipsanity: Marble,SHIPSANITY, +2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, +2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, +2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, +2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, +2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, +2814,Shipping,Shipsanity: Opal,SHIPSANITY, +2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, +2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, +2825,Shipping,Shipsanity: Quartz,SHIPSANITY, +2826,Shipping,Shipsanity: Ruby,SHIPSANITY, +2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, +2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Shipping,Shipsanity: Slate,SHIPSANITY, +2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, +2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, +2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, +2835,Shipping,Shipsanity: Topaz,SHIPSANITY, +2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, +2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", +2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, +2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, +2848,Shipping,Shipsanity: Hay,SHIPSANITY, +2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Shipping,Shipsanity: Pearl,SHIPSANITY, +2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, +2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Shipping,Shipsanity: White Algae,SHIPSANITY, +2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, +2858,Shipping,Shipsanity: Acorn,SHIPSANITY, +2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, +2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, +2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, +2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, +2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, +2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, +2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, +2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, +2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, +2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, +2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Shipping,Shipsanity: Trash,SHIPSANITY, +2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, +2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", +2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Shipping,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", +2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", +3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", +3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", +3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", +3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", +3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", +3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", +3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", +3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", +3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", +3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3201,Kitchen,Cook Algae Soup,"COOKSANITY", +3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", +3203,Kitchen,Cook Autumn's Bounty,"COOKSANITY", +3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", +3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", +3206,Kitchen,Cook Bean Hotpot,"COOKSANITY", +3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", +3208,Kitchen,Cook Blueberry Tart,"COOKSANITY", +3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", +3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", +3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", +3212,Kitchen,Cook Cheese Cauliflower,"COOKSANITY", +3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", +3214,Kitchen,Cook Chowder,"COOKSANITY", +3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", +3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", +3217,Kitchen,Cook Cookies,"COOKSANITY", +3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", +3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", +3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY", +3221,Kitchen,Cook Crispy Bass,"COOKSANITY", +3222,Kitchen,Cook Dish O' The Sea,"COOKSANITY", +3223,Kitchen,Cook Eggplant Parmesan,"COOKSANITY", +3224,Kitchen,Cook Escargot,"COOKSANITY", +3225,Kitchen,Cook Farmer's Lunch,"COOKSANITY", +3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", +3227,Kitchen,Cook Fish Stew,"COOKSANITY", +3228,Kitchen,Cook Fish Taco,"COOKSANITY", +3229,Kitchen,Cook Fried Calamari,"COOKSANITY", +3230,Kitchen,Cook Fried Eel,"COOKSANITY", +3231,Kitchen,Cook Fried Egg,"COOKSANITY", +3232,Kitchen,Cook Fried Mushroom,"COOKSANITY", +3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", +3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", +3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", +3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", +3237,Kitchen,Cook Ice Cream,"COOKSANITY", +3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", +3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", +3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", +3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", +3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", +3243,Kitchen,Cook Miner's Treat,"COOKSANITY", +3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", +3245,Kitchen,Cook Pale Broth,"COOKSANITY", +3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", +3247,Kitchen,Cook Parsnip Soup,"COOKSANITY", +3248,Kitchen,Cook Pepper Poppers,"COOKSANITY", +3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", +3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", +3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", +3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", +3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", +3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", +3255,Kitchen,Cook Pumpkin Soup,"COOKSANITY", +3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", +3257,Kitchen,Cook Red Plate,"COOKSANITY", +3258,Kitchen,Cook Rhubarb Pie,"COOKSANITY", +3259,Kitchen,Cook Rice Pudding,"COOKSANITY", +3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", +3261,Kitchen,Cook Roots Platter,"COOKSANITY", +3262,Kitchen,Cook Salad,"COOKSANITY", +3263,Kitchen,Cook Salmon Dinner,"COOKSANITY", +3264,Kitchen,Cook Sashimi,"COOKSANITY", +3265,Kitchen,Cook Seafoam Pudding,"COOKSANITY", +3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", +3267,Kitchen,Cook Spaghetti,"COOKSANITY", +3268,Kitchen,Cook Spicy Eel,"COOKSANITY", +3269,Kitchen,Cook Squid Ink Ravioli,"COOKSANITY", +3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", +3271,Kitchen,Cook Strange Bun,"COOKSANITY", +3272,Kitchen,Cook Stuffing,"COOKSANITY", +3273,Kitchen,Cook Super Meal,"COOKSANITY", +3274,Kitchen,Cook Survival Burger,"COOKSANITY", +3275,Kitchen,Cook Tom Kha Soup,"COOKSANITY", +3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", +3277,Kitchen,Cook Triple Shot Espresso,"COOKSANITY", +3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", +3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", +3280,Kitchen,Cook Vegetable Medley,"COOKSANITY", +3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3331,Farm,Fried Egg Recipe,"CHEFSANITY_STARTER", +3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3401,Farm,Craft Cherry Bomb,"CRAFTSANITY", +3402,Farm,Craft Bomb,"CRAFTSANITY", +3403,Farm,Craft Mega Bomb,"CRAFTSANITY", +3404,Farm,Craft Gate,"CRAFTSANITY", +3405,Farm,Craft Wood Fence,"CRAFTSANITY", +3406,Farm,Craft Stone Fence,"CRAFTSANITY", +3407,Farm,Craft Iron Fence,"CRAFTSANITY", +3408,Farm,Craft Hardwood Fence,"CRAFTSANITY", +3409,Farm,Craft Sprinkler,"CRAFTSANITY", +3410,Farm,Craft Quality Sprinkler,"CRAFTSANITY", +3411,Farm,Craft Iridium Sprinkler,"CRAFTSANITY", +3412,Farm,Craft Bee House,"CRAFTSANITY", +3413,Farm,Craft Cask,"CRAFTSANITY", +3414,Farm,Craft Cheese Press,"CRAFTSANITY", +3415,Farm,Craft Keg,"CRAFTSANITY", +3416,Farm,Craft Loom,"CRAFTSANITY", +3417,Farm,Craft Mayonnaise Machine,"CRAFTSANITY", +3418,Farm,Craft Oil Maker,"CRAFTSANITY", +3419,Farm,Craft Preserves Jar,"CRAFTSANITY", +3420,Farm,Craft Basic Fertilizer,"CRAFTSANITY", +3421,Farm,Craft Quality Fertilizer,"CRAFTSANITY", +3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY", +3423,Farm,Craft Speed-Gro,"CRAFTSANITY", +3424,Farm,Craft Deluxe Speed-Gro,"CRAFTSANITY", +3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", +3426,Farm,Craft Basic Retaining Soil,"CRAFTSANITY", +3427,Farm,Craft Quality Retaining Soil,"CRAFTSANITY", +3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", +3429,Farm,Craft Tree Fertilizer,"CRAFTSANITY", +3430,Farm,Craft Spring Seeds,"CRAFTSANITY", +3431,Farm,Craft Summer Seeds,"CRAFTSANITY", +3432,Farm,Craft Fall Seeds,"CRAFTSANITY", +3433,Farm,Craft Winter Seeds,"CRAFTSANITY", +3434,Farm,Craft Ancient Seeds,"CRAFTSANITY", +3435,Farm,Craft Grass Starter,"CRAFTSANITY", +3436,Farm,Craft Tea Sapling,"CRAFTSANITY", +3437,Farm,Craft Fiber Seeds,"CRAFTSANITY", +3438,Farm,Craft Wood Floor,"CRAFTSANITY", +3439,Farm,Craft Rustic Plank Floor,"CRAFTSANITY", +3440,Farm,Craft Straw Floor,"CRAFTSANITY", +3441,Farm,Craft Weathered Floor,"CRAFTSANITY", +3442,Farm,Craft Crystal Floor,"CRAFTSANITY", +3443,Farm,Craft Stone Floor,"CRAFTSANITY", +3444,Farm,Craft Stone Walkway Floor,"CRAFTSANITY", +3445,Farm,Craft Brick Floor,"CRAFTSANITY", +3446,Farm,Craft Wood Path,"CRAFTSANITY", +3447,Farm,Craft Gravel Path,"CRAFTSANITY", +3448,Farm,Craft Cobblestone Path,"CRAFTSANITY", +3449,Farm,Craft Stepping Stone Path,"CRAFTSANITY", +3450,Farm,Craft Crystal Path,"CRAFTSANITY", +3451,Farm,Craft Spinner,"CRAFTSANITY", +3452,Farm,Craft Trap Bobber,"CRAFTSANITY", +3453,Farm,Craft Cork Bobber,"CRAFTSANITY", +3454,Farm,Craft Quality Bobber,"CRAFTSANITY", +3455,Farm,Craft Treasure Hunter,"CRAFTSANITY", +3456,Farm,Craft Dressed Spinner,"CRAFTSANITY", +3457,Farm,Craft Barbed Hook,"CRAFTSANITY", +3458,Farm,Craft Magnet,"CRAFTSANITY", +3459,Farm,Craft Bait,"CRAFTSANITY", +3460,Farm,Craft Wild Bait,"CRAFTSANITY", +3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", +3462,Farm,Craft Crab Pot,"CRAFTSANITY", +3463,Farm,Craft Sturdy Ring,"CRAFTSANITY", +3464,Farm,Craft Warrior Ring,"CRAFTSANITY", +3465,Farm,Craft Ring of Yoba,"CRAFTSANITY", +3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", +3467,Farm,Craft Glowstone Ring,"CRAFTSANITY", +3468,Farm,Craft Iridium Band,"CRAFTSANITY", +3469,Farm,Craft Wedding Ring,"CRAFTSANITY", +3470,Farm,Craft Field Snack,"CRAFTSANITY", +3471,Farm,Craft Bug Steak,"CRAFTSANITY", +3472,Farm,Craft Life Elixir,"CRAFTSANITY", +3473,Farm,Craft Oil of Garlic,"CRAFTSANITY", +3474,Farm,Craft Monster Musk,"CRAFTSANITY", +3475,Farm,Craft Fairy Dust,"CRAFTSANITY", +3476,Farm,Craft Warp Totem: Beach,"CRAFTSANITY", +3477,Farm,Craft Warp Totem: Mountains,"CRAFTSANITY", +3478,Farm,Craft Warp Totem: Farm,"CRAFTSANITY", +3479,Farm,Craft Warp Totem: Desert,"CRAFTSANITY", +3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", +3481,Farm,Craft Rain Totem,"CRAFTSANITY", +3482,Farm,Craft Torch,"CRAFTSANITY", +3483,Farm,Craft Campfire,"CRAFTSANITY", +3484,Farm,Craft Wooden Brazier,"CRAFTSANITY", +3485,Farm,Craft Stone Brazier,"CRAFTSANITY", +3486,Farm,Craft Gold Brazier,"CRAFTSANITY", +3487,Farm,Craft Carved Brazier,"CRAFTSANITY", +3488,Farm,Craft Stump Brazier,"CRAFTSANITY", +3489,Farm,Craft Barrel Brazier,"CRAFTSANITY", +3490,Farm,Craft Skull Brazier,"CRAFTSANITY", +3491,Farm,Craft Marble Brazier,"CRAFTSANITY", +3492,Farm,Craft Wood Lamp-post,"CRAFTSANITY", +3493,Farm,Craft Iron Lamp-post,"CRAFTSANITY", +3494,Farm,Craft Jack-O-Lantern,"CRAFTSANITY", +3495,Farm,Craft Bone Mill,"CRAFTSANITY", +3496,Farm,Craft Charcoal Kiln,"CRAFTSANITY", +3497,Farm,Craft Crystalarium,"CRAFTSANITY", +3498,Farm,Craft Furnace,"CRAFTSANITY", +3499,Farm,Craft Geode Crusher,"CRAFTSANITY", +3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", +3501,Farm,Craft Lightning Rod,"CRAFTSANITY", +3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", +3503,Farm,Craft Recycling Machine,"CRAFTSANITY", +3504,Farm,Craft Seed Maker,"CRAFTSANITY", +3505,Farm,Craft Slime Egg-Press,"CRAFTSANITY", +3506,Farm,Craft Slime Incubator,"CRAFTSANITY", +3507,Farm,Craft Solar Panel,"CRAFTSANITY", +3508,Farm,Craft Tapper,"CRAFTSANITY", +3509,Farm,Craft Worm Bin,"CRAFTSANITY", +3510,Farm,Craft Tub o' Flowers,"CRAFTSANITY", +3511,Farm,Craft Wicked Statue,"CRAFTSANITY", +3512,Farm,Craft Flute Block,"CRAFTSANITY", +3513,Farm,Craft Drum Block,"CRAFTSANITY", +3514,Farm,Craft Chest,"CRAFTSANITY", +3515,Farm,Craft Stone Chest,"CRAFTSANITY", +3516,Farm,Craft Wood Sign,"CRAFTSANITY", +3517,Farm,Craft Stone Sign,"CRAFTSANITY", +3518,Farm,Craft Dark Sign,"CRAFTSANITY", +3519,Farm,Craft Garden Pot,"CRAFTSANITY", +3520,Farm,Craft Scarecrow,"CRAFTSANITY", +3521,Farm,Craft Deluxe Scarecrow,"CRAFTSANITY", +3522,Farm,Craft Staircase,"CRAFTSANITY", +3523,Farm,Craft Explosive Ammo,"CRAFTSANITY", +3524,Farm,Craft Transmute (Fe),"CRAFTSANITY", +3525,Farm,Craft Transmute (Au),"CRAFTSANITY", +3526,Farm,Craft Mini-Jukebox,"CRAFTSANITY", +3527,Farm,Craft Mini-Obelisk,"CRAFTSANITY", +3528,Farm,Craft Farm Computer,"CRAFTSANITY", +3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", +3530,Farm,Craft Cookout Kit,"CRAFTSANITY", +3551,Pierre's General Store,Grass Starter Recipe,"CRAFTSANITY", +3552,Carpenter Shop,Wood Floor Recipe,"CRAFTSANITY", +3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", +3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", +3555,Mines Dwarf Shop,Weathered Floor Recipe,"CRAFTSANITY", +3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY", +3557,Carpenter Shop,Stone Floor Recipe,"CRAFTSANITY", +3558,Carpenter Shop,Stone Walkway Floor Recipe,"CRAFTSANITY", +3559,Carpenter Shop,Brick Floor Recipe,"CRAFTSANITY", +3560,Carpenter Shop,Stepping Stone Path Recipe,"CRAFTSANITY", +3561,Carpenter Shop,Crystal Path Recipe,"CRAFTSANITY", +3562,Traveling Cart,Wedding Ring Recipe,"CRAFTSANITY", +3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", +3564,Carpenter Shop,Wooden Brazier Recipe,"CRAFTSANITY", +3565,Carpenter Shop,Stone Brazier Recipe,"CRAFTSANITY", +3566,Carpenter Shop,Gold Brazier Recipe,"CRAFTSANITY", +3567,Carpenter Shop,Carved Brazier Recipe,"CRAFTSANITY", +3568,Carpenter Shop,Stump Brazier Recipe,"CRAFTSANITY", +3569,Carpenter Shop,Barrel Brazier Recipe,"CRAFTSANITY", +3570,Carpenter Shop,Skull Brazier Recipe,"CRAFTSANITY", +3571,Carpenter Shop,Marble Brazier Recipe,"CRAFTSANITY", +3572,Carpenter Shop,Wood Lamp-post Recipe,"CRAFTSANITY", +3573,Carpenter Shop,Iron Lamp-post Recipe,"CRAFTSANITY", +3574,Sewer,Wicked Statue Recipe,"CRAFTSANITY", +5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic +5502,Magic Altar,Analyze: Till,MANDATORY,Magic +5503,Magic Altar,Analyze: Water,MANDATORY,Magic +5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic +5505,Magic Altar,Analyze: Evac,MANDATORY,Magic +5506,Magic Altar,Analyze: Haste,MANDATORY,Magic +5507,Magic Altar,Analyze: Heal,MANDATORY,Magic +5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic +5509,Magic Altar,Analyze: Descend,MANDATORY,Magic +5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbite,MANDATORY,Magic +5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic +5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic +5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic +5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic +5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic +5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic +5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic +5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic +5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic +5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic +6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas +6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas +6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas +6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas +6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas +6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas +6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas +6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas +6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas +6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas +6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas +6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas +6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas +6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas +6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba +6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba +6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba +6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba +6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba +6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba +6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba +6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba +6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba +6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba +6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) +6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) +6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) +6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) +6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) +6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) +6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) +6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) +6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) +6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) +6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC +6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC +6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC +6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC +6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC +6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC +6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC +6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC +6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC +6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC +6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC +6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC +6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC +6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC +6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick +6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick +6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick +6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick +6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick +6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick +6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick +6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick +6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick +6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick +6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick +6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick +6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick +6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick +6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC +6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC +6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC +6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC +6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC +6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC +6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC +6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC +6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC +6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC +6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC +6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC +6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC +6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC +6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited +6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited +6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited +6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited +6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited +6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited +6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited +6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited +6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited +6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited +6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited +6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited +6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited +6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited +6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene +6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene +6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene +6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene +6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene +6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene +6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene +6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene +6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene +6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene +6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene +6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene +6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene +6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene +6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC +6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC +6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC +6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC +6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC +6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC +6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC +6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC +6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC +6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC +6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley +6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley +6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley +6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley +6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley +6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley +6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley +6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley +6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley +6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley +6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley +6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley +6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley +6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded +6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded +6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded +6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded +6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded +6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded +6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded +6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded +6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded +6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded +6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded +6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded +6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded +6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded +6153,Highlands,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Highlands,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Highlands,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Highlands,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Highlands,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Highlands,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Highlands,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Highlands,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Highlands,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Highlands,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Highlands,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded +6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded +6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded +6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded +6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded +6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded +6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded +6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded +6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded +6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded +6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded +6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded +6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded +6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded +6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded +6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded +6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded +6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded +6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded +6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded +6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded +6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded +6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded +6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded +6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded +6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded +6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded +6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded +6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded +6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded +6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded +6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded +6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded +6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded +6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded +6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded +6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded +6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded +6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded +6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded +6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded +6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded +6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded +6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded +6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded +6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded +6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded +6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded +6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded +6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded +6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded +6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded +6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded +6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded +6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded +6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded +6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded +6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded +6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded +6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded +6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded +6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded +6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded +6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded +6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded +6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded +6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded +6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded +6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6273,Blue Moon Vineyard,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded +6274,Blue Moon Vineyard,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded +6275,Blue Moon Vineyard,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded +6276,Blue Moon Vineyard,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded +6277,Blue Moon Vineyard,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded +6278,Blue Moon Vineyard,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded +6279,Blue Moon Vineyard,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded +6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded +6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded +6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded +6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded +6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded +6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded +6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded +6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded +6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded +6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded +6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded +6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded +7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack +7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod +7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods +7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods +7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods +7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods +7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods +7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods +7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods +7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods +7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods +7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods +7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods +7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods +7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods +7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods +7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods +7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods +7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods +7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator +7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator +7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator +7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator +7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator +7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator +7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator +7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic +7402,Farm,Craft Travel Core,CRAFTSANITY,Magic +7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded +7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded +7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Farm,Craft Glass Path,CRAFTSANITY,Archaeology +7407,Farm,Craft Bone Path,CRAFTSANITY,Archaeology +7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology +7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology +7410,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology +7411,Farm,Craft Grinder,CRAFTSANITY,Archaeology +7412,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology +7413,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology +7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology +7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology +7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology +7417,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology +7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic +7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic +7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Issac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology +7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology +7458,Farm,Glass Bazier Recipe,CRAFTSANITY,Archaeology +7459,Farm,Glass Fence Recipe,CRAFTSANITY,Archaeology +7460,Farm,Water Shifter Recipe,CRAFTSANITY,Archaeology +7461,Farm,Grinder Recipe,CRAFTSANITY,Archaeology +7462,Farm,Ancient Battery Production Station Recipe,CRAFTSANITY,Archaeology +7463,Farm,Preservation Chamber Recipe,CRAFTSANITY,Archaeology +7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology +7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology +7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology +7467,Farm,Dwarf Gadget: Infinite Volcano Simulation Recipe,"CRAFTSANITY,GINGER_ISLAND",Archaeology +7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) +7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC +7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC +7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC +7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded +7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded +7509,Grandpa's Shed Interior,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded +7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded +7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded +7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded +7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded +7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded +7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded +7554,Kitchen,Cook Frog Legs,"COOKSANITY",Stardew Valley Expanded +7555,Kitchen,Cook Glazed Butterfish,"COOKSANITY",Stardew Valley Expanded +7556,Kitchen,Cook Mixed Berry Pie,"COOKSANITY",Stardew Valley Expanded +7557,Kitchen,Cook Mushroom Berry Rice,"COOKSANITY",Stardew Valley Expanded +7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded +7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded +7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded +7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7651,Alesia Shop,Purchase Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7652,Issac Shop,Purchase Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Issac Shop,Purchase Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded +7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded +7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded +7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7706,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded +7708,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded +7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded +7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded +7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded +7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded +7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded +7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded +7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded +7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded +7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded +7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded +7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic +8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded +8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded +8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded +8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded +8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded +8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded +8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded +8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded +8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded +8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded +8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded +8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded +8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded +8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded +8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded +8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded +8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded +8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded +8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded +8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded +8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded +8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded +8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded +8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology +8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology +8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology +8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology +8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology +8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology +8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology +8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology +8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology +8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology +8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology +8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology +8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology +8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology +8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology +8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology +8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology +8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology +8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology +8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology +8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology +8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology +8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology +8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology +8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology +8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology +8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology +8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology +8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology +8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology +8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology +8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology +8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology +8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology +8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology +8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology +8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology +8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology +8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology +8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology +8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology +8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology +8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology +8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology +8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology +8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology +8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology +8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology +8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology +8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology +8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology +8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology +8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology +8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology +8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology +8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology +8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology +8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology +8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology +8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology +8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology +8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology +8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology +8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology +8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology +8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology +8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology +8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology +8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology +8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology +8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology +8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology +8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 5e349a33f4f0..ce99b3eb97cf 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -44,3 +44,14 @@ def has_any_rune(self): rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", "Nexus: Outpost Runes", "Nexus: Farm Runes", "Nexus: Wizard Runes"] return Or(*(self.logic.received(rune) for rune in rune_list)) + + def append_sve_recipe_rules(self, recipe: str): + if recipe == SVEMeal.glazed_butterfish: + return self.logic.relationship.has_hearts(NPC.gus, 10) + if recipe == SVEMeal.big_bark_burger: + return self.logic.relationship.has_hearts(NPC.gus, 5) + if recipe == SVEMeal.mushroom_berry_rice: + return self.logic.relationship.has_hearts(ModNPC.marlon, 6) + if recipe == SVEMeal.void_delight: + return self.logic.relationship.has_hearts(NPC.krobus, 10) + return True_() diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index f03476b509ee..71c0a2ffaaef 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -736,7 +736,9 @@ def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, mul recipe_name = location.name[:-len(chefsanity_suffix)] recipe = all_cooking_recipes_by_name[recipe_name] learn_rule = logic.cooking.can_learn_recipe(recipe.source) - MultiWorldRules.set_rule(multiworld.get_location(location.name, player), learn_rule) + friendship_purchase_rule = logic.mod.sve.append_sve_recipe_rules(recipe_name) + full_rule = learn_rule & friendship_purchase_rule + MultiWorldRules.set_rule(multiworld.get_location(location.name, player), full_rule) def set_craftsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index 055deccc4d8e..e70fd9f63197 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -153,7 +153,7 @@ class ModEdible: class ModCraftable: travel_core = "Travel Core" glass_bazier = "Glass Bazier" - water_strainer = "Water Strainer" + water_shifter = "Water Shifter" glass_fence = "Glass Fence" wooden_display = "Wooden Display" hardwood_display = "Hardwood Display" @@ -163,7 +163,7 @@ class ModMachine: preservation_chamber = "Preservation Chamber" hardwood_preservation_chamber = "hardwood Preservation Chamber" grinder = "Grinder" - ancient_battery = "Ancient Battery Creator" + ancient_battery = "Ancient Battery Production Station" class ModFloor: @@ -172,6 +172,6 @@ class ModFloor: class ModConsumable: - volcano_totem = "Warp Totem: Volcano" + volcano_totem = "Dwarf Gadget: Infinite Volcano Simulation" From a9cc2134214123aa77ba345d3ec7798945cafcc4 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:08:49 -0600 Subject: [PATCH 275/482] Add excalibur location --- worlds/stardew_valley/data/items.csv | 3 +++ worlds/stardew_valley/data/locations.csv | 1 + worlds/stardew_valley/mods/logic/deepwoods_logic.py | 5 +++++ worlds/stardew_valley/rules.py | 2 ++ 4 files changed, 11 insertions(+) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index adc5af611263..d812225b29db 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -750,6 +750,9 @@ id,name,classification,groups,mod_name 10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic 10028,Spell: Spirit,progression,MAGIC_SPELL,Magic 10029,Spell: Rewind,useful,MAGIC_SPELL,Magic +10030,Pendant of Community,progression,,DeepWoods +10031,Pendant of Elders,progression,,DeepWoods +10032,Pendant of Depths,progression,,DeepWoods 10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC 10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas 10103,Alec <3,progression,FRIENDSANITY,Alec Revisited diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c0b2f42c6739..f4914ad68b93 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2481,6 +2481,7 @@ id,region,name,tags,mod_name 7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator 7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator 7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods 7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic 7402,Farm,Craft Travel Core,CRAFTSANITY,Magic 7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index ca3ff8002b0f..dcd753c3f5e9 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -49,3 +49,8 @@ def can_chop_to_depth(self, floor: int) -> StardewRule: previous_elevator = max(floor - 10, 0) return (self.has_woods_rune_to_depth(previous_elevator) & self.can_reach_woods_depth(previous_elevator)) + + def can_pull_sword(self) -> StardewRule: + rules = [self.logic.received("Pendant of Depths") & self.logic.received("Pendant of Community") & self.logic.received("Pendant of Elders"), + self.logic.skill.has_total_level(40)] + return And(*rules) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 71c0a2ffaaef..eb82f16142b9 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -828,6 +828,8 @@ def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int for depth in range(10, 100 + 10, 10): MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), logic.mod.deepwoods.can_chop_to_depth(depth)) + MultiWorldRules.add_rule(multiworld.get_location("The Sword in the Stone", player), + logic.mod.deepwoods.can_pull_sword()) def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): From f79e2324ad86e1025f8d8ad3375468eb369ae5c2 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:09:15 -0600 Subject: [PATCH 276/482] Add SVE special orders --- worlds/stardew_valley/data/locations.csv | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f4914ad68b93..36c6384376ef 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2528,6 +2528,11 @@ id,region,name,tags,mod_name 7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded 7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded 7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded +7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded +7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded From 7fd8b0e95215417a05a899759fa04931603efa4d Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:09:38 -0600 Subject: [PATCH 277/482] Fix Frostbolt name --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/rules.py | 2 +- worlds/stardew_valley/strings/spells.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index d812225b29db..4cb937cf3027 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -739,7 +739,7 @@ id,name,classification,groups,mod_name 10016,Spell: Buff,useful,MAGIC_SPELL,Magic 10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic 10018,Spell: Fireball,progression,MAGIC_SPELL,Magic -10019,Spell: Frostbite,progression,MAGIC_SPELL,Magic +10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic 10020,Spell: Teleport,progression,MAGIC_SPELL,Magic 10021,Spell: Lantern,filler,MAGIC_SPELL,Magic 10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 36c6384376ef..bc579a466b0a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2141,7 +2141,7 @@ id,region,name,tags,mod_name 5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic 5509,Magic Altar,Analyze: Descend,MANDATORY,Magic 5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic -5511,Magic Altar,Analyze: Frostbite,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic 5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic 5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic 5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index eb82f16142b9..1735ca86fb83 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -862,7 +862,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i logic.region.can_reach(Region.mines)) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), logic.has("Fire Quartz")) - MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbite", player), + MultiWorldRules.add_rule(multiworld.get_location("Analyze: Frostbolt", player), logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Elemental School Locations", player), logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85)) diff --git a/worlds/stardew_valley/strings/spells.py b/worlds/stardew_valley/strings/spells.py index fd2a515db9ff..ef5545c56902 100644 --- a/worlds/stardew_valley/strings/spells.py +++ b/worlds/stardew_valley/strings/spells.py @@ -9,7 +9,7 @@ class MagicSpell: buff = "Spell: Buff" shockwave = "Spell: Shockwave" fireball = "Spell: Fireball" - frostbite = "Spell: Frostbite" + frostbite = "Spell: Frostbolt" teleport = "Spell: Teleport" lantern = "Spell: Lantern" tendrils = "Spell: Tendrils" From be9b71a8d80ab2fb2bd69ba1fc266e46e942745b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:09:58 -0600 Subject: [PATCH 278/482] Include missing imports --- worlds/stardew_valley/mods/logic/sve_logic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index ce99b3eb97cf..e4bb721d5380 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -14,7 +14,9 @@ from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin -from ...stardew_rule import Or +from ...strings.food_names import SVEMeal +from ...strings.villager_names import NPC, ModNPC +from ...stardew_rule import Or, True_ class SVELogicMixin(BaseLogicMixin): From 84c90f4b77c0197bee4a529b3347a15a46569709 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 14:10:42 -0600 Subject: [PATCH 279/482] general fixes --- worlds/stardew_valley/items.py | 7 +++++++ worlds/stardew_valley/logic/relationship_logic.py | 10 ++++++++++ worlds/stardew_valley/mods/logic/item_logic.py | 2 +- worlds/stardew_valley/rules.py | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index b3d14d8a5838..80cba1fef1b1 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -217,6 +217,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_cooking_recipes(item_factory, options, items) create_magic_mod_spells(item_factory, options, items) items.append(item_factory("Golden Egg")) + create_deepwoods_pendants(item_factory, options, items) return items @@ -568,6 +569,12 @@ def create_magic_mod_spells(item_factory: StardewItemFactory, options: StardewVa items.extend([item_factory(item) for item in items_by_group[Group.MAGIC_SPELL]]) +def create_deepwoods_pendants(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if ModNames.deepwoods not in options.mods: + return + items.extend([item_factory(item) for item in ["Pendant of Elders", "Pendant of Community", "Pendant of Depths"]]) + + def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true if ModNames.sve not in options.mods: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 7f60ea914505..a2a5fd4b81b0 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -13,9 +13,11 @@ from ..data.villagers_data import all_villagers_by_name, Villager from ..options import Friendsanity from ..stardew_rule import StardewRule, True_, And, Or, Count +from ..strings.crop_names import Fruit from ..strings.generic_names import Generic from ..strings.gift_names import Gift from ..strings.region_names import Region +from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC possible_kids = ("Cute Baby", "Ugly Baby") @@ -112,6 +114,14 @@ def can_meet(self, npc: str) -> StardewRule: rules.append(self.logic.received("Island West Turtle")) elif npc == ModNPC.lance: rules.append(self.logic.region.can_reach(Region.volcano_floor_10)) + elif npc == ModNPC.apples: + rules.append(self.logic.has(Fruit.starfruit)) + elif npc == ModNPC.scarlett: + scarlett_job = self.logic.received("Scarlett's Job Offer") + scarlett_spring = self.logic.season.has(Season.spring) & self.can_meet(ModNPC.andy) + scarlett_summer = self.logic.season.has(Season.summer) & self.can_meet(ModNPC.susan) + scarlett_fall = self.logic.season.has(Season.fall) & self.can_meet(ModNPC.sophia) + rules.append(scarlett_job & (scarlett_spring | scarlett_summer | scarlett_fall)) return And(*rules) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 6b8bbad72a4f..ac66633bcd7e 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -88,7 +88,7 @@ def get_sve_item_rules(self): self.logic.season.has_any([Season.summer, Season.fall])), "Galdoran Gem": self.logic.museum.can_complete_museum() & self.logic.relationship.has_hearts(ModNPC.marlon, 8), SVEForage.golden_ocean_flower: self.logic.region.can_reach(SVERegion.fable_reef), - SVEMeal.grampleton_orange_chicken: self.logic.money.can_spend_at(Region.saloon, 650), + SVEMeal.grampleton_orange_chicken: self.logic.money.can_spend_at(Region.saloon, 650) & self.logic.relationship.has_hearts(ModNPC.sophia, 6), ModEdible.hero_elixir: self.logic.money.can_spend_at(SVERegion.issac_shop, 8000), SVEForage.lucky_four_leaf_clover: self.logic.region.can_reach_any((Region.secret_woods, SVERegion.forest_west)) & self.logic.season.has_any([Season.spring, Season.summer]), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 1735ca86fb83..96b62dd6f7a6 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -903,6 +903,8 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.received("Iridium Bomb")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), logic.mod.sve.has_any_rune()) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.badlands_to_cave, player), + logic.has("Aegis Elixir")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), logic.quest.can_complete_quest(Quest.magic_ink)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), From 6542f217c3cb2feb1db28f375d04580f9a4fad03 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 19:39:45 -0600 Subject: [PATCH 280/482] Rework some weapon additions --- worlds/stardew_valley/data/locations.csv | 6 +++--- worlds/stardew_valley/items.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index bc579a466b0a..243ea7d13e52 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2553,9 +2553,9 @@ id,region,name,tags,mod_name 7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7651,Alesia Shop,Purchase Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7652,Issac Shop,Purchase Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7653,Issac Shop,Purchase Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7652,Issac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Issac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded 7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded 7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 80cba1fef1b1..ceed18d108f9 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -235,12 +235,16 @@ def create_weapons(item_factory: StardewItemFactory, options: StardewValleyOptio monstersanity = options.monstersanity if monstersanity == Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons items.extend(item_factory(item) for item in [APWeapon.weapon] * 5) + if ModNames.sve in options.mods: + items.append(APWeapon.weapon) items.extend(item_factory(item) for item in [APWeapon.footwear] * 3) # 1-2 | 3-4 | 6-7-8 return items.extend(item_factory(item) for item in [APWeapon.sword] * 5) items.extend(item_factory(item) for item in [APWeapon.club] * 5) items.extend(item_factory(item) for item in [APWeapon.dagger] * 5) + if ModNames.sve in options.mods: + items.extend(item_factory(item) for item in [APWeapon.sword, APWeapon.club, APWeapon.dagger]) items.extend(item_factory(item) for item in [APWeapon.footwear] * 4) # 1-2 | 3-4 | 6-7-8 | 11-13 if monstersanity == Monstersanity.option_goals or monstersanity == Monstersanity.option_one_per_category or \ monstersanity == Monstersanity.option_short_goals or monstersanity == Monstersanity.option_very_short_goals: From 3b9fc74051c08b8d45f57b36b72a52d6085b0fd7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 29 Nov 2023 21:43:15 -0600 Subject: [PATCH 281/482] Fix rules with names --- worlds/stardew_valley/data/craftable_data.py | 2 +- worlds/stardew_valley/data/locations.csv | 6 +++--- .../stardew_valley/mods/logic/item_logic.py | 2 +- worlds/stardew_valley/mods/logic/sve_logic.py | 19 ++++++----------- worlds/stardew_valley/mods/mod_regions.py | 6 +++--- worlds/stardew_valley/rules.py | 4 ++-- .../strings/ap_names/mods/mod_items.py | 21 +++++++++++++++++++ .../stardew_valley/strings/entrance_names.py | 2 +- worlds/stardew_valley/strings/region_names.py | 2 +- 9 files changed, 39 insertions(+), 25 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 4bce46432ec8..b3016c6eeb4f 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -276,7 +276,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, ModNames.archaeology) haste_elixir = shop_recipe(ModEdible.haste_elixir, SVERegion.alesia_shop, 35000, {Loot.void_essence: 35, SVEForage.void_soul: 5, Ingredient.sugar: 1, Meal.spicy_eel: 1}, ModNames.sve) -hero_elixir = shop_recipe(ModEdible.hero_elixir, SVERegion.issac_shop, 65000, {SVEForage.void_pebble: 3, SVEForage.void_soul: 5, Ingredient.oil: 1, +hero_elixir = shop_recipe(ModEdible.hero_elixir, SVERegion.isaac_shop, 65000, {SVEForage.void_pebble: 3, SVEForage.void_soul: 5, Ingredient.oil: 1, Loot.slime: 10}, ModNames.sve) armor_elixir = shop_recipe(ModEdible.armor_elixir, SVERegion.alesia_shop, 50000, {Loot.solar_essence: 30, SVEForage.void_soul: 5, Ingredient.vinegar: 5, Fossil.bone_fragment: 5}, ModNames.sve) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 243ea7d13e52..39732a03533a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2502,7 +2502,7 @@ id,region,name,tags,mod_name 7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7454,Issac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology 7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology @@ -2554,8 +2554,8 @@ id,region,name,tags,mod_name 7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7652,Issac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7653,Issac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded 7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded 7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index ac66633bcd7e..a90136b4b991 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -89,7 +89,7 @@ def get_sve_item_rules(self): "Galdoran Gem": self.logic.museum.can_complete_museum() & self.logic.relationship.has_hearts(ModNPC.marlon, 8), SVEForage.golden_ocean_flower: self.logic.region.can_reach(SVERegion.fable_reef), SVEMeal.grampleton_orange_chicken: self.logic.money.can_spend_at(Region.saloon, 650) & self.logic.relationship.has_hearts(ModNPC.sophia, 6), - ModEdible.hero_elixir: self.logic.money.can_spend_at(SVERegion.issac_shop, 8000), + ModEdible.hero_elixir: self.logic.money.can_spend_at(SVERegion.isaac_shop, 8000), SVEForage.lucky_four_leaf_clover: self.logic.region.can_reach_any((Region.secret_woods, SVERegion.forest_west)) & self.logic.season.has_any([Season.spring, Season.summer]), SVEForage.mushroom_colony: self.logic.region.can_reach_any((Region.secret_woods, SVERegion.junimo_woods, SVERegion.forest_west)) & diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index e4bb721d5380..5c00d0218de9 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -14,6 +14,7 @@ from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin +from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes from ...strings.food_names import SVEMeal from ...strings.villager_names import NPC, ModNPC from ...stardew_rule import Or, True_ @@ -29,22 +30,14 @@ class SVELogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, QuestLogicMixi FishingLogicMixin, CookingLogicMixin, MoneyLogicMixin, CombatLogicMixin, SeasonLogicMixin]]): def initialize_rules(self): self.registry.sve_location_rules.update({ - "Alesia: Tempered Galaxy Dagger": self.logic.region.can_reach( - SVERegion.alesia_shop) & self.logic.combat.has_galaxy_weapon() & - self.logic.money.can_spend(350000) & self.logic.time.has_lived_months(3), - "Issac: Tempered Galaxy Sword": self.logic.region.can_reach( - SVERegion.issac_shop) & self.logic.combat.has_galaxy_weapon() & - self.logic.money.can_spend(600000), - "Issac: Tempered Galaxy Hammer": self.logic.region.can_reach( - SVERegion.issac_shop) & self.logic.combat.has_galaxy_weapon() & - self.logic.money.can_spend(400000), - "Lance's Diamond Wand": self.logic.quest.can_complete_quest("Monster Crops") & self.logic.region.can_reach( - SVERegion.lances_house), + SVELocation.tempered_galaxy_sword: self.logic.money.can_spend_at(SVERegion.alesia_shop, 350000), + SVELocation.tempered_galaxy_dagger: self.logic.money.can_spend_at(SVERegion.isaac_shop, 600000), + SVELocation.tempered_galaxy_hammer: self.logic.money.can_spend_at(SVERegion.isaac_shop, 400000), + SVELocation.diamond_wand: self.logic.quest.can_complete_quest(SVELocation.monster_crops) & self.logic.region.can_reach(SVERegion.lances_house), }) def has_any_rune(self): - rune_list = ["Nexus: Adventurer's Guild Runes", "Nexus: Junimo Woods Runes", "Nexus: Aurora Vineyard Runes", "Nexus: Sprite Spring Runes", - "Nexus: Outpost Runes", "Nexus: Farm Runes", "Nexus: Wizard Runes"] + rune_list = SVERunes.nexus_items return Or(*(self.logic.received(rune) for rune in rune_list)) def append_sve_recipe_rules(self, recipe: str): diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 03d736157ac3..05f03986516c 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -144,7 +144,7 @@ RegionData(SVERegion.grove_outpost_warp, [SVEEntrance.outpost_warp_to_outpost]), RegionData(SVERegion.grove_wizard_warp, [SVEEntrance.wizard_warp_to_wizard]), RegionData(SVERegion.galmoran_outpost, [SVEEntrance.outpost_to_badlands_entrance, SVEEntrance.use_alesia_shop, - SVEEntrance.use_issac_shop]), + SVEEntrance.use_isaac_shop]), RegionData(SVERegion.badlands_entrance, [SVEEntrance.badlands_entrance_to_badlands]), RegionData(SVERegion.crimson_badlands, [SVEEntrance.badlands_to_cave]), RegionData(SVERegion.badlands_cave), @@ -194,7 +194,7 @@ RegionData(SVERegion.purple_junimo_shop), RegionData(SVERegion.alesia_shop), - RegionData(SVERegion.issac_shop), + RegionData(SVERegion.isaac_shop), RegionData(SVERegion.summit), RegionData(SVERegion.susans_house), RegionData(Region.mountain, [Entrance.mountain_to_adventurer_guild, Entrance.mountain_to_the_mines], ModificationFlag.MODIFIED) @@ -258,7 +258,7 @@ ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop), - ConnectionData(SVEEntrance.use_issac_shop, SVERegion.issac_shop), + ConnectionData(SVEEntrance.use_isaac_shop, SVERegion.isaac_shop), ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.railroad_to_grampleton_station, SVERegion.grampleton_station), ConnectionData(SVEEntrance.grampleton_station_to_grampleton_suburbs, SVERegion.grampleton_suburbs), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 96b62dd6f7a6..cfae137a6dfa 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -820,7 +820,7 @@ def set_friendsanity_rules(all_location_names: List[str], logic: StardewLogic, m def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.deepwoods in world_options.mods: MultiWorldRules.add_rule(multiworld.get_location("Breaking Up Deep Woods Gingerbread House", player), - logic.tool.has_tool(Tool.axe, "Gold") & logic.mod.deepwoods.can_reach_woods_depth(50)) + logic.tool.has_tool(Tool.axe, "Gold")) MultiWorldRules.add_rule(multiworld.get_location("Chop Down a Deep Woods Iridium Tree", player), logic.tool.has_tool(Tool.axe, "Iridium")) MultiWorldRules.set_rule(multiworld.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), @@ -829,7 +829,7 @@ def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), logic.mod.deepwoods.can_chop_to_depth(depth)) MultiWorldRules.add_rule(multiworld.get_location("The Sword in the Stone", player), - logic.mod.deepwoods.can_pull_sword()) + logic.mod.deepwoods.can_pull_sword() & logic.mod.deepwoods.can_chop_to_depth(100)) def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 1a16c4ab9267..ed7c991295b7 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -14,3 +14,24 @@ class SVEQuestItem: sve_quest_items: List[str] = [aurora_vineyard_tablet, iridium_bomb, void_soul, kittyfish_spell, scarlett_job_offer, morgan_schooling] sve_quest_items_ginger_island: List[str] = [diamond_wand, marlon_boat_paddle, fable_reef_portal] + + +class SVELocation: + tempered_galaxy_sword = "Tempered Galaxy Sword" + tempered_galaxy_hammer = "Tempered Galaxy Hammer" + tempered_galaxy_dagger = "Tempered Galaxy Dagger" + diamond_wand = "Lance's Diamond Wand" + monster_crops = "Monster Crops" + + +class SVERunes: + nexus_guild = "Nexus: Adventurer's Guild Runes" + nexus_junimo = "Nexus: Junimo Woods Runes" + nexus_aurora = "Nexus: Aurora Vineyard Runes" + nexus_spring = "Nexus: Sprite Spring Runes" + nexus_outpost = "Nexus: Outpost Runes" + nexus_farm = "Nexus: Farm Runes" + nexus_wizard = "Nexus: Wizard Runes" + + nexus_items: List[str] = [nexus_wizard, nexus_farm, nexus_outpost, nexus_spring, nexus_aurora, nexus_guild, nexus_junimo] + diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index cb41c13ed3cb..0e5abe3d5c76 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -302,7 +302,7 @@ class SVEEntrance: to_aurora_basement = "Aurora Vineyard to Aurora Vineyard Basement" outpost_to_badlands_entrance = "Galmoran Outpost to Badlands Entrance" use_alesia_shop = "Talk to Alesia" - use_issac_shop = "Talk to Issac" + use_isaac_shop = "Talk to Isaac" badlands_entrance_to_badlands = "Badlands Entrance to Crimson Badlands" badlands_to_cave = "Crimson Badlands to Badlands Cave" to_susan_house = "Railroad to Susan's House" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 9674f0879e55..6f5ff0ee3d6d 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -258,7 +258,7 @@ class SVERegion: badlands_entrance = "Badlands Entrance" crimson_badlands = "Crimson Badlands" alesia_shop = "Alesia Shop" - issac_shop = "Issac Shop" + isaac_shop = "Isaac Shop" summit = "Summit" susans_house = "Susan's House" marlon_boat = "Marlon's Boat" From 5748c3c2bbb98959992ca5f826a3a27e046b7d4b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 30 Nov 2023 11:09:13 -0600 Subject: [PATCH 282/482] Add Cropsanity locations --- worlds/stardew_valley/data/locations.csv | 6 ++++++ worlds/stardew_valley/locations.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 39732a03533a..6f6639582c0e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2584,6 +2584,12 @@ id,region,name,tags,mod_name 7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded 7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded 7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded +7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded +7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic 8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic 8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index b5866f4af504..b668d3f73d8b 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -169,7 +169,7 @@ def extend_cropsanity_locations(randomized_locations: List[LocationData], option if options.cropsanity == Cropsanity.option_disabled: return - cropsanity_locations = locations_by_tag[LocationTags.CROPSANITY] + cropsanity_locations = [item for item in locations_by_tag[LocationTags.CROPSANITY] if item.mod_name in options.mods or not item.mod_name] cropsanity_locations = filter_ginger_island(options, cropsanity_locations) randomized_locations.extend(cropsanity_locations) From 59b0f47e840720fb4869d545c551f59d48c04df7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 30 Nov 2023 11:21:02 -0600 Subject: [PATCH 283/482] Remove Learned Craftsanity Locations --- worlds/stardew_valley/data/items.csv | 12 ---------- worlds/stardew_valley/data/locations.csv | 24 -------------------- worlds/stardew_valley/test/TestGeneration.py | 2 +- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 4cb937cf3027..9941fd3fe601 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -815,16 +815,4 @@ id,name,classification,groups,mod_name 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10606,Glass Bazier Recipe,progression,CRAFTSANITY,Archaeology -10607,Glass Path Recipe,progression,CRAFTSANITY,Archaeology -10608,Glass Fence Recipe,progression,CRAFTSANITY,Archaeology -10609,Bone Path Recipe,progression,CRAFTSANITY,Archaeology -10610,Water Shifter Recipe,progression,CRAFTSANITY,Archaeology -10611,Wooden Display Recipe,progression,CRAFTSANITY,Archaeology -10612,Hardwood Display Recipe,progression,CRAFTSANITY,Archaeology -10613,Dwarf Gadget: Infinite Volcano Simulation Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Archaeology -10614,Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology -10615,hardwood Preservation Chamber Recipe,progression,CRAFTSANITY,Archaeology -10616,Grinder Recipe,progression,CRAFTSANITY,Archaeology -10617,Ancient Battery Production Station Recipe,progression,CRAFTSANITY,Archaeology diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 6f6639582c0e..d3b615291f1b 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2487,35 +2487,11 @@ id,region,name,tags,mod_name 7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded 7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded 7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded -7406,Farm,Craft Glass Path,CRAFTSANITY,Archaeology -7407,Farm,Craft Bone Path,CRAFTSANITY,Archaeology -7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology -7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology -7410,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology -7411,Farm,Craft Grinder,CRAFTSANITY,Archaeology -7412,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology -7413,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology -7414,Farm,Craft hardwood Preservation Chamber,CRAFTSANITY,Archaeology -7415,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology -7416,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology -7417,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology 7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7456,Farm,Glass Path Recipe,CRAFTSANITY,Archaeology -7457,Farm,Bone Path Recipe,CRAFTSANITY,Archaeology -7458,Farm,Glass Bazier Recipe,CRAFTSANITY,Archaeology -7459,Farm,Glass Fence Recipe,CRAFTSANITY,Archaeology -7460,Farm,Water Shifter Recipe,CRAFTSANITY,Archaeology -7461,Farm,Grinder Recipe,CRAFTSANITY,Archaeology -7462,Farm,Ancient Battery Production Station Recipe,CRAFTSANITY,Archaeology -7463,Farm,Preservation Chamber Recipe,CRAFTSANITY,Archaeology -7464,Farm,hardwood Preservation Chamber Recipe,CRAFTSANITY,Archaeology -7465,Farm,Wooden Display Recipe,CRAFTSANITY,Archaeology -7466,Farm,Hardwood Display Recipe,CRAFTSANITY,Archaeology -7467,Farm,Dwarf Gadget: Infinite Volcano Simulation Recipe,"CRAFTSANITY,GINGER_ISLAND",Archaeology 7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index aa6bbe03663c..07a071809e5b 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -396,7 +396,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2652 + expected_locations = 2640 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) From cffdff33d870ba235811577d8721df6b6887b441 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 30 Nov 2023 16:46:00 -0600 Subject: [PATCH 284/482] Add Alecto & Distant Lands --- worlds/stardew_valley/data/craftable_data.py | 10 ++-- worlds/stardew_valley/data/fish_data.py | 6 ++- worlds/stardew_valley/data/items.csv | 8 +++ worlds/stardew_valley/data/locations.csv | 52 +++++++++++++++++++ worlds/stardew_valley/data/recipe_data.py | 24 ++++++--- worlds/stardew_valley/data/villagers_data.py | 8 ++- worlds/stardew_valley/items.py | 11 ++-- worlds/stardew_valley/locations.py | 7 +++ .../stardew_valley/mods/logic/item_logic.py | 36 ++++++++++--- .../stardew_valley/mods/logic/quests_logic.py | 25 +++++++++ worlds/stardew_valley/mods/mod_data.py | 5 +- worlds/stardew_valley/mods/mod_regions.py | 14 ++++- worlds/stardew_valley/options.py | 3 +- .../stardew_valley/strings/craftable_names.py | 1 + worlds/stardew_valley/strings/crop_names.py | 5 ++ .../stardew_valley/strings/entrance_names.py | 2 + worlds/stardew_valley/strings/fish_names.py | 6 ++- worlds/stardew_valley/strings/food_names.py | 6 +++ .../strings/forageable_names.py | 4 ++ worlds/stardew_valley/strings/quest_names.py | 7 ++- worlds/stardew_valley/strings/region_names.py | 3 ++ worlds/stardew_valley/strings/seed_names.py | 5 ++ .../stardew_valley/strings/villager_names.py | 2 + .../test/mods/TestModVillagers.py | 4 ++ 24 files changed, 224 insertions(+), 30 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index b3016c6eeb4f..2b48e8a1deb0 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -12,7 +12,7 @@ from ..strings.fish_names import Fish, WaterItem from ..strings.flower_names import Flower from ..strings.food_names import Meal -from ..strings.forageable_names import Forageable, SVEForage +from ..strings.forageable_names import Forageable, SVEForage, DistantLandsForageable from ..strings.ingredient_names import Ingredient from ..strings.machine_names import Machine from ..strings.material_names import Material @@ -22,7 +22,7 @@ from ..strings.seed_names import Seed, TreeSeed from ..strings.skill_names import Skill, ModSkill from ..strings.special_order_names import SpecialOrder -from ..strings.villager_names import NPC +from ..strings.villager_names import NPC, ModNPC class CraftingRecipe: @@ -45,9 +45,9 @@ def __repr__(self): all_crafting_recipes: List[CraftingRecipe] = [] -def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int]) -> CraftingRecipe: +def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe: source = FriendshipSource(friend, hearts) - return create_recipe(name, ingredients, source) + return create_recipe(name, ingredients, source, mod_name) def cutscene_recipe(name: str, region: str, friend: str, hearts: int, ingredients: Dict[str, int]) -> CraftingRecipe: @@ -280,5 +280,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, Loot.slime: 10}, ModNames.sve) armor_elixir = shop_recipe(ModEdible.armor_elixir, SVERegion.alesia_shop, 50000, {Loot.solar_essence: 30, SVEForage.void_soul: 5, Ingredient.vinegar: 5, Fossil.bone_fragment: 5}, ModNames.sve) +ginger_tincture = friendship_recipe(ModConsumable.ginger_tincture, ModNPC.goblin, 4, {DistantLandsForageable.brown_amanita: 1, Forageable.ginger: 5, + Material.cinder_shard: 1, DistantLandsForageable.swamp_herb: 1}, ModNames.distant_lands) all_crafting_recipes_by_name = {recipe.item: recipe for recipe in all_crafting_recipes} diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 2925fd8d3114..06cc7cdcb235 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -2,7 +2,7 @@ from typing import List, Tuple, Union, Optional, Set from . import season_data as season -from ..strings.fish_names import Fish, SVEFish +from ..strings.fish_names import Fish, SVEFish, DistantLandsFish from ..strings.region_names import Region, SVERegion from ..mods.mod_data import ModNames @@ -157,6 +157,10 @@ def create_fish(name: str, locations: Tuple[str, ...], seasons: Union[str, Tuple sea_sponge = create_fish(SVEFish.sea_sponge, ginger_island_ocean, season.all_seasons, 40, mod_name=ModNames.sve) dulse_seaweed = create_fish(SVEFish.dulse_seaweed, vineyard, season.all_seasons, 50, mod_name=ModNames.sve) +void_minnow = create_fish(DistantLandsFish.void_minnow, witch_swamp, season.all_seasons, 15, mod_name=ModNames.distant_lands) +swamp_leech = create_fish(DistantLandsFish.swamp_leech, witch_swamp, season.all_seasons, 15, mod_name=ModNames.distant_lands) +giant_horsehoe_crab = create_fish(DistantLandsFish.giant_horsehoe_crab, witch_swamp, season.all_seasons, 90, mod_name=ModNames.distant_lands) + clam = create_fish("Clam", ocean, season.all_seasons, -1) cockle = create_fish("Cockle", ocean, season.all_seasons, -1) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 9941fd3fe601..e05a51f717ba 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -778,6 +778,8 @@ id,name,classification,groups,mod_name 10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded 10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch (New NPC) +10127,Goblin <3,progression,FRIENDSANITY,Distant Lands 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator 10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded @@ -790,6 +792,12 @@ id,name,classification,groups,mod_name 10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands +10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded 10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10503,Iridium Bomb,progression,,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index d3b615291f1b..c8776deea650 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2454,6 +2454,26 @@ id,region,name,tags,mod_name 6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded 6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded 6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded +6303,Witch's Swamp,Friendsanity: Goblin 1 <3,FRIENDSANITY,Distant Lands +6304,Witch's Swamp,Friendsanity: Goblin 2 <3,FRIENDSANITY,Distant Lands +6305,Witch's Swamp,Friendsanity: Goblin 3 <3,FRIENDSANITY,Distant Lands +6306,Witch's Swamp,Friendsanity: Goblin 4 <3,FRIENDSANITY,Distant Lands +6307,Witch's Swamp,Friendsanity: Goblin 5 <3,FRIENDSANITY,Distant Lands +6308,Witch's Swamp,Friendsanity: Goblin 6 <3,FRIENDSANITY,Distant Lands +6309,Witch's Swamp,Friendsanity: Goblin 7 <3,FRIENDSANITY,Distant Lands +6310,Witch's Swamp,Friendsanity: Goblin 8 <3,FRIENDSANITY,Distant Lands +6311,Witch's Swamp,Friendsanity: Goblin 9 <3,FRIENDSANITY,Distant Lands +6312,Witch's Swamp,Friendsanity: Goblin 10 <3,FRIENDSANITY,Distant Lands +6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch (New NPC) 7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack 7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod 7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods @@ -2509,6 +2529,10 @@ id,region,name,tags,mod_name 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded 7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7519,Witch's Swamp,Corrupted Crops Task,,Distant Lands +7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands +7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands +7522,Witch's Swamp,Witch's order,,Distant Lands 7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded @@ -2519,6 +2543,10 @@ id,region,name,tags,mod_name 7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded 7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded 7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded +7561,Kitchen,Cook Mushroom Kebab,"COOKSANITY",Distant Lands +7562,Kitchen,Cook Crayfish Soup,"COOKSANITY",Distant Lands +7563,Kitchen,Cook Pemmican,"COOKSANITY",Distant Lands +7564,Kitchen,Cook Void Mint Tea,"COOKSANITY",Distant Lands 7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded @@ -2529,6 +2557,10 @@ id,region,name,tags,mod_name 7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands 7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded 7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded @@ -2560,12 +2592,17 @@ id,region,name,tags,mod_name 7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded 7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded 7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands +7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands +7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands 7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded 7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded 7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands +7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands 8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic 8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic 8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded @@ -2759,3 +2796,18 @@ id,region,name,tags,mod_name 8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology 8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology 8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology +8203,Shipping,Shipsanity: Brown Amanita,SHIPSANITY,Distant Lands +8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands +8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands +8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands +8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands +8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands +8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands +8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands +8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands +8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands +8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands +8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands +8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands +8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands +8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 4bcd669d5a85..5e8d16b6a355 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -3,18 +3,19 @@ from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood -from ..strings.crop_names import Fruit, Vegetable, SVEFruit -from ..strings.fish_names import Fish, SVEFish, WaterItem +from ..strings.crop_names import Fruit, Vegetable, SVEFruit, DistantLandsCrop +from ..strings.fish_names import Fish, SVEFish, WaterItem, DistantLandsFish from ..strings.flower_names import Flower -from ..strings.forageable_names import Forageable, SVEForage +from ..strings.forageable_names import Forageable, SVEForage, DistantLandsForageable from ..strings.ingredient_names import Ingredient -from ..strings.food_names import Meal, SVEMeal, Beverage +from ..strings.food_names import Meal, SVEMeal, Beverage, DistantLandsMeal +from ..strings.material_names import Material from ..strings.metal_names import Fossil from ..strings.monster_drop_names import Loot from ..strings.region_names import Region, SVERegion from ..strings.season_names import Season from ..strings.skill_names import Skill -from ..strings.villager_names import NPC +from ..strings.villager_names import NPC, ModNPC class CookingRecipe: @@ -37,9 +38,9 @@ def __repr__(self): all_cooking_recipes: List[CookingRecipe] = [] -def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int]) -> CookingRecipe: +def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe: source = FriendshipSource(friend, hearts) - return create_recipe(name, ingredients, source) + return create_recipe(name, ingredients, source, mod_name) def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int]) -> CookingRecipe: @@ -187,4 +188,13 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, void_salmon_sushi = shop_recipe(SVEMeal.void_salmon_sushi, Region.sewer, 5000, {Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, ModNames.sve) +mushroom_kebab = friendship_recipe(DistantLandsMeal.mushroom_kebab, ModNPC.goblin, 2, {Forageable.chanterelle: 1, Forageable.common_mushroom: 1, + Forageable.red_mushroom: 1, Material.wood: 1}, ModNames.distant_lands) +void_mint_tea = friendship_recipe(DistantLandsMeal.void_mint_tea, ModNPC.goblin, 4, {DistantLandsCrop.void_mint: 1}, ModNames.distant_lands) +crayfish_soup = friendship_recipe(DistantLandsMeal.crayfish_soup, ModNPC.goblin, 6, {Forageable.cave_carrot: 1, Fish.crayfish: 1, + DistantLandsFish.purple_algae: 1, WaterItem.white_algae: 1}, ModNames.distant_lands) +pemmican = friendship_recipe(DistantLandsMeal.pemmican, ModNPC.goblin, 8, {Loot.bug_meat: 1, Fish.any: 1, Forageable.salmonberry: 3, + Material.stone: 2}, ModNames.distant_lands) + + all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} \ No newline at end of file diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 7d2299be281b..bd83f05832dd 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -2,7 +2,7 @@ from typing import List, Tuple, Optional, Dict, Callable, Set from ..strings.food_names import Beverage -from ..strings.region_names import Region, SVERegion +from ..strings.region_names import Region, SVERegion, AlectoRegion from ..mods.mod_data import ModNames from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC @@ -53,6 +53,10 @@ def __repr__(self): railroad = (Region.railroad,) junimo = (SVERegion.junimo_woods,) +# Witch Swamp Overhaul Location +witch_swamp = (Region.witch_swamp,) +witch_attic = (AlectoRegion.witch_attic,) + golden_pumpkin = ("Golden Pumpkin",) # magic_rock_candy = ("Magic Rock Candy",) pearl = ("Pearl",) @@ -417,6 +421,8 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu wellwick = villager(ModNPC.wellwick, True, forest, Season.winter, universal_loves + wellwick_loves, True, ModNames.shiko) yoba = villager(ModNPC.yoba, False, secret_woods, Season.spring, universal_loves + yoba_loves, False, ModNames.yoba) riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley) +zic = villager(ModNPC.goblin, False, witch_swamp, Season.fall, void_mayonnaise, False, ModNames.distant_lands) +alecto = villager(ModNPC.alecto, False, witch_attic, Season.fall, universal_loves, False, ModNames.alecto) # SVE Villagers claire = villager(ModNPC.claire, True, town + jojamart, Season.fall, universal_loves + claire_loves, True, ModNames.sve) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index ceed18d108f9..aeb7124f27c6 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -461,8 +461,9 @@ def create_seeds(item_factory: StardewItemFactory, options: StardewValleyOptions if options.cropsanity == Cropsanity.option_disabled: return - include_ginger_island = options.exclude_ginger_island != ExcludeGingerIsland.option_true - seed_items = [item_factory(item) for item in items_by_group[Group.CROPSANITY] if include_ginger_island or Group.GINGER_ISLAND not in item.groups] + base_seed_items = [item for item in items_by_group[Group.CROPSANITY]] + filtered_seed_items = remove_excluded_items(base_seed_items, options) + seed_items = [item_factory(item) for item in filtered_seed_items] items.extend(seed_items) @@ -658,8 +659,8 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options return items -def filter_deprecated_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: - return [item for item in items if Group.DEPRECATED not in item.groups] +def filter_deprecated_items(items: List[ItemData]) -> List[ItemData]: + return [item for item in items if Group.DEPRECATED not in item.groups] def filter_ginger_island_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: @@ -672,7 +673,7 @@ def filter_mod_items(options: StardewValleyOptions, items: List[ItemData]) -> Li def remove_excluded_items(items, options): - deprecated_filter = filter_deprecated_items(options, items) + deprecated_filter = filter_deprecated_items(items) ginger_island_filter = filter_ginger_island_items(options, deprecated_filter) mod_filter = filter_mod_items(options, ginger_island_filter) return mod_filter diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index b668d3f73d8b..aae45ae2af24 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -10,8 +10,10 @@ from .data.fish_data import legendary_fish, special_fish, get_fish_for_mods from .data.museum_data import all_museum_items from .data.villagers_data import get_villagers_for_mods +from .mods.mod_data import ModNames from .options import ExcludeGingerIsland, Friendsanity, ArcadeMachineLocations, SpecialOrderLocations, Cropsanity, Fishsanity, Museumsanity, FestivalLocations, SkillProgression, BuildingProgression, ToolProgression, ElevatorProgression, BackpackProgression from .strings.goal_names import Goal +from .strings.quest_names import ModQuest from .strings.villager_names import NPC, ModNPC from .strings.region_names import Region @@ -311,6 +313,11 @@ def extend_walnut_purchase_locations(randomized_locations: List[LocationData], o def extend_mandatory_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): mandatory_locations = [location for location in locations_by_tag[LocationTags.MANDATORY]] + if ModNames.distant_lands in options.mods: + if ModNames.alecto in options.mods: + mandatory_locations.append(location_table[ModQuest.WitchOrder]) + else: + mandatory_locations.append(location_table[ModQuest.CorruptedCropsTask]) filtered_mandatory_locations = filter_disabled_locations(options, mandatory_locations) randomized_locations.extend(filtered_mandatory_locations) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index a90136b4b991..d922306fb3e6 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -7,6 +7,7 @@ from ...logic.cooking_logic import CookingLogicMixin from ...logic.crafting_logic import CraftingLogicMixin from ...logic.crop_logic import CropLogicMixin +from ...logic.fishing_logic import FishingLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin from ...logic.museum_logic import MuseumLogicMixin @@ -15,17 +16,19 @@ from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.tool_logic import ToolLogicMixin -from ...stardew_rule import StardewRule +from ...options import Cropsanity +from ...stardew_rule import StardewRule, True_ from ...strings.craftable_names import ModCraftable, ModEdible, ModMachine -from ...strings.crop_names import SVEVegetable, SVEFruit +from ...strings.crop_names import SVEVegetable, SVEFruit, DistantLandsCrop +from ...strings.fish_names import DistantLandsFish from ...strings.food_names import SVEMeal, SVEBeverage -from ...strings.forageable_names import SVEForage +from ...strings.forageable_names import SVEForage, DistantLandsForageable from ...strings.gift_names import SVEGift from ...strings.metal_names import all_fossils, all_artifacts from ...strings.monster_drop_names import ModLoot from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season -from ...strings.seed_names import SVESeed +from ...strings.seed_names import SVESeed, DistantLandsSeed from ...strings.tool_names import Tool, ToolMaterial from ...strings.villager_names import ModNPC @@ -39,8 +42,8 @@ def __init__(self, *args, **kwargs): self.item = ModItemLogic(*args, **kwargs) -class ModItemLogic(BaseLogic[Union[CombatLogicMixin, ReceivedLogicMixin, CropLogicMixin, CookingLogicMixin, HasLogicMixin, MoneyLogicMixin, RegionLogicMixin, -SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin]]): +class ModItemLogic(BaseLogic[Union[CombatLogicMixin, ReceivedLogicMixin, CropLogicMixin, CookingLogicMixin, FishingLogicMixin, HasLogicMixin, MoneyLogicMixin, +RegionLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin]]): def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() @@ -48,6 +51,8 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: items.update(self.get_sve_item_rules()) if ModNames.archaeology in self.options.mods: items.update(self.get_archaeology_item_rules()) + if ModNames.distant_lands in self.options.mods: + items.update(self.get_distant_lands_item_rules()) return items def get_sve_item_rules(self): @@ -117,3 +122,22 @@ def get_archaeology_item_rules(self): else: archaeology_item_rules[location_name] = display_item_rule & hardwood_preservation_chamber_rule return archaeology_item_rules + + def get_distant_lands_item_rules(self): + return{ + DistantLandsForageable.swamp_herb: self.logic.region.can_reach(Region.witch_swamp), + DistantLandsForageable.brown_amanita: self.logic.region.can_reach(Region.witch_swamp), + DistantLandsFish.purple_algae: self.logic.fishing.can_fish_at(Region.witch_swamp), + DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.pseudo_cropsanity_check(DistantLandsSeed.vile_ancient_fruit), + DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.pseudo_cropsanity_check(DistantLandsSeed.void_mint), + DistantLandsCrop.void_mint: self.logic.has(DistantLandsSeed.void_mint), + DistantLandsCrop.vile_ancient_fruit: self.logic.has(DistantLandsSeed.vile_ancient_fruit) + } + + # Items that don't behave enough like a crop but enough to warrant a portion of the cropsanity logic. + def pseudo_cropsanity_check(self, seed_name: str): + if self.options.cropsanity == Cropsanity.option_disabled: + item_rule = True_() + else: + item_rule = self.logic.received(seed_name) + return item_rule diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 34733f825aeb..4f8881ed4599 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -9,8 +9,10 @@ from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin from ...stardew_rule import StardewRule +from ...strings.animal_product_names import AnimalProduct from ...strings.artisan_good_names import ArtisanGood from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable +from ...strings.fertilizer_names import Fertilizer from ...strings.food_names import Meal, Beverage from ...strings.forageable_names import SVEForage from ...strings.material_names import Material @@ -36,6 +38,7 @@ def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests.update(self._get_mr_ginger_quest_rules()) quests.update(self._get_ayeisha_quest_rules()) quests.update(self._get_sve_quest_rules()) + quests.update(self._get_distant_lands_quest_rules()) return quests def _get_juna_quest_rules(self): @@ -79,3 +82,25 @@ def _get_sve_quest_rules(self): ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul), } + + def _get_distant_lands_quest_rules(self): + if ModNames.distant_lands not in self.options.mods: + return {} + + rules = { + ModQuest.ANewPot: self.logic.region.can_reach(Region.witch_swamp) & self.logic.region.can_reach(Region.saloon) & + self.logic.region.can_reach(Region.sam_house) & self.logic.region.can_reach(Region.pierre_store) & + self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron), + ModQuest.FancyBlanketTask: self.logic.region.can_reach(Region.witch_swamp) & self.logic.region.can_reach(Region.haley_house) & self.logic.has(AnimalProduct.wool) & + self.logic.has(ArtisanGood.cloth) + + } + if ModNames.alecto not in self.options.mods: + rules.update({ + ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.quality), + }) + return rules + rules.update({ + ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.quality), + }) + return rules diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index 25f5cb60071d..6869562415d7 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -22,6 +22,8 @@ class ModNames: riley = "Custom NPC - Riley" skull_cavern_elevator = "Skull Cavern Elevator" sve = "Stardew Valley Expanded" + alecto = "Alecto the Witch (New NPC)" + distant_lands = "Distant Lands" all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, @@ -29,4 +31,5 @@ class ModNames: ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve}) + ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.alecto, + ModNames.distant_lands}) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 05f03986516c..6aeb8fe7ef4a 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -1,7 +1,7 @@ from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, \ - JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance + JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance, AlectoEntrance from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, \ - AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion + AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion, AlectoRegion from ..region_classes import RegionData, ConnectionData, ModificationFlag, RandomizationFlag, ModRegionData from .mod_data import ModNames @@ -268,6 +268,15 @@ ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS) ] +alecto_regions = [ + RegionData(Region.witch_hut, [AlectoEntrance.witch_hut_to_witch_attic]), + RegionData(AlectoRegion.witch_attic) +] + +alecto_entrances = [ + ConnectionData(AlectoEntrance.witch_hut_to_witch_attic, AlectoRegion.witch_attic, flag=RandomizationFlag.BUILDINGS) +] + vanilla_connections_to_remove_by_mod = { ModNames.sve: [ConnectionData(Entrance.mountain_to_the_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), @@ -287,4 +296,5 @@ ModNames.ayeisha: ModRegionData(ModNames.ayeisha, ayeisha_regions, ayeisha_entrances), ModNames.riley: ModRegionData(ModNames.riley, riley_regions, riley_entrances), ModNames.sve: ModRegionData(ModNames.sve, stardew_valley_expanded_regions, mandatory_sve_connections), + ModNames.alecto: ModRegionData(ModNames.alecto, alecto_regions, alecto_entrances), } diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 7aafed1c7a7b..98ac0247054f 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -651,7 +651,8 @@ class Mods(OptionSet): ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, - ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve + ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.distant_lands, + ModNames.alecto } diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index e70fd9f63197..5ba6dc291038 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -173,5 +173,6 @@ class ModFloor: class ModConsumable: volcano_totem = "Dwarf Gadget: Infinite Volcano Simulation" + ginger_tincture = "Ginger Tincture" diff --git a/worlds/stardew_valley/strings/crop_names.py b/worlds/stardew_valley/strings/crop_names.py index 595d8a867bcc..295e40005f75 100644 --- a/worlds/stardew_valley/strings/crop_names.py +++ b/worlds/stardew_valley/strings/crop_names.py @@ -73,5 +73,10 @@ class SVEVegetable: ancient_fiber = "Ancient Fiber" +class DistantLandsCrop: + void_mint = "Void Mint Leaves" + vile_ancient_fruit = "Vile Ancient Fruit" + + all_vegetables = tuple(all_vegetables) all_fruits = tuple(all_fruits) diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 0e5abe3d5c76..153664fb5bed 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -325,4 +325,6 @@ class SVEEntrance: sprite_spring_to_cave = "Sprite Spring to Sprite Spring Cave" +class AlectoEntrance: + witch_hut_to_witch_attic = "Witch's Hut to Witch's Attic" diff --git a/worlds/stardew_valley/strings/fish_names.py b/worlds/stardew_valley/strings/fish_names.py index 831c6343a06b..cd59d749ee01 100644 --- a/worlds/stardew_valley/strings/fish_names.py +++ b/worlds/stardew_valley/strings/fish_names.py @@ -128,5 +128,9 @@ class SVEFish: dulse_seaweed = "Dulse Seaweed" - +class DistantLandsFish: + void_minnow = "Void Minnow" + swamp_leech = "Swamp Leech" + purple_algae = "Purple Algae" + giant_horsehoe_crab = "Giant Horsehoe Crab" diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index 9294cbebb7d5..07dace7d7d1f 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -105,3 +105,9 @@ class SVEMeal: class SVEBeverage: sports_drink = "Sports Drink" + +class DistantLandsMeal: + mushroom_kebab = "Mushroom Kebab" + crayfish_soup = "Crayfish Soup" + pemmican = "Pemmican" + void_mint_tea = "Void Mint Tea" diff --git a/worlds/stardew_valley/strings/forageable_names.py b/worlds/stardew_valley/strings/forageable_names.py index 3b4c9f7759ee..24127beb9838 100644 --- a/worlds/stardew_valley/strings/forageable_names.py +++ b/worlds/stardew_valley/strings/forageable_names.py @@ -55,3 +55,7 @@ class SVEForage: smelly_rafflesia = "Smelly Rafflesia" thistle = "Thistle" + +class DistantLandsForageable: + brown_amanita = "Brown Amanita" + swamp_herb = "Swamp Herb" diff --git a/worlds/stardew_valley/strings/quest_names.py b/worlds/stardew_valley/strings/quest_names.py index 9431389d51cd..4cc2b48418b0 100644 --- a/worlds/stardew_valley/strings/quest_names.py +++ b/worlds/stardew_valley/strings/quest_names.py @@ -62,4 +62,9 @@ class ModQuest: MarlonsBoat = "Marlon's Boat" AuroraVineyard = "Aurora Vineyard" MonsterCrops = "Monster Crops" - VoidSoul = "Void Soul" \ No newline at end of file + VoidSoul = "Void Soul" + WizardInvite = "Wizard's Invite" + CorruptedCropsTask = "Corrupted Crops Task" + ANewPot = "A New Pot" + FancyBlanketTask = "Fancy Blanket Task" + WitchOrder = "Witch's order" \ No newline at end of file diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 6f5ff0ee3d6d..7a2cfc50a4fe 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -271,3 +271,6 @@ class SVERegion: first_slash_spare_room = "First Slash Spare Room" sprite_spring_cave = "Sprite Spring Cave" + +class AlectoRegion: + witch_attic = "Witch's Attic" diff --git a/worlds/stardew_valley/strings/seed_names.py b/worlds/stardew_valley/strings/seed_names.py index 4abb86e679e4..398b370f2745 100644 --- a/worlds/stardew_valley/strings/seed_names.py +++ b/worlds/stardew_valley/strings/seed_names.py @@ -30,3 +30,8 @@ class SVESeed: void_seed = "Void Seed" shrub_seed = "Shrub Seed" ancient_ferns_seed = "Ancient Ferns Seed" + + +class DistantLandsSeed: + void_mint = "Void Mint Seeds" + vile_ancient_fruit = "Vile Ancient Fruit Seeds" diff --git a/worlds/stardew_valley/strings/villager_names.py b/worlds/stardew_valley/strings/villager_names.py index 61443aa5e138..448065875bf9 100644 --- a/worlds/stardew_valley/strings/villager_names.py +++ b/worlds/stardew_valley/strings/villager_names.py @@ -61,3 +61,5 @@ class ModNPC: morris = "Morris" scarlett = "Scarlett" susan = "Susan" + alecto = "Alecto" + goblin = "Goblin" diff --git a/worlds/stardew_valley/test/mods/TestModVillagers.py b/worlds/stardew_valley/test/mods/TestModVillagers.py index 85fe6d5ce3a3..3be437c3f737 100644 --- a/worlds/stardew_valley/test/mods/TestModVillagers.py +++ b/worlds/stardew_valley/test/mods/TestModVillagers.py @@ -79,6 +79,8 @@ def test_no_mods_no_mod_villagers(self): self.assertNotIn(ModNPC.morris, villager_names) self.assertNotIn(ModNPC.scarlett, villager_names) self.assertNotIn(ModNPC.susan, villager_names) + self.assertNotIn(ModNPC.goblin, villager_names) + self.assertNotIn(ModNPC.alecto, villager_names) def test_sve_has_sve_villagers(self): villagers = get_villagers_for_mods(sve) @@ -114,6 +116,8 @@ def test_sve_has_no_other_mod_villagers(self): self.assertNotIn(ModNPC.shiko, villager_names) self.assertNotIn(ModNPC.wellwick, villager_names) self.assertNotIn(ModNPC.yoba, villager_names) + self.assertNotIn(ModNPC.goblin, villager_names) + self.assertNotIn(ModNPC.alecto, villager_names) def test_no_mods_wizard_is_not_bachelor(self): villagers = get_villagers_for_mods(no_mods) From eac1c5a1d7749605fb25e18f924572a5724fda07 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 1 Dec 2023 21:02:57 -0600 Subject: [PATCH 285/482] Fix SVE entrance name --- worlds/stardew_valley/strings/entrance_names.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 153664fb5bed..221dc6347a85 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -268,8 +268,8 @@ class SVEEntrance: aurora_warp_to_aurora = "Grove Aurora Vineyard Warp to Aurora Vineyard Basement" grove_to_farm_warp = "Enchanted Grove to Grove Farm Warp" farm_warp_to_farm = "Grove Farm Warp to Farm" - grove_to_guild_warp = "Enchanted Grove to Grove Adventurer's Guild Warp" - guild_warp_to_guild = "Grove Adventurer's Guild Warp to Adventurer's Guild Summit" + grove_to_guild_warp = "Enchanted Grove to Grove Guild Warp" + guild_warp_to_guild = "Grove Guild Warp to Guild Summit" grove_to_junimo_warp = "Enchanted Grove to Grove Junimo Woods Warp" junimo_warp_to_junimo = "Grove Junimo Woods Warp to Junimo Woods" grove_to_spring_warp = "Enchanted Grove to Grove Sprite Spring Warp" @@ -294,11 +294,11 @@ class SVEEntrance: bmv_to_beach = "Blue Moon Vineyard to Beach" jenkins_to_cellar = "Jenkins' Residence to Jenkins' Cellar" plot_to_bridge = "Unclaimed Plot to Shearwater Bridge" - mountain_to_guild_summit = "Mountain to Adventurer's Guild Summit" - guild_to_interior = "Adventurer's Guild Summit to Adventurer's Guild" - guild_to_mines = "Adventurer's Guild Summit to The Mines" - summit_to_boat = "Adventurer's Guild Summit to Marlon's Boat" - summit_to_highlands = "Adventurer's Guild Summit to Highlands" + mountain_to_guild_summit = "Mountain to Guild Summit" + guild_to_interior = "Guild Summit to Adventurer's Guild" + guild_to_mines = "Guild Summit to The Mines" + summit_to_boat = "Guild Summit to Marlon's Boat" + summit_to_highlands = "Guild Summit to Highlands" to_aurora_basement = "Aurora Vineyard to Aurora Vineyard Basement" outpost_to_badlands_entrance = "Galmoran Outpost to Badlands Entrance" use_alesia_shop = "Talk to Alesia" From 140a818d573b436fc3544996a16736d857ccd915 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 1 Dec 2023 21:03:23 -0600 Subject: [PATCH 286/482] Fix SVE region name and remove shuffle --- worlds/stardew_valley/mods/mod_regions.py | 2 +- worlds/stardew_valley/strings/region_names.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 6aeb8fe7ef4a..54d9894ca91e 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -226,7 +226,7 @@ ConnectionData(SVEEntrance.aurora_warp_to_aurora, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grove_to_farm_warp, SVERegion.grove_farm_warp), ConnectionData(SVEEntrance.to_aurora_basement, SVERegion.aurora_vineyard_basement, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.farm_warp_to_farm, Region.farm, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.farm_warp_to_farm, Region.farm), ConnectionData(SVEEntrance.grove_to_guild_warp, SVERegion.grove_guild_warp), ConnectionData(SVEEntrance.guild_warp_to_guild, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grove_to_junimo_warp, SVERegion.grove_junimo_warp), diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 7a2cfc50a4fe..89acc85903d2 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -227,7 +227,7 @@ class SVERegion: grove_wizard_warp = "Grove Wizard Warp" grove_farm_warp = "Grove Farm Warp" grove_aurora_warp = "Grove Aurora Vineyard Warp" - grove_guild_warp = "Grove Adventurer's Guild Warp" + grove_guild_warp = "Grove Guild Warp" grove_junimo_warp = "Grove Junimo Woods Warp" grove_spring_warp = "Grove Sprite Spring Warp" marnies_shed = "Marnie's Shed" @@ -238,7 +238,7 @@ class SVERegion: jenkins_cellar = "Jenkins' Cellar" unclaimed_plot = "Unclaimed Plot" shearwater = "Shearwater Bridge" - guild_summit = "Adventurer's Guild Summit" + guild_summit = "Guild Summit" fable_reef = "Fable Reef" first_slash_guild = "First Slash Guild" highlands = "Highlands" From ebc3da073f7b9ada1eba07bdfeb9a06b13eda9d4 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 1 Dec 2023 21:04:04 -0600 Subject: [PATCH 287/482] Fix some DL logic and names --- worlds/stardew_valley/data/items.csv | 17 +-- worlds/stardew_valley/data/locations.csv | 106 +++++++++--------- .../stardew_valley/mods/logic/quests_logic.py | 15 +-- worlds/stardew_valley/mods/mod_data.py | 4 +- 4 files changed, 70 insertions(+), 72 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index e05a51f717ba..eeefbad0e63b 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -778,8 +778,8 @@ id,name,classification,groups,mod_name 10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded 10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded -10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch (New NPC) -10127,Goblin <3,progression,FRIENDSANITY,Distant Lands +10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch +10127,Goblin <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator 10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded @@ -792,12 +792,13 @@ id,name,classification,groups,mod_name 10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands -10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands +10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul +10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded 10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10503,Iridium Bomb,progression,,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c8776deea650..7415474a5288 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2454,26 +2454,26 @@ id,region,name,tags,mod_name 6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded 6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded 6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded -6303,Witch's Swamp,Friendsanity: Goblin 1 <3,FRIENDSANITY,Distant Lands -6304,Witch's Swamp,Friendsanity: Goblin 2 <3,FRIENDSANITY,Distant Lands -6305,Witch's Swamp,Friendsanity: Goblin 3 <3,FRIENDSANITY,Distant Lands -6306,Witch's Swamp,Friendsanity: Goblin 4 <3,FRIENDSANITY,Distant Lands -6307,Witch's Swamp,Friendsanity: Goblin 5 <3,FRIENDSANITY,Distant Lands -6308,Witch's Swamp,Friendsanity: Goblin 6 <3,FRIENDSANITY,Distant Lands -6309,Witch's Swamp,Friendsanity: Goblin 7 <3,FRIENDSANITY,Distant Lands -6310,Witch's Swamp,Friendsanity: Goblin 8 <3,FRIENDSANITY,Distant Lands -6311,Witch's Swamp,Friendsanity: Goblin 9 <3,FRIENDSANITY,Distant Lands -6312,Witch's Swamp,Friendsanity: Goblin 10 <3,FRIENDSANITY,Distant Lands -6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch (New NPC) -6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch (New NPC) +6303,Witch's Swamp,Friendsanity: Goblin 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6304,Witch's Swamp,Friendsanity: Goblin 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6305,Witch's Swamp,Friendsanity: Goblin 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6306,Witch's Swamp,Friendsanity: Goblin 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6307,Witch's Swamp,Friendsanity: Goblin 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6308,Witch's Swamp,Friendsanity: Goblin 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6309,Witch's Swamp,Friendsanity: Goblin 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6310,Witch's Swamp,Friendsanity: Goblin 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6311,Witch's Swamp,Friendsanity: Goblin 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6312,Witch's Swamp,Friendsanity: Goblin 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch +6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch +6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch +6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch +6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch +6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch +6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch +6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch +6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch +6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch 7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack 7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod 7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods @@ -2507,11 +2507,13 @@ id,region,name,tags,mod_name 7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded 7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded 7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul 7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul 7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) @@ -2529,10 +2531,10 @@ id,region,name,tags,mod_name 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded 7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,,Distant Lands -7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands -7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands -7522,Witch's Swamp,Witch's order,,Distant Lands +7519,Witch's Swamp,Corrupted Crops Task,,Distant Lands - Witch Swamp Overhaul +7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul +7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,,Distant Lands - Witch Swamp Overhaul 7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded @@ -2543,10 +2545,10 @@ id,region,name,tags,mod_name 7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded 7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded 7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded -7561,Kitchen,Cook Mushroom Kebab,"COOKSANITY",Distant Lands -7562,Kitchen,Cook Crayfish Soup,"COOKSANITY",Distant Lands -7563,Kitchen,Cook Pemmican,"COOKSANITY",Distant Lands -7564,Kitchen,Cook Void Mint Tea,"COOKSANITY",Distant Lands +7561,Kitchen,Cook Mushroom Kebab,"COOKSANITY",Distant Lands - Witch Swamp Overhaul +7562,Kitchen,Cook Crayfish Soup,"COOKSANITY",Distant Lands - Witch Swamp Overhaul +7563,Kitchen,Cook Pemmican,"COOKSANITY",Distant Lands - Witch Swamp Overhaul +7564,Kitchen,Cook Void Mint Tea,"COOKSANITY",Distant Lands - Witch Swamp Overhaul 7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded @@ -2557,10 +2559,10 @@ id,region,name,tags,mod_name 7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands -7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands +7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded 7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded @@ -2592,17 +2594,17 @@ id,region,name,tags,mod_name 7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded 7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded 7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded -7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands -7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands -7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands +7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul 7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded 7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded 7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands -7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands +7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul +7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul 8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic 8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic 8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded @@ -2796,18 +2798,18 @@ id,region,name,tags,mod_name 8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology 8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology 8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology -8203,Shipping,Shipsanity: Brown Amanita,SHIPSANITY,Distant Lands -8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands -8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands -8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands -8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands -8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands -8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands -8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands -8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands -8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands -8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands -8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands -8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands -8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands -8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands +8203,Shipping,Shipsanity: Brown Amanita,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 4f8881ed4599..97c83092b249 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -87,7 +87,10 @@ def _get_distant_lands_quest_rules(self): if ModNames.distant_lands not in self.options.mods: return {} - rules = { + return{ + ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.region.can_reach(Region.witch_swamp) & + self.logic.has(Fertilizer.quality), + ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.quality), ModQuest.ANewPot: self.logic.region.can_reach(Region.witch_swamp) & self.logic.region.can_reach(Region.saloon) & self.logic.region.can_reach(Region.sam_house) & self.logic.region.can_reach(Region.pierre_store) & self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron), @@ -95,12 +98,4 @@ def _get_distant_lands_quest_rules(self): self.logic.has(ArtisanGood.cloth) } - if ModNames.alecto not in self.options.mods: - rules.update({ - ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.quality), - }) - return rules - rules.update({ - ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.quality), - }) - return rules + diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index 6869562415d7..f5cd26889450 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -22,8 +22,8 @@ class ModNames: riley = "Custom NPC - Riley" skull_cavern_elevator = "Skull Cavern Elevator" sve = "Stardew Valley Expanded" - alecto = "Alecto the Witch (New NPC)" - distant_lands = "Distant Lands" + alecto = "Alecto the Witch" + distant_lands = "Distant Lands - Witch Swamp Overhaul" all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, From b14c6064e29fab550aaa10a43898f6b7edce98fe Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 1 Dec 2023 21:18:49 -0600 Subject: [PATCH 288/482] Fix spacing problem I hope --- worlds/stardew_valley/data/items.csv | 189 ++++---- worlds/stardew_valley/data/locations.csv | 532 +++++++++++------------ 2 files changed, 360 insertions(+), 361 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index eeefbad0e63b..6c93e1bcf108 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -243,7 +243,7 @@ id,name,classification,groups,mod_name 258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", 260,Boat Repair,progression,GINGER_ISLAND, -261,Open Professor Snail Cave,progression,"GINGER_ISLAND", +261,Open Professor Snail Cave,progression,GINGER_ISLAND, 262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", @@ -258,65 +258,65 @@ id,name,classification,groups,mod_name 273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", 274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", 275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", -276,Weather Report,useful,"TV_CHANNEL", -277,Fortune Teller,useful,"TV_CHANNEL", -278,Livin' Off The Land,useful,"TV_CHANNEL", -279,The Queen of Sauce,progression,"TV_CHANNEL", -280,Fishing Information Broadcasting Service,useful,"TV_CHANNEL", -281,Sinister Signal,useful,"TV_CHANNEL", +276,Weather Report,useful,TV_CHANNEL, +277,Fortune Teller,useful,TV_CHANNEL, +278,Livin' Off The Land,useful,TV_CHANNEL, +279,The Queen of Sauce,progression,TV_CHANNEL, +280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, +281,Sinister Signal,useful,TV_CHANNEL, 282,Dark Talisman,progression,, -283,Ostrich Incubator Recipe,progression,"GINGER_ISLAND", -284,Cute Baby,progression,"BABY", -285,Ugly Baby,progression,"BABY", -286,Deluxe Scarecrow Recipe,progression,"RARECROW", -287,Treehouse,progression,"GINGER_ISLAND", +283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, +284,Cute Baby,progression,BABY, +285,Ugly Baby,progression,BABY, +286,Deluxe Scarecrow Recipe,progression,RARECROW, +287,Treehouse,progression,GINGER_ISLAND, 288,Coffee Bean,progression,CROPSANITY, 289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", 290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", 291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", 292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", 293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -294,Progressive Footwear,useful,"FOOTWEAR", -295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE" -308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" -324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE" +294,Progressive Footwear,useful,FOOTWEAR, +295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", 325,Fairy Dust Recipe,progression,, 326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", 327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -328,Deluxe Fertilizer Recipe,progression,"QI_CRAFTING_RECIPE", +328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, 329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", 330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -331,Jack-O-Lantern Recipe,progression,"FESTIVAL", -332,Fiber Seeds Recipe,progression,"SPECIAL_ORDER_BOARD", -333,Tub o' Flowers Recipe,progression,"FESTIVAL", -334,Quality Bobber Recipe,progression,"SPECIAL_ORDER_BOARD", +331,Jack-O-Lantern Recipe,progression,FESTIVAL, +332,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, +333,Tub o' Flowers Recipe,progression,FESTIVAL, +334,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, 335,Moonlight Jellies Banner,filler,FESTIVAL, 336,Starport Decal,filler,FESTIVAL, 337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", @@ -350,7 +350,7 @@ id,name,classification,groups,mod_name 367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -370,Fried Egg Recipe,progression,"CHEFSANITY_STARTER", +370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, 371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", 373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", @@ -400,50 +400,50 @@ id,name,classification,groups,mod_name 417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", 418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", 419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -425,Gate Recipe,progression,"CRAFTSANITY", -426,Wood Fence Recipe,progression,"CRAFTSANITY", +425,Gate Recipe,progression,CRAFTSANITY, +426,Wood Fence Recipe,progression,CRAFTSANITY, 427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -428,Grass Starter Recipe,progression,"CRAFTSANITY", -429,Wood Floor Recipe,progression,"CRAFTSANITY", -430,Rustic Plank Floor Recipe,progression,"CRAFTSANITY", -431,Straw Floor Recipe,progression,"CRAFTSANITY", -432,Weathered Floor Recipe,progression,"CRAFTSANITY", -433,Crystal Floor Recipe,progression,"CRAFTSANITY", -434,Stone Floor Recipe,progression,"CRAFTSANITY", -435,Stone Walkway Floor Recipe,progression,"CRAFTSANITY", -436,Brick Floor Recipe,progression,"CRAFTSANITY", -437,Wood Path Recipe,progression,"CRAFTSANITY", -438,Gravel Path Recipe,progression,"CRAFTSANITY", -439,Cobblestone Path Recipe,progression,"CRAFTSANITY", -440,Stepping Stone Path Recipe,progression,"CRAFTSANITY", -441,Crystal Path Recipe,progression,"CRAFTSANITY", -442,Wedding Ring Recipe,progression,"CRAFTSANITY", -443,Warp Totem: Desert Recipe,progression,"CRAFTSANITY", +428,Grass Starter Recipe,progression,CRAFTSANITY, +429,Wood Floor Recipe,progression,CRAFTSANITY, +430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, +431,Straw Floor Recipe,progression,CRAFTSANITY, +432,Weathered Floor Recipe,progression,CRAFTSANITY, +433,Crystal Floor Recipe,progression,CRAFTSANITY, +434,Stone Floor Recipe,progression,CRAFTSANITY, +435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, +436,Brick Floor Recipe,progression,CRAFTSANITY, +437,Wood Path Recipe,progression,CRAFTSANITY, +438,Gravel Path Recipe,progression,CRAFTSANITY, +439,Cobblestone Path Recipe,progression,CRAFTSANITY, +440,Stepping Stone Path Recipe,progression,CRAFTSANITY, +441,Crystal Path Recipe,progression,CRAFTSANITY, +442,Wedding Ring Recipe,progression,CRAFTSANITY, +443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, 444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -445,Torch Recipe,progression,"CRAFTSANITY", -446,Campfire Recipe,progression,"CRAFTSANITY", -447,Wooden Brazier Recipe,progression,"CRAFTSANITY", -448,Stone Brazier Recipe,progression,"CRAFTSANITY", -449,Gold Brazier Recipe,progression,"CRAFTSANITY", -450,Carved Brazier Recipe,progression,"CRAFTSANITY", -451,Stump Brazier Recipe,progression,"CRAFTSANITY", -452,Barrel Brazier Recipe,progression,"CRAFTSANITY", -453,Skull Brazier Recipe,progression,"CRAFTSANITY", -454,Marble Brazier Recipe,progression,"CRAFTSANITY", -455,Wood Lamp-post Recipe,progression,"CRAFTSANITY", -456,Iron Lamp-post Recipe,progression,"CRAFTSANITY", -457,Furnace Recipe,progression,"CRAFTSANITY", -458,Wicked Statue Recipe,progression,"CRAFTSANITY", -459,Chest Recipe,progression,"CRAFTSANITY", -460,Wood Sign Recipe,progression,"CRAFTSANITY", -461,Stone Sign Recipe,progression,"CRAFTSANITY", -462,Standard Farm,progression,"FARM_TYPE", -463,Riverland Farm,progression,"FARM_TYPE", -464,Forest Farm,progression,"FARM_TYPE", -465,Hill-top Farm,progression,"FARM_TYPE", -466,Wilderness Farm,progression,"FARM_TYPE", -467,Four Corners Farm,progression,"FARM_TYPE", -468,Beach Farm,progression,"FARM_TYPE", +445,Torch Recipe,progression,CRAFTSANITY, +446,Campfire Recipe,progression,CRAFTSANITY, +447,Wooden Brazier Recipe,progression,CRAFTSANITY, +448,Stone Brazier Recipe,progression,CRAFTSANITY, +449,Gold Brazier Recipe,progression,CRAFTSANITY, +450,Carved Brazier Recipe,progression,CRAFTSANITY, +451,Stump Brazier Recipe,progression,CRAFTSANITY, +452,Barrel Brazier Recipe,progression,CRAFTSANITY, +453,Skull Brazier Recipe,progression,CRAFTSANITY, +454,Marble Brazier Recipe,progression,CRAFTSANITY, +455,Wood Lamp-post Recipe,progression,CRAFTSANITY, +456,Iron Lamp-post Recipe,progression,CRAFTSANITY, +457,Furnace Recipe,progression,CRAFTSANITY, +458,Wicked Statue Recipe,progression,CRAFTSANITY, +459,Chest Recipe,progression,CRAFTSANITY, +460,Wood Sign Recipe,progression,CRAFTSANITY, +461,Stone Sign Recipe,progression,CRAFTSANITY, +462,Standard Farm,progression,FARM_TYPE, +463,Riverland Farm,progression,FARM_TYPE, +464,Forest Farm,progression,FARM_TYPE, +465,Hill-top Farm,progression,FARM_TYPE, +466,Wilderness Farm,progression,FARM_TYPE, +467,Four Corners Farm,progression,FARM_TYPE, +468,Beach Farm,progression,FARM_TYPE, 469,Railroad Boulder Removed,progression,, 4001,Burnt,trap,TRAP, 4002,Darkness,trap,TRAP, @@ -717,8 +717,8 @@ id,name,classification,groups,mod_name 5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5262,Slime Incubator,useful,"RESOURCE_PACK", -5263,Slime Egg-Press,useful,"RESOURCE_PACK", +5262,Slime Incubator,useful,RESOURCE_PACK, +5263,Slime Egg-Press,useful,RESOURCE_PACK, 5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill @@ -811,7 +811,7 @@ id,name,classification,groups,mod_name 10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded 10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded 10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded -10513,Fable Reef Portal,progression,"GINGER_ISLAND",Stardew Valley Expanded +10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded 10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded @@ -824,4 +824,3 @@ id,name,classification,groups,mod_name 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded - diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 7415474a5288..ad3b07354345 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -69,7 +69,7 @@ id,region,name,tags,mod_name 75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -80,Vault,"500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +80,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", @@ -81,10 +81,10 @@ id,region,name,tags,mod_name 89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -92,Vault,"Gambler's Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -93,Vault,"Carnival Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -94,Vault,"Walnut Hunter Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -95,Vault,"Qi's Helper Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 101,Pierre's General Store,Large Pack,BACKPACK, 102,Pierre's General Store,Deluxe Pack,BACKPACK, 103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", @@ -289,10 +289,10 @@ id,region,name,tags,mod_name 701,Secret Woods,Old Master Cannoli,MANDATORY, 702,Beach,Beach Bridge Repair,MANDATORY, 703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,"BABY", -705,Farmhouse,Have Another Baby,"BABY", +704,Farmhouse,Have a Baby,BABY, +705,Farmhouse,Have Another Baby,BABY, 706,Farmhouse,Spouse Stardrop,, -707,Sewer,Krobus Stardrop,"MANDATORY", +707,Sewer,Krobus Stardrop,MANDATORY, 801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, 802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, 803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, @@ -832,16 +832,16 @@ id,region,name,tags,mod_name 1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, 1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, 1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,"FRIENDSANITY", -1580,Sewer,Friendsanity: Krobus 2 <3,"FRIENDSANITY", -1581,Sewer,Friendsanity: Krobus 3 <3,"FRIENDSANITY", -1582,Sewer,Friendsanity: Krobus 4 <3,"FRIENDSANITY", -1583,Sewer,Friendsanity: Krobus 5 <3,"FRIENDSANITY", -1584,Sewer,Friendsanity: Krobus 6 <3,"FRIENDSANITY", -1585,Sewer,Friendsanity: Krobus 7 <3,"FRIENDSANITY", -1586,Sewer,Friendsanity: Krobus 8 <3,"FRIENDSANITY", -1587,Sewer,Friendsanity: Krobus 9 <3,"FRIENDSANITY", -1588,Sewer,Friendsanity: Krobus 10 <3,"FRIENDSANITY", +1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, +1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, +1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, +1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, +1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, +1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, +1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, +1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, +1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, +1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, 1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", 1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", 1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", @@ -1050,53 +1050,53 @@ id,region,name,tags,mod_name 2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", 2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, 2216,Field Office,Complete Island Field Office,GINGER_ISLAND, -2301,Farming,Harvest Amaranth,"CROPSANITY", -2302,Farming,Harvest Artichoke,"CROPSANITY", -2303,Farming,Harvest Beet,"CROPSANITY", -2304,Farming,Harvest Blue Jazz,"CROPSANITY", -2305,Farming,Harvest Blueberry,"CROPSANITY", -2306,Farming,Harvest Bok Choy,"CROPSANITY", -2307,Farming,Harvest Cauliflower,"CROPSANITY", -2308,Farming,Harvest Corn,"CROPSANITY", -2309,Farming,Harvest Cranberries,"CROPSANITY", -2310,Farming,Harvest Eggplant,"CROPSANITY", -2311,Farming,Harvest Fairy Rose,"CROPSANITY", -2312,Farming,Harvest Garlic,"CROPSANITY", -2313,Farming,Harvest Grape,"CROPSANITY", -2314,Farming,Harvest Green Bean,"CROPSANITY", -2315,Farming,Harvest Hops,"CROPSANITY", -2316,Farming,Harvest Hot Pepper,"CROPSANITY", -2317,Farming,Harvest Kale,"CROPSANITY", -2318,Farming,Harvest Melon,"CROPSANITY", -2319,Farming,Harvest Parsnip,"CROPSANITY", -2320,Farming,Harvest Poppy,"CROPSANITY", -2321,Farming,Harvest Potato,"CROPSANITY", -2322,Farming,Harvest Pumpkin,"CROPSANITY", -2323,Farming,Harvest Radish,"CROPSANITY", -2324,Farming,Harvest Red Cabbage,"CROPSANITY", -2325,Farming,Harvest Rhubarb,"CROPSANITY", -2326,Farming,Harvest Starfruit,"CROPSANITY", -2327,Farming,Harvest Strawberry,"CROPSANITY", -2328,Farming,Harvest Summer Spangle,"CROPSANITY", -2329,Farming,Harvest Sunflower,"CROPSANITY", -2330,Farming,Harvest Tomato,"CROPSANITY", -2331,Farming,Harvest Tulip,"CROPSANITY", -2332,Farming,Harvest Unmilled Rice,"CROPSANITY", -2333,Farming,Harvest Wheat,"CROPSANITY", -2334,Farming,Harvest Yam,"CROPSANITY", -2335,Farming,Harvest Cactus Fruit,"CROPSANITY", +2301,Farming,Harvest Amaranth,CROPSANITY, +2302,Farming,Harvest Artichoke,CROPSANITY, +2303,Farming,Harvest Beet,CROPSANITY, +2304,Farming,Harvest Blue Jazz,CROPSANITY, +2305,Farming,Harvest Blueberry,CROPSANITY, +2306,Farming,Harvest Bok Choy,CROPSANITY, +2307,Farming,Harvest Cauliflower,CROPSANITY, +2308,Farming,Harvest Corn,CROPSANITY, +2309,Farming,Harvest Cranberries,CROPSANITY, +2310,Farming,Harvest Eggplant,CROPSANITY, +2311,Farming,Harvest Fairy Rose,CROPSANITY, +2312,Farming,Harvest Garlic,CROPSANITY, +2313,Farming,Harvest Grape,CROPSANITY, +2314,Farming,Harvest Green Bean,CROPSANITY, +2315,Farming,Harvest Hops,CROPSANITY, +2316,Farming,Harvest Hot Pepper,CROPSANITY, +2317,Farming,Harvest Kale,CROPSANITY, +2318,Farming,Harvest Melon,CROPSANITY, +2319,Farming,Harvest Parsnip,CROPSANITY, +2320,Farming,Harvest Poppy,CROPSANITY, +2321,Farming,Harvest Potato,CROPSANITY, +2322,Farming,Harvest Pumpkin,CROPSANITY, +2323,Farming,Harvest Radish,CROPSANITY, +2324,Farming,Harvest Red Cabbage,CROPSANITY, +2325,Farming,Harvest Rhubarb,CROPSANITY, +2326,Farming,Harvest Starfruit,CROPSANITY, +2327,Farming,Harvest Strawberry,CROPSANITY, +2328,Farming,Harvest Summer Spangle,CROPSANITY, +2329,Farming,Harvest Sunflower,CROPSANITY, +2330,Farming,Harvest Tomato,CROPSANITY, +2331,Farming,Harvest Tulip,CROPSANITY, +2332,Farming,Harvest Unmilled Rice,CROPSANITY, +2333,Farming,Harvest Wheat,CROPSANITY, +2334,Farming,Harvest Yam,CROPSANITY, +2335,Farming,Harvest Cactus Fruit,CROPSANITY, 2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", 2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farming,Harvest Sweet Gem Berry,"CROPSANITY", -2339,Farming,Harvest Apple,"CROPSANITY", -2340,Farming,Harvest Apricot,"CROPSANITY", -2341,Farming,Harvest Cherry,"CROPSANITY", -2342,Farming,Harvest Orange,"CROPSANITY", -2343,Farming,Harvest Pomegranate,"CROPSANITY", -2344,Farming,Harvest Peach,"CROPSANITY", +2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, +2339,Farming,Harvest Apple,CROPSANITY, +2340,Farming,Harvest Apricot,CROPSANITY, +2341,Farming,Harvest Cherry,CROPSANITY, +2342,Farming,Harvest Orange,CROPSANITY, +2343,Farming,Harvest Pomegranate,CROPSANITY, +2344,Farming,Harvest Peach,CROPSANITY, 2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", 2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farming,Harvest Coffee Bean,"CROPSANITY", +2347,Farming,Harvest Coffee Bean,CROPSANITY, 2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", @@ -1256,7 +1256,7 @@ id,region,name,tags,mod_name 2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, 2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, 2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,"SHIPSANITY", +2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, 2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, 2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, 2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, @@ -1303,7 +1303,7 @@ id,region,name,tags,mod_name 2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, 2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", 2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Shipping,Shipsanity: Weathered Floor,"SHIPSANITY", +2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, 2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, 2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, 2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, @@ -1757,86 +1757,86 @@ id,region,name,tags,mod_name 3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", 3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", 3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3201,Kitchen,Cook Algae Soup,"COOKSANITY", +3201,Kitchen,Cook Algae Soup,COOKSANITY, 3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", -3203,Kitchen,Cook Autumn's Bounty,"COOKSANITY", +3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, 3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", 3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", -3206,Kitchen,Cook Bean Hotpot,"COOKSANITY", +3206,Kitchen,Cook Bean Hotpot,COOKSANITY, 3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", -3208,Kitchen,Cook Blueberry Tart,"COOKSANITY", +3208,Kitchen,Cook Blueberry Tart,COOKSANITY, 3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", 3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", 3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", -3212,Kitchen,Cook Cheese Cauliflower,"COOKSANITY", +3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, 3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", -3214,Kitchen,Cook Chowder,"COOKSANITY", +3214,Kitchen,Cook Chowder,COOKSANITY, 3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", 3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", -3217,Kitchen,Cook Cookies,"COOKSANITY", +3217,Kitchen,Cook Cookies,COOKSANITY, 3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", 3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", -3220,Kitchen,Cook Cranberry Sauce,"COOKSANITY", -3221,Kitchen,Cook Crispy Bass,"COOKSANITY", -3222,Kitchen,Cook Dish O' The Sea,"COOKSANITY", -3223,Kitchen,Cook Eggplant Parmesan,"COOKSANITY", -3224,Kitchen,Cook Escargot,"COOKSANITY", -3225,Kitchen,Cook Farmer's Lunch,"COOKSANITY", +3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, +3221,Kitchen,Cook Crispy Bass,COOKSANITY, +3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, +3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, +3224,Kitchen,Cook Escargot,COOKSANITY, +3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, 3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", -3227,Kitchen,Cook Fish Stew,"COOKSANITY", -3228,Kitchen,Cook Fish Taco,"COOKSANITY", -3229,Kitchen,Cook Fried Calamari,"COOKSANITY", -3230,Kitchen,Cook Fried Eel,"COOKSANITY", -3231,Kitchen,Cook Fried Egg,"COOKSANITY", -3232,Kitchen,Cook Fried Mushroom,"COOKSANITY", +3227,Kitchen,Cook Fish Stew,COOKSANITY, +3228,Kitchen,Cook Fish Taco,COOKSANITY, +3229,Kitchen,Cook Fried Calamari,COOKSANITY, +3230,Kitchen,Cook Fried Eel,COOKSANITY, +3231,Kitchen,Cook Fried Egg,COOKSANITY, +3232,Kitchen,Cook Fried Mushroom,COOKSANITY, 3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", 3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", 3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", 3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", -3237,Kitchen,Cook Ice Cream,"COOKSANITY", +3237,Kitchen,Cook Ice Cream,COOKSANITY, 3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", 3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", 3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", 3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", 3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", -3243,Kitchen,Cook Miner's Treat,"COOKSANITY", +3243,Kitchen,Cook Miner's Treat,COOKSANITY, 3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", -3245,Kitchen,Cook Pale Broth,"COOKSANITY", +3245,Kitchen,Cook Pale Broth,COOKSANITY, 3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", -3247,Kitchen,Cook Parsnip Soup,"COOKSANITY", -3248,Kitchen,Cook Pepper Poppers,"COOKSANITY", +3247,Kitchen,Cook Parsnip Soup,COOKSANITY, +3248,Kitchen,Cook Pepper Poppers,COOKSANITY, 3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", 3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", 3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", 3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", 3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", 3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", -3255,Kitchen,Cook Pumpkin Soup,"COOKSANITY", +3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, 3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", -3257,Kitchen,Cook Red Plate,"COOKSANITY", -3258,Kitchen,Cook Rhubarb Pie,"COOKSANITY", -3259,Kitchen,Cook Rice Pudding,"COOKSANITY", +3257,Kitchen,Cook Red Plate,COOKSANITY, +3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, +3259,Kitchen,Cook Rice Pudding,COOKSANITY, 3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", -3261,Kitchen,Cook Roots Platter,"COOKSANITY", -3262,Kitchen,Cook Salad,"COOKSANITY", -3263,Kitchen,Cook Salmon Dinner,"COOKSANITY", -3264,Kitchen,Cook Sashimi,"COOKSANITY", -3265,Kitchen,Cook Seafoam Pudding,"COOKSANITY", +3261,Kitchen,Cook Roots Platter,COOKSANITY, +3262,Kitchen,Cook Salad,COOKSANITY, +3263,Kitchen,Cook Salmon Dinner,COOKSANITY, +3264,Kitchen,Cook Sashimi,COOKSANITY, +3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, 3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", -3267,Kitchen,Cook Spaghetti,"COOKSANITY", -3268,Kitchen,Cook Spicy Eel,"COOKSANITY", -3269,Kitchen,Cook Squid Ink Ravioli,"COOKSANITY", +3267,Kitchen,Cook Spaghetti,COOKSANITY, +3268,Kitchen,Cook Spicy Eel,COOKSANITY, +3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, 3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", -3271,Kitchen,Cook Strange Bun,"COOKSANITY", -3272,Kitchen,Cook Stuffing,"COOKSANITY", -3273,Kitchen,Cook Super Meal,"COOKSANITY", -3274,Kitchen,Cook Survival Burger,"COOKSANITY", -3275,Kitchen,Cook Tom Kha Soup,"COOKSANITY", +3271,Kitchen,Cook Strange Bun,COOKSANITY, +3272,Kitchen,Cook Stuffing,COOKSANITY, +3273,Kitchen,Cook Super Meal,COOKSANITY, +3274,Kitchen,Cook Survival Burger,COOKSANITY, +3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, 3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", -3277,Kitchen,Cook Triple Shot Espresso,"COOKSANITY", +3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, 3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", 3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", -3280,Kitchen,Cook Vegetable Medley,"COOKSANITY", +3280,Kitchen,Cook Vegetable Medley,COOKSANITY, 3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", 3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", @@ -1867,7 +1867,7 @@ id,region,name,tags,mod_name 3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3331,Farm,Fried Egg Recipe,"CHEFSANITY_STARTER", +3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, 3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", 3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", 3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", @@ -1917,160 +1917,160 @@ id,region,name,tags,mod_name 3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", 3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", 3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3401,Farm,Craft Cherry Bomb,"CRAFTSANITY", -3402,Farm,Craft Bomb,"CRAFTSANITY", -3403,Farm,Craft Mega Bomb,"CRAFTSANITY", -3404,Farm,Craft Gate,"CRAFTSANITY", -3405,Farm,Craft Wood Fence,"CRAFTSANITY", -3406,Farm,Craft Stone Fence,"CRAFTSANITY", -3407,Farm,Craft Iron Fence,"CRAFTSANITY", -3408,Farm,Craft Hardwood Fence,"CRAFTSANITY", -3409,Farm,Craft Sprinkler,"CRAFTSANITY", -3410,Farm,Craft Quality Sprinkler,"CRAFTSANITY", -3411,Farm,Craft Iridium Sprinkler,"CRAFTSANITY", -3412,Farm,Craft Bee House,"CRAFTSANITY", -3413,Farm,Craft Cask,"CRAFTSANITY", -3414,Farm,Craft Cheese Press,"CRAFTSANITY", -3415,Farm,Craft Keg,"CRAFTSANITY", -3416,Farm,Craft Loom,"CRAFTSANITY", -3417,Farm,Craft Mayonnaise Machine,"CRAFTSANITY", -3418,Farm,Craft Oil Maker,"CRAFTSANITY", -3419,Farm,Craft Preserves Jar,"CRAFTSANITY", -3420,Farm,Craft Basic Fertilizer,"CRAFTSANITY", -3421,Farm,Craft Quality Fertilizer,"CRAFTSANITY", -3422,Farm,Craft Deluxe Fertilizer,"CRAFTSANITY", -3423,Farm,Craft Speed-Gro,"CRAFTSANITY", -3424,Farm,Craft Deluxe Speed-Gro,"CRAFTSANITY", +3401,Farm,Craft Cherry Bomb,CRAFTSANITY, +3402,Farm,Craft Bomb,CRAFTSANITY, +3403,Farm,Craft Mega Bomb,CRAFTSANITY, +3404,Farm,Craft Gate,CRAFTSANITY, +3405,Farm,Craft Wood Fence,CRAFTSANITY, +3406,Farm,Craft Stone Fence,CRAFTSANITY, +3407,Farm,Craft Iron Fence,CRAFTSANITY, +3408,Farm,Craft Hardwood Fence,CRAFTSANITY, +3409,Farm,Craft Sprinkler,CRAFTSANITY, +3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, +3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, +3412,Farm,Craft Bee House,CRAFTSANITY, +3413,Farm,Craft Cask,CRAFTSANITY, +3414,Farm,Craft Cheese Press,CRAFTSANITY, +3415,Farm,Craft Keg,CRAFTSANITY, +3416,Farm,Craft Loom,CRAFTSANITY, +3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, +3418,Farm,Craft Oil Maker,CRAFTSANITY, +3419,Farm,Craft Preserves Jar,CRAFTSANITY, +3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, +3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, +3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, +3423,Farm,Craft Speed-Gro,CRAFTSANITY, +3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, 3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", -3426,Farm,Craft Basic Retaining Soil,"CRAFTSANITY", -3427,Farm,Craft Quality Retaining Soil,"CRAFTSANITY", +3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, +3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, 3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", -3429,Farm,Craft Tree Fertilizer,"CRAFTSANITY", -3430,Farm,Craft Spring Seeds,"CRAFTSANITY", -3431,Farm,Craft Summer Seeds,"CRAFTSANITY", -3432,Farm,Craft Fall Seeds,"CRAFTSANITY", -3433,Farm,Craft Winter Seeds,"CRAFTSANITY", -3434,Farm,Craft Ancient Seeds,"CRAFTSANITY", -3435,Farm,Craft Grass Starter,"CRAFTSANITY", -3436,Farm,Craft Tea Sapling,"CRAFTSANITY", -3437,Farm,Craft Fiber Seeds,"CRAFTSANITY", -3438,Farm,Craft Wood Floor,"CRAFTSANITY", -3439,Farm,Craft Rustic Plank Floor,"CRAFTSANITY", -3440,Farm,Craft Straw Floor,"CRAFTSANITY", -3441,Farm,Craft Weathered Floor,"CRAFTSANITY", -3442,Farm,Craft Crystal Floor,"CRAFTSANITY", -3443,Farm,Craft Stone Floor,"CRAFTSANITY", -3444,Farm,Craft Stone Walkway Floor,"CRAFTSANITY", -3445,Farm,Craft Brick Floor,"CRAFTSANITY", -3446,Farm,Craft Wood Path,"CRAFTSANITY", -3447,Farm,Craft Gravel Path,"CRAFTSANITY", -3448,Farm,Craft Cobblestone Path,"CRAFTSANITY", -3449,Farm,Craft Stepping Stone Path,"CRAFTSANITY", -3450,Farm,Craft Crystal Path,"CRAFTSANITY", -3451,Farm,Craft Spinner,"CRAFTSANITY", -3452,Farm,Craft Trap Bobber,"CRAFTSANITY", -3453,Farm,Craft Cork Bobber,"CRAFTSANITY", -3454,Farm,Craft Quality Bobber,"CRAFTSANITY", -3455,Farm,Craft Treasure Hunter,"CRAFTSANITY", -3456,Farm,Craft Dressed Spinner,"CRAFTSANITY", -3457,Farm,Craft Barbed Hook,"CRAFTSANITY", -3458,Farm,Craft Magnet,"CRAFTSANITY", -3459,Farm,Craft Bait,"CRAFTSANITY", -3460,Farm,Craft Wild Bait,"CRAFTSANITY", +3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, +3430,Farm,Craft Spring Seeds,CRAFTSANITY, +3431,Farm,Craft Summer Seeds,CRAFTSANITY, +3432,Farm,Craft Fall Seeds,CRAFTSANITY, +3433,Farm,Craft Winter Seeds,CRAFTSANITY, +3434,Farm,Craft Ancient Seeds,CRAFTSANITY, +3435,Farm,Craft Grass Starter,CRAFTSANITY, +3436,Farm,Craft Tea Sapling,CRAFTSANITY, +3437,Farm,Craft Fiber Seeds,CRAFTSANITY, +3438,Farm,Craft Wood Floor,CRAFTSANITY, +3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, +3440,Farm,Craft Straw Floor,CRAFTSANITY, +3441,Farm,Craft Weathered Floor,CRAFTSANITY, +3442,Farm,Craft Crystal Floor,CRAFTSANITY, +3443,Farm,Craft Stone Floor,CRAFTSANITY, +3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, +3445,Farm,Craft Brick Floor,CRAFTSANITY, +3446,Farm,Craft Wood Path,CRAFTSANITY, +3447,Farm,Craft Gravel Path,CRAFTSANITY, +3448,Farm,Craft Cobblestone Path,CRAFTSANITY, +3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, +3450,Farm,Craft Crystal Path,CRAFTSANITY, +3451,Farm,Craft Spinner,CRAFTSANITY, +3452,Farm,Craft Trap Bobber,CRAFTSANITY, +3453,Farm,Craft Cork Bobber,CRAFTSANITY, +3454,Farm,Craft Quality Bobber,CRAFTSANITY, +3455,Farm,Craft Treasure Hunter,CRAFTSANITY, +3456,Farm,Craft Dressed Spinner,CRAFTSANITY, +3457,Farm,Craft Barbed Hook,CRAFTSANITY, +3458,Farm,Craft Magnet,CRAFTSANITY, +3459,Farm,Craft Bait,CRAFTSANITY, +3460,Farm,Craft Wild Bait,CRAFTSANITY, 3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", -3462,Farm,Craft Crab Pot,"CRAFTSANITY", -3463,Farm,Craft Sturdy Ring,"CRAFTSANITY", -3464,Farm,Craft Warrior Ring,"CRAFTSANITY", -3465,Farm,Craft Ring of Yoba,"CRAFTSANITY", +3462,Farm,Craft Crab Pot,CRAFTSANITY, +3463,Farm,Craft Sturdy Ring,CRAFTSANITY, +3464,Farm,Craft Warrior Ring,CRAFTSANITY, +3465,Farm,Craft Ring of Yoba,CRAFTSANITY, 3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", -3467,Farm,Craft Glowstone Ring,"CRAFTSANITY", -3468,Farm,Craft Iridium Band,"CRAFTSANITY", -3469,Farm,Craft Wedding Ring,"CRAFTSANITY", -3470,Farm,Craft Field Snack,"CRAFTSANITY", -3471,Farm,Craft Bug Steak,"CRAFTSANITY", -3472,Farm,Craft Life Elixir,"CRAFTSANITY", -3473,Farm,Craft Oil of Garlic,"CRAFTSANITY", -3474,Farm,Craft Monster Musk,"CRAFTSANITY", -3475,Farm,Craft Fairy Dust,"CRAFTSANITY", -3476,Farm,Craft Warp Totem: Beach,"CRAFTSANITY", -3477,Farm,Craft Warp Totem: Mountains,"CRAFTSANITY", -3478,Farm,Craft Warp Totem: Farm,"CRAFTSANITY", -3479,Farm,Craft Warp Totem: Desert,"CRAFTSANITY", +3467,Farm,Craft Glowstone Ring,CRAFTSANITY, +3468,Farm,Craft Iridium Band,CRAFTSANITY, +3469,Farm,Craft Wedding Ring,CRAFTSANITY, +3470,Farm,Craft Field Snack,CRAFTSANITY, +3471,Farm,Craft Bug Steak,CRAFTSANITY, +3472,Farm,Craft Life Elixir,CRAFTSANITY, +3473,Farm,Craft Oil of Garlic,CRAFTSANITY, +3474,Farm,Craft Monster Musk,CRAFTSANITY, +3475,Farm,Craft Fairy Dust,CRAFTSANITY, +3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, +3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, +3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, +3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, 3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", -3481,Farm,Craft Rain Totem,"CRAFTSANITY", -3482,Farm,Craft Torch,"CRAFTSANITY", -3483,Farm,Craft Campfire,"CRAFTSANITY", -3484,Farm,Craft Wooden Brazier,"CRAFTSANITY", -3485,Farm,Craft Stone Brazier,"CRAFTSANITY", -3486,Farm,Craft Gold Brazier,"CRAFTSANITY", -3487,Farm,Craft Carved Brazier,"CRAFTSANITY", -3488,Farm,Craft Stump Brazier,"CRAFTSANITY", -3489,Farm,Craft Barrel Brazier,"CRAFTSANITY", -3490,Farm,Craft Skull Brazier,"CRAFTSANITY", -3491,Farm,Craft Marble Brazier,"CRAFTSANITY", -3492,Farm,Craft Wood Lamp-post,"CRAFTSANITY", -3493,Farm,Craft Iron Lamp-post,"CRAFTSANITY", -3494,Farm,Craft Jack-O-Lantern,"CRAFTSANITY", -3495,Farm,Craft Bone Mill,"CRAFTSANITY", -3496,Farm,Craft Charcoal Kiln,"CRAFTSANITY", -3497,Farm,Craft Crystalarium,"CRAFTSANITY", -3498,Farm,Craft Furnace,"CRAFTSANITY", -3499,Farm,Craft Geode Crusher,"CRAFTSANITY", +3481,Farm,Craft Rain Totem,CRAFTSANITY, +3482,Farm,Craft Torch,CRAFTSANITY, +3483,Farm,Craft Campfire,CRAFTSANITY, +3484,Farm,Craft Wooden Brazier,CRAFTSANITY, +3485,Farm,Craft Stone Brazier,CRAFTSANITY, +3486,Farm,Craft Gold Brazier,CRAFTSANITY, +3487,Farm,Craft Carved Brazier,CRAFTSANITY, +3488,Farm,Craft Stump Brazier,CRAFTSANITY, +3489,Farm,Craft Barrel Brazier,CRAFTSANITY, +3490,Farm,Craft Skull Brazier,CRAFTSANITY, +3491,Farm,Craft Marble Brazier,CRAFTSANITY, +3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, +3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, +3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, +3495,Farm,Craft Bone Mill,CRAFTSANITY, +3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, +3497,Farm,Craft Crystalarium,CRAFTSANITY, +3498,Farm,Craft Furnace,CRAFTSANITY, +3499,Farm,Craft Geode Crusher,CRAFTSANITY, 3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", -3501,Farm,Craft Lightning Rod,"CRAFTSANITY", +3501,Farm,Craft Lightning Rod,CRAFTSANITY, 3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", -3503,Farm,Craft Recycling Machine,"CRAFTSANITY", -3504,Farm,Craft Seed Maker,"CRAFTSANITY", -3505,Farm,Craft Slime Egg-Press,"CRAFTSANITY", -3506,Farm,Craft Slime Incubator,"CRAFTSANITY", -3507,Farm,Craft Solar Panel,"CRAFTSANITY", -3508,Farm,Craft Tapper,"CRAFTSANITY", -3509,Farm,Craft Worm Bin,"CRAFTSANITY", -3510,Farm,Craft Tub o' Flowers,"CRAFTSANITY", -3511,Farm,Craft Wicked Statue,"CRAFTSANITY", -3512,Farm,Craft Flute Block,"CRAFTSANITY", -3513,Farm,Craft Drum Block,"CRAFTSANITY", -3514,Farm,Craft Chest,"CRAFTSANITY", -3515,Farm,Craft Stone Chest,"CRAFTSANITY", -3516,Farm,Craft Wood Sign,"CRAFTSANITY", -3517,Farm,Craft Stone Sign,"CRAFTSANITY", -3518,Farm,Craft Dark Sign,"CRAFTSANITY", -3519,Farm,Craft Garden Pot,"CRAFTSANITY", -3520,Farm,Craft Scarecrow,"CRAFTSANITY", -3521,Farm,Craft Deluxe Scarecrow,"CRAFTSANITY", -3522,Farm,Craft Staircase,"CRAFTSANITY", -3523,Farm,Craft Explosive Ammo,"CRAFTSANITY", -3524,Farm,Craft Transmute (Fe),"CRAFTSANITY", -3525,Farm,Craft Transmute (Au),"CRAFTSANITY", -3526,Farm,Craft Mini-Jukebox,"CRAFTSANITY", -3527,Farm,Craft Mini-Obelisk,"CRAFTSANITY", -3528,Farm,Craft Farm Computer,"CRAFTSANITY", +3503,Farm,Craft Recycling Machine,CRAFTSANITY, +3504,Farm,Craft Seed Maker,CRAFTSANITY, +3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, +3506,Farm,Craft Slime Incubator,CRAFTSANITY, +3507,Farm,Craft Solar Panel,CRAFTSANITY, +3508,Farm,Craft Tapper,CRAFTSANITY, +3509,Farm,Craft Worm Bin,CRAFTSANITY, +3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, +3511,Farm,Craft Wicked Statue,CRAFTSANITY, +3512,Farm,Craft Flute Block,CRAFTSANITY, +3513,Farm,Craft Drum Block,CRAFTSANITY, +3514,Farm,Craft Chest,CRAFTSANITY, +3515,Farm,Craft Stone Chest,CRAFTSANITY, +3516,Farm,Craft Wood Sign,CRAFTSANITY, +3517,Farm,Craft Stone Sign,CRAFTSANITY, +3518,Farm,Craft Dark Sign,CRAFTSANITY, +3519,Farm,Craft Garden Pot,CRAFTSANITY, +3520,Farm,Craft Scarecrow,CRAFTSANITY, +3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, +3522,Farm,Craft Staircase,CRAFTSANITY, +3523,Farm,Craft Explosive Ammo,CRAFTSANITY, +3524,Farm,Craft Transmute (Fe),CRAFTSANITY, +3525,Farm,Craft Transmute (Au),CRAFTSANITY, +3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, +3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, +3528,Farm,Craft Farm Computer,CRAFTSANITY, 3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", -3530,Farm,Craft Cookout Kit,"CRAFTSANITY", -3551,Pierre's General Store,Grass Starter Recipe,"CRAFTSANITY", -3552,Carpenter Shop,Wood Floor Recipe,"CRAFTSANITY", -3553,Carpenter Shop,Rustic Plank Floor Recipe,"CRAFTSANITY", -3554,Carpenter Shop,Straw Floor Recipe,"CRAFTSANITY", -3555,Mines Dwarf Shop,Weathered Floor Recipe,"CRAFTSANITY", -3556,Sewer,Crystal Floor Recipe,"CRAFTSANITY", -3557,Carpenter Shop,Stone Floor Recipe,"CRAFTSANITY", -3558,Carpenter Shop,Stone Walkway Floor Recipe,"CRAFTSANITY", -3559,Carpenter Shop,Brick Floor Recipe,"CRAFTSANITY", -3560,Carpenter Shop,Stepping Stone Path Recipe,"CRAFTSANITY", -3561,Carpenter Shop,Crystal Path Recipe,"CRAFTSANITY", -3562,Traveling Cart,Wedding Ring Recipe,"CRAFTSANITY", +3530,Farm,Craft Cookout Kit,CRAFTSANITY, +3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, +3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, +3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, +3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, +3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, +3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, +3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, +3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, +3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, +3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, +3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, +3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, 3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", -3564,Carpenter Shop,Wooden Brazier Recipe,"CRAFTSANITY", -3565,Carpenter Shop,Stone Brazier Recipe,"CRAFTSANITY", -3566,Carpenter Shop,Gold Brazier Recipe,"CRAFTSANITY", -3567,Carpenter Shop,Carved Brazier Recipe,"CRAFTSANITY", -3568,Carpenter Shop,Stump Brazier Recipe,"CRAFTSANITY", -3569,Carpenter Shop,Barrel Brazier Recipe,"CRAFTSANITY", -3570,Carpenter Shop,Skull Brazier Recipe,"CRAFTSANITY", -3571,Carpenter Shop,Marble Brazier Recipe,"CRAFTSANITY", -3572,Carpenter Shop,Wood Lamp-post Recipe,"CRAFTSANITY", -3573,Carpenter Shop,Iron Lamp-post Recipe,"CRAFTSANITY", -3574,Sewer,Wicked Statue Recipe,"CRAFTSANITY", +3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, +3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, +3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, +3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, +3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, +3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, +3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, +3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, +3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, +3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, +3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill @@ -2535,20 +2535,20 @@ id,region,name,tags,mod_name 7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul 7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul 7522,Witch's Swamp,Witch's order,,Distant Lands - Witch Swamp Overhaul -7551,Kitchen,Cook Baked Berry Oatmeal,"COOKSANITY",Stardew Valley Expanded -7552,Kitchen,Cook Flower Cookie,"COOKSANITY",Stardew Valley Expanded -7553,Kitchen,Cook Big Bark Burger,"COOKSANITY",Stardew Valley Expanded -7554,Kitchen,Cook Frog Legs,"COOKSANITY",Stardew Valley Expanded -7555,Kitchen,Cook Glazed Butterfish,"COOKSANITY",Stardew Valley Expanded -7556,Kitchen,Cook Mixed Berry Pie,"COOKSANITY",Stardew Valley Expanded -7557,Kitchen,Cook Mushroom Berry Rice,"COOKSANITY",Stardew Valley Expanded -7558,Kitchen,Cook Seaweed Salad,"COOKSANITY",Stardew Valley Expanded -7559,Kitchen,Cook Void Delight,"COOKSANITY",Stardew Valley Expanded -7560,Kitchen,Cook Void Salmon Sushi,"COOKSANITY",Stardew Valley Expanded -7561,Kitchen,Cook Mushroom Kebab,"COOKSANITY",Distant Lands - Witch Swamp Overhaul -7562,Kitchen,Cook Crayfish Soup,"COOKSANITY",Distant Lands - Witch Swamp Overhaul -7563,Kitchen,Cook Pemmican,"COOKSANITY",Distant Lands - Witch Swamp Overhaul -7564,Kitchen,Cook Void Mint Tea,"COOKSANITY",Distant Lands - Witch Swamp Overhaul +7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded +7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded +7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded +7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded +7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded +7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded +7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded +7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded +7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded +7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded +7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul 7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded From a73e7a3d5a626092bda0de2e23aeead3160cbad1 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sat, 2 Dec 2023 12:05:33 -0600 Subject: [PATCH 289/482] How about this for line endings. --- worlds/stardew_valley/data/items.csv | 1 + worlds/stardew_valley/data/locations.csv | 1 + 2 files changed, 2 insertions(+) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 6c93e1bcf108..d51359b17d81 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -824,3 +824,4 @@ id,name,classification,groups,mod_name 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded + diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index ad3b07354345..c610f6c4e08a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2813,3 +2813,4 @@ id,region,name,tags,mod_name 8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul + From 28aa482adcdce12aad5bfab8d9e0e7200e806680 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sat, 2 Dec 2023 12:06:25 -0600 Subject: [PATCH 290/482] And the finale. --- worlds/stardew_valley/data/items.csv | 1 - worlds/stardew_valley/data/locations.csv | 1 - 2 files changed, 2 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index d51359b17d81..6c93e1bcf108 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -824,4 +824,3 @@ id,name,classification,groups,mod_name 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded - diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c610f6c4e08a..ad3b07354345 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2813,4 +2813,3 @@ id,region,name,tags,mod_name 8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul - From 8d2d044e8c01a2ad1984b2b111f229befa4d2e46 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 2 Dec 2023 23:05:58 -0500 Subject: [PATCH 291/482] - Slight improvement --- worlds/stardew_valley/mods/logic/item_logic.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index d922306fb3e6..43012a608232 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -137,7 +137,5 @@ def get_distant_lands_item_rules(self): # Items that don't behave enough like a crop but enough to warrant a portion of the cropsanity logic. def pseudo_cropsanity_check(self, seed_name: str): if self.options.cropsanity == Cropsanity.option_disabled: - item_rule = True_() - else: - item_rule = self.logic.received(seed_name) - return item_rule + return True_() + return self.logic.received(seed_name) From ec2905ffe2591cbe2d86bd7a127a76bc870edded Mon Sep 17 00:00:00 2001 From: Witchybun <96719127+Witchybun@users.noreply.github.com> Date: Mon, 4 Dec 2023 00:54:06 -0600 Subject: [PATCH 292/482] Add files via upload --- worlds/stardew_valley/data/items.csv | 1652 +++---- worlds/stardew_valley/data/locations.csv | 5630 +++++++++++----------- 2 files changed, 3641 insertions(+), 3641 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 6c93e1bcf108..1ee00327e922 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -1,826 +1,826 @@ -id,name,classification,groups,mod_name -0,Joja Cola,filler,TRASH, -15,Rusty Key,progression,, -16,Dwarvish Translation Guide,progression,, -17,Bridge Repair,progression,COMMUNITY_REWARD, -18,Greenhouse,progression,COMMUNITY_REWARD, -19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, -20,Minecarts Repair,useful,COMMUNITY_REWARD, -21,Bus Repair,progression,COMMUNITY_REWARD, -22,Progressive Movie Theater,progression,COMMUNITY_REWARD, -23,Stardrop,progression,, -24,Progressive Backpack,progression,, -25,Rusty Sword,filler,"WEAPON,DEPRECATED", -26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", -27,Work Boots,filler,"FOOTWEAR,DEPRECATED", -28,Wooden Blade,filler,"WEAPON,DEPRECATED", -29,Iron Dirk,filler,"WEAPON,DEPRECATED", -30,Wind Spire,filler,"WEAPON,DEPRECATED", -31,Femur,filler,"WEAPON,DEPRECATED", -32,Steel Smallsword,filler,"WEAPON,DEPRECATED", -33,Wood Club,filler,"WEAPON,DEPRECATED", -34,Elf Blade,filler,"WEAPON,DEPRECATED", -37,Slingshot,filler,"WEAPON,DEPRECATED", -38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", -39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", -40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", -41,Silver Saber,filler,"WEAPON,DEPRECATED", -42,Pirate's Sword,filler,"WEAPON,DEPRECATED", -43,Crystal Dagger,filler,"WEAPON,DEPRECATED", -44,Cutlass,filler,"WEAPON,DEPRECATED", -45,Iron Edge,filler,"WEAPON,DEPRECATED", -46,Burglar's Shank,filler,"WEAPON,DEPRECATED", -47,Wood Mallet,filler,"WEAPON,DEPRECATED", -48,Master Slingshot,filler,"WEAPON,DEPRECATED", -49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", -50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", -51,Claymore,filler,"WEAPON,DEPRECATED", -52,Templar's Blade,filler,"WEAPON,DEPRECATED", -53,Kudgel,filler,"WEAPON,DEPRECATED", -54,Shadow Dagger,filler,"WEAPON,DEPRECATED", -55,Obsidian Edge,filler,"WEAPON,DEPRECATED", -56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", -57,Wicked Kris,filler,"WEAPON,DEPRECATED", -58,Bone Sword,filler,"WEAPON,DEPRECATED", -59,Ossified Blade,filler,"WEAPON,DEPRECATED", -60,Space Boots,filler,"FOOTWEAR,DEPRECATED", -61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", -62,Steel Falchion,filler,"WEAPON,DEPRECATED", -63,The Slammer,filler,"WEAPON,DEPRECATED", -64,Skull Key,progression,, -65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, -66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, -67,Progressive Axe,progression,PROGRESSIVE_TOOLS, -68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, -69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, -70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, -71,Golden Scythe,useful,, -72,Progressive Mine Elevator,progression,, -73,Farming Level,progression,SKILL_LEVEL_UP, -74,Fishing Level,progression,SKILL_LEVEL_UP, -75,Foraging Level,progression,SKILL_LEVEL_UP, -76,Mining Level,progression,SKILL_LEVEL_UP, -77,Combat Level,progression,SKILL_LEVEL_UP, -78,Earth Obelisk,progression,WIZARD_BUILDING, -79,Water Obelisk,progression,WIZARD_BUILDING, -80,Desert Obelisk,progression,WIZARD_BUILDING, -81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", -82,Junimo Hut,useful,WIZARD_BUILDING, -83,Gold Clock,progression,WIZARD_BUILDING, -84,Progressive Coop,progression,BUILDING, -85,Progressive Barn,progression,BUILDING, -86,Well,useful,BUILDING, -87,Silo,progression,BUILDING, -88,Mill,progression,BUILDING, -89,Progressive Shed,progression,BUILDING, -90,Fish Pond,progression,BUILDING, -91,Stable,useful,BUILDING, -92,Slime Hutch,progression,BUILDING, -93,Shipping Bin,progression,BUILDING, -94,Beach Bridge,progression,, -95,Adventurer's Guild,progression,, -96,Club Card,progression,, -97,Magnifying Glass,progression,, -98,Bear's Knowledge,useful,, -99,Iridium Snake Milk,useful,, -100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, -101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, -102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, -103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, -104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, -105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, -106,Galaxy Sword,filler,"WEAPON,DEPRECATED", -107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", -108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", -109,Movement Speed Bonus,progression,, -110,Luck Bonus,progression,, -111,Lava Katana,filler,"WEAPON,DEPRECATED", -112,Progressive House,progression,, -113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, -114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, -115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, -116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, -117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, -118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, -119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, -120,Traveling Merchant Stock Size,useful,, -121,Traveling Merchant Discount,useful,, -122,Return Scepter,useful,, -123,Progressive Season,progression,, -124,Spring,progression,SEASON, -125,Summer,progression,SEASON, -126,Fall,progression,SEASON, -127,Winter,progression,SEASON, -128,Amaranth Seeds,progression,CROPSANITY, -129,Artichoke Seeds,progression,CROPSANITY, -130,Beet Seeds,progression,CROPSANITY, -131,Jazz Seeds,progression,CROPSANITY, -132,Blueberry Seeds,progression,CROPSANITY, -133,Bok Choy Seeds,progression,CROPSANITY, -134,Cauliflower Seeds,progression,CROPSANITY, -135,Corn Seeds,progression,CROPSANITY, -136,Cranberry Seeds,progression,CROPSANITY, -137,Eggplant Seeds,progression,CROPSANITY, -138,Fairy Seeds,progression,CROPSANITY, -139,Garlic Seeds,progression,CROPSANITY, -140,Grape Starter,progression,CROPSANITY, -141,Bean Starter,progression,CROPSANITY, -142,Hops Starter,progression,CROPSANITY, -143,Pepper Seeds,progression,CROPSANITY, -144,Kale Seeds,progression,CROPSANITY, -145,Melon Seeds,progression,CROPSANITY, -146,Parsnip Seeds,progression,CROPSANITY, -147,Poppy Seeds,progression,CROPSANITY, -148,Potato Seeds,progression,CROPSANITY, -149,Pumpkin Seeds,progression,CROPSANITY, -150,Radish Seeds,progression,CROPSANITY, -151,Red Cabbage Seeds,progression,CROPSANITY, -152,Rhubarb Seeds,progression,CROPSANITY, -153,Starfruit Seeds,progression,CROPSANITY, -154,Strawberry Seeds,progression,CROPSANITY, -155,Spangle Seeds,progression,CROPSANITY, -156,Sunflower Seeds,progression,CROPSANITY, -157,Tomato Seeds,progression,CROPSANITY, -158,Tulip Bulb,progression,CROPSANITY, -159,Rice Shoot,progression,CROPSANITY, -160,Wheat Seeds,progression,CROPSANITY, -161,Yam Seeds,progression,CROPSANITY, -162,Cactus Seeds,progression,CROPSANITY, -163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -164,Ancient Seeds Recipe,progression,MUSEUM, -165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -166,Traveling Merchant Metal Detector,progression,MUSEUM, -167,Alex <3,progression,FRIENDSANITY, -168,Elliott <3,progression,FRIENDSANITY, -169,Harvey <3,progression,FRIENDSANITY, -170,Sam <3,progression,FRIENDSANITY, -171,Sebastian <3,progression,FRIENDSANITY, -172,Shane <3,progression,FRIENDSANITY, -173,Abigail <3,progression,FRIENDSANITY, -174,Emily <3,progression,FRIENDSANITY, -175,Haley <3,progression,FRIENDSANITY, -176,Leah <3,progression,FRIENDSANITY, -177,Maru <3,progression,FRIENDSANITY, -178,Penny <3,progression,FRIENDSANITY, -179,Caroline <3,progression,FRIENDSANITY, -180,Clint <3,progression,FRIENDSANITY, -181,Demetrius <3,progression,FRIENDSANITY, -182,Dwarf <3,progression,FRIENDSANITY, -183,Evelyn <3,progression,FRIENDSANITY, -184,George <3,progression,FRIENDSANITY, -185,Gus <3,progression,FRIENDSANITY, -186,Jas <3,progression,FRIENDSANITY, -187,Jodi <3,progression,FRIENDSANITY, -188,Kent <3,progression,FRIENDSANITY, -189,Krobus <3,progression,FRIENDSANITY, -190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", -191,Lewis <3,progression,FRIENDSANITY, -192,Linus <3,progression,FRIENDSANITY, -193,Marnie <3,progression,FRIENDSANITY, -194,Pam <3,progression,FRIENDSANITY, -195,Pierre <3,progression,FRIENDSANITY, -196,Robin <3,progression,FRIENDSANITY, -197,Sandy <3,progression,FRIENDSANITY, -198,Vincent <3,progression,FRIENDSANITY, -199,Willy <3,progression,FRIENDSANITY, -200,Wizard <3,progression,FRIENDSANITY, -201,Pet <3,progression,FRIENDSANITY, -202,Rarecrow #1,progression,"FESTIVAL,RARECROW", -203,Rarecrow #2,progression,"FESTIVAL,RARECROW", -204,Rarecrow #3,progression,"FESTIVAL,RARECROW", -205,Rarecrow #4,progression,"FESTIVAL,RARECROW", -206,Rarecrow #5,progression,"FESTIVAL,RARECROW", -207,Rarecrow #6,progression,"FESTIVAL,RARECROW", -208,Rarecrow #7,progression,"FESTIVAL,RARECROW", -209,Rarecrow #8,progression,"FESTIVAL,RARECROW", -210,Straw Hat,filler,FESTIVAL, -211,Golden Pumpkin,useful,FESTIVAL, -212,Barbed Hook,useful,FESTIVAL, -213,Dressed Spinner,useful,FESTIVAL, -214,Magnet,useful,FESTIVAL, -215,Sailor's Cap,filler,FESTIVAL, -216,Pearl,useful,FESTIVAL, -217,Cone Hat,filler,FESTIVAL, -218,Iridium Fireplace,filler,FESTIVAL, -219,Lupini: Red Eagle,filler,FESTIVAL, -220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, -221,Lupini: Solar Kingdom,filler,FESTIVAL, -222,Lupini: Clouds,filler,FESTIVAL, -223,Lupini: 1000 Years From Now,filler,FESTIVAL, -224,Lupini: Three Trees,filler,FESTIVAL, -225,Lupini: The Serpent,filler,FESTIVAL, -226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, -227,Lupini: Land Of Clay,filler,FESTIVAL, -228,Special Order Board,progression,SPECIAL_ORDER_BOARD, -229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, -230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, -231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, -232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, -233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, -234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, -235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, -236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, -237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, -239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -260,Boat Repair,progression,GINGER_ISLAND, -261,Open Professor Snail Cave,progression,GINGER_ISLAND, -262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", -271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", -275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", -276,Weather Report,useful,TV_CHANNEL, -277,Fortune Teller,useful,TV_CHANNEL, -278,Livin' Off The Land,useful,TV_CHANNEL, -279,The Queen of Sauce,progression,TV_CHANNEL, -280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, -281,Sinister Signal,useful,TV_CHANNEL, -282,Dark Talisman,progression,, -283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, -284,Cute Baby,progression,BABY, -285,Ugly Baby,progression,BABY, -286,Deluxe Scarecrow Recipe,progression,RARECROW, -287,Treehouse,progression,GINGER_ISLAND, -288,Coffee Bean,progression,CROPSANITY, -289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", -290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", -291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", -292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", -293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -294,Progressive Footwear,useful,FOOTWEAR, -295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -325,Fairy Dust Recipe,progression,, -326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, -329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -331,Jack-O-Lantern Recipe,progression,FESTIVAL, -332,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, -333,Tub o' Flowers Recipe,progression,FESTIVAL, -334,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, -335,Moonlight Jellies Banner,filler,FESTIVAL, -336,Starport Decal,filler,FESTIVAL, -337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, -371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", -417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -425,Gate Recipe,progression,CRAFTSANITY, -426,Wood Fence Recipe,progression,CRAFTSANITY, -427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -428,Grass Starter Recipe,progression,CRAFTSANITY, -429,Wood Floor Recipe,progression,CRAFTSANITY, -430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, -431,Straw Floor Recipe,progression,CRAFTSANITY, -432,Weathered Floor Recipe,progression,CRAFTSANITY, -433,Crystal Floor Recipe,progression,CRAFTSANITY, -434,Stone Floor Recipe,progression,CRAFTSANITY, -435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, -436,Brick Floor Recipe,progression,CRAFTSANITY, -437,Wood Path Recipe,progression,CRAFTSANITY, -438,Gravel Path Recipe,progression,CRAFTSANITY, -439,Cobblestone Path Recipe,progression,CRAFTSANITY, -440,Stepping Stone Path Recipe,progression,CRAFTSANITY, -441,Crystal Path Recipe,progression,CRAFTSANITY, -442,Wedding Ring Recipe,progression,CRAFTSANITY, -443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, -444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -445,Torch Recipe,progression,CRAFTSANITY, -446,Campfire Recipe,progression,CRAFTSANITY, -447,Wooden Brazier Recipe,progression,CRAFTSANITY, -448,Stone Brazier Recipe,progression,CRAFTSANITY, -449,Gold Brazier Recipe,progression,CRAFTSANITY, -450,Carved Brazier Recipe,progression,CRAFTSANITY, -451,Stump Brazier Recipe,progression,CRAFTSANITY, -452,Barrel Brazier Recipe,progression,CRAFTSANITY, -453,Skull Brazier Recipe,progression,CRAFTSANITY, -454,Marble Brazier Recipe,progression,CRAFTSANITY, -455,Wood Lamp-post Recipe,progression,CRAFTSANITY, -456,Iron Lamp-post Recipe,progression,CRAFTSANITY, -457,Furnace Recipe,progression,CRAFTSANITY, -458,Wicked Statue Recipe,progression,CRAFTSANITY, -459,Chest Recipe,progression,CRAFTSANITY, -460,Wood Sign Recipe,progression,CRAFTSANITY, -461,Stone Sign Recipe,progression,CRAFTSANITY, -462,Standard Farm,progression,FARM_TYPE, -463,Riverland Farm,progression,FARM_TYPE, -464,Forest Farm,progression,FARM_TYPE, -465,Hill-top Farm,progression,FARM_TYPE, -466,Wilderness Farm,progression,FARM_TYPE, -467,Four Corners Farm,progression,FARM_TYPE, -468,Beach Farm,progression,FARM_TYPE, -469,Railroad Boulder Removed,progression,, -4001,Burnt,trap,TRAP, -4002,Darkness,trap,TRAP, -4003,Frozen,trap,TRAP, -4004,Jinxed,trap,TRAP, -4005,Nauseated,trap,TRAP, -4006,Slimed,trap,TRAP, -4007,Weakness,trap,TRAP, -4008,Taxes,trap,TRAP, -4009,Random Teleport,trap,TRAP, -4010,The Crows,trap,TRAP, -4011,Monsters,trap,TRAP, -4012,Entrance Reshuffle,trap,"TRAP,DEPRECATED", -4013,Debris,trap,TRAP, -4014,Shuffle,trap,TRAP, -4015,Temporary Winter,trap,"TRAP,DEPRECATED", -4016,Pariah,trap,TRAP, -4017,Drought,trap,TRAP, -5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", -5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", -5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", -5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", -5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", -5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", -5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", -5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", -5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", -5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM", -5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", -5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", -5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", -5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", -5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", -5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", -5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", -5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", -5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", -5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", -5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", -5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", -5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", -5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", -5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", -5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", -5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", -5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", -5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", -5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5207,Fiber Seeds,filler,RESOURCE_PACK, -5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5210,Quality Bobber,filler,RESOURCE_PACK, -5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", -5212,Monster Musk,filler,RESOURCE_PACK, -5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5216,Scarecrow,filler,RESOURCE_PACK, -5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", -5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", -5236,Aquatic Sanctuary,filler,RESOURCE_PACK, -5242,Exotic Double Bed,filler,RESOURCE_PACK, -5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", -5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", -5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5262,Slime Incubator,useful,RESOURCE_PACK, -5263,Slime Egg-Press,useful,RESOURCE_PACK, -5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill -10002,Magic Level,progression,SKILL_LEVEL_UP,Magic -10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill -10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology -10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill -10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill -10007,Tractor Garage,useful,,Tractor Mod -10008,Woods Obelisk,progression,,DeepWoods -10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic -10010,Spell: Till,useful,MAGIC_SPELL,Magic -10011,Spell: Water,progression,MAGIC_SPELL,Magic -10012,Spell: Blink,progression,MAGIC_SPELL,Magic -10013,Spell: Evac,useful,MAGIC_SPELL,Magic -10014,Spell: Haste,filler,MAGIC_SPELL,Magic -10015,Spell: Heal,progression,MAGIC_SPELL,Magic -10016,Spell: Buff,useful,MAGIC_SPELL,Magic -10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic -10018,Spell: Fireball,progression,MAGIC_SPELL,Magic -10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic -10020,Spell: Teleport,progression,MAGIC_SPELL,Magic -10021,Spell: Lantern,filler,MAGIC_SPELL,Magic -10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic -10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic -10024,Spell: Descend,progression,MAGIC_SPELL,Magic -10025,Spell: Meteor,progression,MAGIC_SPELL,Magic -10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic -10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic -10028,Spell: Spirit,progression,MAGIC_SPELL,Magic -10029,Spell: Rewind,useful,MAGIC_SPELL,Magic -10030,Pendant of Community,progression,,DeepWoods -10031,Pendant of Elders,progression,,DeepWoods -10032,Pendant of Depths,progression,,DeepWoods -10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC -10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas -10103,Alec <3,progression,FRIENDSANITY,Alec Revisited -10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba -10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene -10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick -10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) -10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC -10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC -10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley -10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded -10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded -10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded -10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded -10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded -10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded -10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded -10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded -10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded -10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch -10127,Goblin <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods -10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator -10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul -10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul -10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded -10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10503,Iridium Bomb,progression,,Stardew Valley Expanded -10504,Krobus' Protection,useful,,Stardew Valley Expanded -10505,Kittyfish Spell,progression,,Stardew Valley Expanded -10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded -10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded -10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded -10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded -10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded -10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded -10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded -10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10517,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded -10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded -10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded -10520,Morgan's Schooling,progression,,Stardew Valley Expanded -10601,Magic Elixir Recipe,progression,CRAFTSANITY,Magic -10602,Travel Core Recipe,progression,CRAFTSANITY,Magic -10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +id,name,classification,groups,mod_name +0,Joja Cola,filler,TRASH, +15,Rusty Key,progression,, +16,Dwarvish Translation Guide,progression,, +17,Bridge Repair,progression,COMMUNITY_REWARD, +18,Greenhouse,progression,COMMUNITY_REWARD, +19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, +20,Minecarts Repair,useful,COMMUNITY_REWARD, +21,Bus Repair,progression,COMMUNITY_REWARD, +22,Progressive Movie Theater,progression,COMMUNITY_REWARD, +23,Stardrop,progression,, +24,Progressive Backpack,progression,, +25,Rusty Sword,filler,"WEAPON,DEPRECATED", +26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", +27,Work Boots,filler,"FOOTWEAR,DEPRECATED", +28,Wooden Blade,filler,"WEAPON,DEPRECATED", +29,Iron Dirk,filler,"WEAPON,DEPRECATED", +30,Wind Spire,filler,"WEAPON,DEPRECATED", +31,Femur,filler,"WEAPON,DEPRECATED", +32,Steel Smallsword,filler,"WEAPON,DEPRECATED", +33,Wood Club,filler,"WEAPON,DEPRECATED", +34,Elf Blade,filler,"WEAPON,DEPRECATED", +37,Slingshot,filler,"WEAPON,DEPRECATED", +38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", +39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", +40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", +41,Silver Saber,filler,"WEAPON,DEPRECATED", +42,Pirate's Sword,filler,"WEAPON,DEPRECATED", +43,Crystal Dagger,filler,"WEAPON,DEPRECATED", +44,Cutlass,filler,"WEAPON,DEPRECATED", +45,Iron Edge,filler,"WEAPON,DEPRECATED", +46,Burglar's Shank,filler,"WEAPON,DEPRECATED", +47,Wood Mallet,filler,"WEAPON,DEPRECATED", +48,Master Slingshot,filler,"WEAPON,DEPRECATED", +49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", +50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", +51,Claymore,filler,"WEAPON,DEPRECATED", +52,Templar's Blade,filler,"WEAPON,DEPRECATED", +53,Kudgel,filler,"WEAPON,DEPRECATED", +54,Shadow Dagger,filler,"WEAPON,DEPRECATED", +55,Obsidian Edge,filler,"WEAPON,DEPRECATED", +56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", +57,Wicked Kris,filler,"WEAPON,DEPRECATED", +58,Bone Sword,filler,"WEAPON,DEPRECATED", +59,Ossified Blade,filler,"WEAPON,DEPRECATED", +60,Space Boots,filler,"FOOTWEAR,DEPRECATED", +61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", +62,Steel Falchion,filler,"WEAPON,DEPRECATED", +63,The Slammer,filler,"WEAPON,DEPRECATED", +64,Skull Key,progression,, +65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, +66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, +67,Progressive Axe,progression,PROGRESSIVE_TOOLS, +68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, +69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, +70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, +71,Golden Scythe,useful,, +72,Progressive Mine Elevator,progression,, +73,Farming Level,progression,SKILL_LEVEL_UP, +74,Fishing Level,progression,SKILL_LEVEL_UP, +75,Foraging Level,progression,SKILL_LEVEL_UP, +76,Mining Level,progression,SKILL_LEVEL_UP, +77,Combat Level,progression,SKILL_LEVEL_UP, +78,Earth Obelisk,progression,WIZARD_BUILDING, +79,Water Obelisk,progression,WIZARD_BUILDING, +80,Desert Obelisk,progression,WIZARD_BUILDING, +81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", +82,Junimo Hut,useful,WIZARD_BUILDING, +83,Gold Clock,progression,WIZARD_BUILDING, +84,Progressive Coop,progression,BUILDING, +85,Progressive Barn,progression,BUILDING, +86,Well,useful,BUILDING, +87,Silo,progression,BUILDING, +88,Mill,progression,BUILDING, +89,Progressive Shed,progression,BUILDING, +90,Fish Pond,progression,BUILDING, +91,Stable,useful,BUILDING, +92,Slime Hutch,progression,BUILDING, +93,Shipping Bin,progression,BUILDING, +94,Beach Bridge,progression,, +95,Adventurer's Guild,progression,, +96,Club Card,progression,, +97,Magnifying Glass,progression,, +98,Bear's Knowledge,useful,, +99,Iridium Snake Milk,useful,, +100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, +101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, +102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, +103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, +104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, +105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, +106,Galaxy Sword,filler,"WEAPON,DEPRECATED", +107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", +108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", +109,Movement Speed Bonus,progression,, +110,Luck Bonus,progression,, +111,Lava Katana,filler,"WEAPON,DEPRECATED", +112,Progressive House,progression,, +113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, +114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, +115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, +116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, +117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, +118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, +119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, +120,Traveling Merchant Stock Size,useful,, +121,Traveling Merchant Discount,useful,, +122,Return Scepter,useful,, +123,Progressive Season,progression,, +124,Spring,progression,SEASON, +125,Summer,progression,SEASON, +126,Fall,progression,SEASON, +127,Winter,progression,SEASON, +128,Amaranth Seeds,progression,CROPSANITY, +129,Artichoke Seeds,progression,CROPSANITY, +130,Beet Seeds,progression,CROPSANITY, +131,Jazz Seeds,progression,CROPSANITY, +132,Blueberry Seeds,progression,CROPSANITY, +133,Bok Choy Seeds,progression,CROPSANITY, +134,Cauliflower Seeds,progression,CROPSANITY, +135,Corn Seeds,progression,CROPSANITY, +136,Cranberry Seeds,progression,CROPSANITY, +137,Eggplant Seeds,progression,CROPSANITY, +138,Fairy Seeds,progression,CROPSANITY, +139,Garlic Seeds,progression,CROPSANITY, +140,Grape Starter,progression,CROPSANITY, +141,Bean Starter,progression,CROPSANITY, +142,Hops Starter,progression,CROPSANITY, +143,Pepper Seeds,progression,CROPSANITY, +144,Kale Seeds,progression,CROPSANITY, +145,Melon Seeds,progression,CROPSANITY, +146,Parsnip Seeds,progression,CROPSANITY, +147,Poppy Seeds,progression,CROPSANITY, +148,Potato Seeds,progression,CROPSANITY, +149,Pumpkin Seeds,progression,CROPSANITY, +150,Radish Seeds,progression,CROPSANITY, +151,Red Cabbage Seeds,progression,CROPSANITY, +152,Rhubarb Seeds,progression,CROPSANITY, +153,Starfruit Seeds,progression,CROPSANITY, +154,Strawberry Seeds,progression,CROPSANITY, +155,Spangle Seeds,progression,CROPSANITY, +156,Sunflower Seeds,progression,CROPSANITY, +157,Tomato Seeds,progression,CROPSANITY, +158,Tulip Bulb,progression,CROPSANITY, +159,Rice Shoot,progression,CROPSANITY, +160,Wheat Seeds,progression,CROPSANITY, +161,Yam Seeds,progression,CROPSANITY, +162,Cactus Seeds,progression,CROPSANITY, +163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +164,Ancient Seeds Recipe,progression,MUSEUM, +165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +166,Traveling Merchant Metal Detector,progression,MUSEUM, +167,Alex <3,progression,FRIENDSANITY, +168,Elliott <3,progression,FRIENDSANITY, +169,Harvey <3,progression,FRIENDSANITY, +170,Sam <3,progression,FRIENDSANITY, +171,Sebastian <3,progression,FRIENDSANITY, +172,Shane <3,progression,FRIENDSANITY, +173,Abigail <3,progression,FRIENDSANITY, +174,Emily <3,progression,FRIENDSANITY, +175,Haley <3,progression,FRIENDSANITY, +176,Leah <3,progression,FRIENDSANITY, +177,Maru <3,progression,FRIENDSANITY, +178,Penny <3,progression,FRIENDSANITY, +179,Caroline <3,progression,FRIENDSANITY, +180,Clint <3,progression,FRIENDSANITY, +181,Demetrius <3,progression,FRIENDSANITY, +182,Dwarf <3,progression,FRIENDSANITY, +183,Evelyn <3,progression,FRIENDSANITY, +184,George <3,progression,FRIENDSANITY, +185,Gus <3,progression,FRIENDSANITY, +186,Jas <3,progression,FRIENDSANITY, +187,Jodi <3,progression,FRIENDSANITY, +188,Kent <3,progression,FRIENDSANITY, +189,Krobus <3,progression,FRIENDSANITY, +190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", +191,Lewis <3,progression,FRIENDSANITY, +192,Linus <3,progression,FRIENDSANITY, +193,Marnie <3,progression,FRIENDSANITY, +194,Pam <3,progression,FRIENDSANITY, +195,Pierre <3,progression,FRIENDSANITY, +196,Robin <3,progression,FRIENDSANITY, +197,Sandy <3,progression,FRIENDSANITY, +198,Vincent <3,progression,FRIENDSANITY, +199,Willy <3,progression,FRIENDSANITY, +200,Wizard <3,progression,FRIENDSANITY, +201,Pet <3,progression,FRIENDSANITY, +202,Rarecrow #1,progression,"FESTIVAL,RARECROW", +203,Rarecrow #2,progression,"FESTIVAL,RARECROW", +204,Rarecrow #3,progression,"FESTIVAL,RARECROW", +205,Rarecrow #4,progression,"FESTIVAL,RARECROW", +206,Rarecrow #5,progression,"FESTIVAL,RARECROW", +207,Rarecrow #6,progression,"FESTIVAL,RARECROW", +208,Rarecrow #7,progression,"FESTIVAL,RARECROW", +209,Rarecrow #8,progression,"FESTIVAL,RARECROW", +210,Straw Hat,filler,FESTIVAL, +211,Golden Pumpkin,useful,FESTIVAL, +212,Barbed Hook,useful,FESTIVAL, +213,Dressed Spinner,useful,FESTIVAL, +214,Magnet,useful,FESTIVAL, +215,Sailor's Cap,filler,FESTIVAL, +216,Pearl,useful,FESTIVAL, +217,Cone Hat,filler,FESTIVAL, +218,Iridium Fireplace,filler,FESTIVAL, +219,Lupini: Red Eagle,filler,FESTIVAL, +220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, +221,Lupini: Solar Kingdom,filler,FESTIVAL, +222,Lupini: Clouds,filler,FESTIVAL, +223,Lupini: 1000 Years From Now,filler,FESTIVAL, +224,Lupini: Three Trees,filler,FESTIVAL, +225,Lupini: The Serpent,filler,FESTIVAL, +226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, +227,Lupini: Land Of Clay,filler,FESTIVAL, +228,Special Order Board,progression,SPECIAL_ORDER_BOARD, +229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, +230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, +231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, +232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, +233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, +234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, +235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, +236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, +237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, +239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +260,Boat Repair,progression,GINGER_ISLAND, +261,Open Professor Snail Cave,progression,GINGER_ISLAND, +262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", +271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", +275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", +276,Weather Report,useful,TV_CHANNEL, +277,Fortune Teller,useful,TV_CHANNEL, +278,Livin' Off The Land,useful,TV_CHANNEL, +279,The Queen of Sauce,progression,TV_CHANNEL, +280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, +281,Sinister Signal,useful,TV_CHANNEL, +282,Dark Talisman,progression,, +283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, +284,Cute Baby,progression,BABY, +285,Ugly Baby,progression,BABY, +286,Deluxe Scarecrow Recipe,progression,RARECROW, +287,Treehouse,progression,GINGER_ISLAND, +288,Coffee Bean,progression,CROPSANITY, +289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +294,Progressive Footwear,useful,FOOTWEAR, +295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +325,Fairy Dust Recipe,progression,, +326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, +329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +331,Jack-O-Lantern Recipe,progression,FESTIVAL, +332,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, +333,Tub o' Flowers Recipe,progression,FESTIVAL, +334,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, +335,Moonlight Jellies Banner,filler,FESTIVAL, +336,Starport Decal,filler,FESTIVAL, +337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, +371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", +417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +425,Gate Recipe,progression,CRAFTSANITY, +426,Wood Fence Recipe,progression,CRAFTSANITY, +427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +428,Grass Starter Recipe,progression,CRAFTSANITY, +429,Wood Floor Recipe,progression,CRAFTSANITY, +430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, +431,Straw Floor Recipe,progression,CRAFTSANITY, +432,Weathered Floor Recipe,progression,CRAFTSANITY, +433,Crystal Floor Recipe,progression,CRAFTSANITY, +434,Stone Floor Recipe,progression,CRAFTSANITY, +435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, +436,Brick Floor Recipe,progression,CRAFTSANITY, +437,Wood Path Recipe,progression,CRAFTSANITY, +438,Gravel Path Recipe,progression,CRAFTSANITY, +439,Cobblestone Path Recipe,progression,CRAFTSANITY, +440,Stepping Stone Path Recipe,progression,CRAFTSANITY, +441,Crystal Path Recipe,progression,CRAFTSANITY, +442,Wedding Ring Recipe,progression,CRAFTSANITY, +443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, +444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +445,Torch Recipe,progression,CRAFTSANITY, +446,Campfire Recipe,progression,CRAFTSANITY, +447,Wooden Brazier Recipe,progression,CRAFTSANITY, +448,Stone Brazier Recipe,progression,CRAFTSANITY, +449,Gold Brazier Recipe,progression,CRAFTSANITY, +450,Carved Brazier Recipe,progression,CRAFTSANITY, +451,Stump Brazier Recipe,progression,CRAFTSANITY, +452,Barrel Brazier Recipe,progression,CRAFTSANITY, +453,Skull Brazier Recipe,progression,CRAFTSANITY, +454,Marble Brazier Recipe,progression,CRAFTSANITY, +455,Wood Lamp-post Recipe,progression,CRAFTSANITY, +456,Iron Lamp-post Recipe,progression,CRAFTSANITY, +457,Furnace Recipe,progression,CRAFTSANITY, +458,Wicked Statue Recipe,progression,CRAFTSANITY, +459,Chest Recipe,progression,CRAFTSANITY, +460,Wood Sign Recipe,progression,CRAFTSANITY, +461,Stone Sign Recipe,progression,CRAFTSANITY, +462,Standard Farm,progression,FARM_TYPE, +463,Riverland Farm,progression,FARM_TYPE, +464,Forest Farm,progression,FARM_TYPE, +465,Hill-top Farm,progression,FARM_TYPE, +466,Wilderness Farm,progression,FARM_TYPE, +467,Four Corners Farm,progression,FARM_TYPE, +468,Beach Farm,progression,FARM_TYPE, +469,Railroad Boulder Removed,progression,, +4001,Burnt,trap,TRAP, +4002,Darkness,trap,TRAP, +4003,Frozen,trap,TRAP, +4004,Jinxed,trap,TRAP, +4005,Nauseated,trap,TRAP, +4006,Slimed,trap,TRAP, +4007,Weakness,trap,TRAP, +4008,Taxes,trap,TRAP, +4009,Random Teleport,trap,TRAP, +4010,The Crows,trap,TRAP, +4011,Monsters,trap,TRAP, +4012,Entrance Reshuffle,trap,"TRAP,DEPRECATED", +4013,Debris,trap,TRAP, +4014,Shuffle,trap,TRAP, +4015,Temporary Winter,trap,"TRAP,DEPRECATED", +4016,Pariah,trap,TRAP, +4017,Drought,trap,TRAP, +5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", +5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", +5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", +5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", +5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", +5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", +5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", +5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", +5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", +5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM", +5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", +5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", +5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", +5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", +5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", +5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", +5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", +5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", +5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", +5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", +5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", +5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", +5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", +5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", +5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", +5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", +5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", +5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", +5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", +5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5207,Fiber Seeds,filler,RESOURCE_PACK, +5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5210,Quality Bobber,filler,RESOURCE_PACK, +5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", +5212,Monster Musk,filler,RESOURCE_PACK, +5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5216,Scarecrow,filler,RESOURCE_PACK, +5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", +5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", +5236,Aquatic Sanctuary,filler,RESOURCE_PACK, +5242,Exotic Double Bed,filler,RESOURCE_PACK, +5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", +5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", +5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5262,Slime Incubator,useful,RESOURCE_PACK, +5263,Slime Egg-Press,useful,RESOURCE_PACK, +5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill +10002,Magic Level,progression,SKILL_LEVEL_UP,Magic +10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill +10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology +10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill +10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill +10007,Tractor Garage,useful,,Tractor Mod +10008,Woods Obelisk,progression,,DeepWoods +10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic +10010,Spell: Till,useful,MAGIC_SPELL,Magic +10011,Spell: Water,progression,MAGIC_SPELL,Magic +10012,Spell: Blink,progression,MAGIC_SPELL,Magic +10013,Spell: Evac,useful,MAGIC_SPELL,Magic +10014,Spell: Haste,filler,MAGIC_SPELL,Magic +10015,Spell: Heal,progression,MAGIC_SPELL,Magic +10016,Spell: Buff,useful,MAGIC_SPELL,Magic +10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic +10018,Spell: Fireball,progression,MAGIC_SPELL,Magic +10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic +10020,Spell: Teleport,progression,MAGIC_SPELL,Magic +10021,Spell: Lantern,filler,MAGIC_SPELL,Magic +10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic +10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic +10024,Spell: Descend,progression,MAGIC_SPELL,Magic +10025,Spell: Meteor,progression,MAGIC_SPELL,Magic +10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic +10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic +10028,Spell: Spirit,progression,MAGIC_SPELL,Magic +10029,Spell: Rewind,useful,MAGIC_SPELL,Magic +10030,Pendant of Community,progression,,DeepWoods +10031,Pendant of Elders,progression,,DeepWoods +10032,Pendant of Depths,progression,,DeepWoods +10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC +10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas +10103,Alec <3,progression,FRIENDSANITY,Alec Revisited +10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba +10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene +10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick +10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) +10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC +10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC +10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley +10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded +10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded +10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded +10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded +10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded +10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded +10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded +10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded +10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch +10127,Goblin <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods +10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator +10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul +10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul +10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded +10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10503,Iridium Bomb,progression,,Stardew Valley Expanded +10504,Krobus' Protection,useful,,Stardew Valley Expanded +10505,Kittyfish Spell,progression,,Stardew Valley Expanded +10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded +10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded +10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded +10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded +10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded +10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10517,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded +10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded +10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded +10520,Morgan's Schooling,progression,,Stardew Valley Expanded +10601,Magic Elixir Recipe,progression,CRAFTSANITY,Magic +10602,Travel Core Recipe,progression,CRAFTSANITY,Magic +10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index ad3b07354345..5a43e8e617fd 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1,2815 +1,2815 @@ -id,region,name,tags,mod_name -1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", -32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", -34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", -35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", -37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", -40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -80,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -84,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -85,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -87,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -88,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -92,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -93,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -94,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -95,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -101,Pierre's General Store,Large Pack,BACKPACK, -102,Pierre's General Store,Deluxe Pack,BACKPACK, -103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", -202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", -203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", -204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", -205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", -206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", -207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", -208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", -209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", -210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", -211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", -212,Quarry Mine,Grim Reaper statue,MANDATORY, -213,The Mines,The Mines Entrance Cutscene,MANDATORY, -214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, -215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, -216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, -217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, -218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, -219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, -220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, -221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, -222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, -223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, -224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, -225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, -226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, -227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, -228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, -229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, -230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, -231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, -232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, -233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, -234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, -235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, -236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, -237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, -251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", -301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", -302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", -303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", -304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", -305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", -306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", -307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", -308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", -309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", -310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", -311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", -332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", -333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", -334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", -335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", -336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", -337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", -338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", -339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", -340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", -341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, -402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, -403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, -404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, -405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, -406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, -407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, -408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, -409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, -410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, -411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, -412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, -413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, -414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, -415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, -416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, -417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, -418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, -501,Town,Introductions,"MANDATORY,QUEST", -502,Town,How To Win Friends,"MANDATORY,QUEST", -503,Farm,Getting Started,"MANDATORY,QUEST", -504,Farm,Raising Animals,"MANDATORY,QUEST", -505,Farm,Advancement,"MANDATORY,QUEST", -506,Museum,Archaeology,"MANDATORY,QUEST", -507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", -508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", -509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", -510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", -511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", -512,Sam's House,Jodi's Request,"MANDATORY,QUEST", -513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", -514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", -515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", -516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", -517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", -518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", -519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", -520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", -521,Alex's House,Knee Therapy,"MANDATORY,QUEST", -522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", -523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", -524,Desert,The Mysterious Qi,"MANDATORY,QUEST", -525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", -526,Town,A Winter Mystery,"MANDATORY,QUEST", -527,Secret Woods,Strange Note,"MANDATORY,QUEST", -528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", -529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", -530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", -531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", -532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", -533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", -534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", -535,Sam's House,Fish Casserole,"MANDATORY,QUEST", -536,Fishing,Catch A Squid,"MANDATORY,QUEST", -537,Saloon,Fish Stew,"MANDATORY,QUEST", -538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", -539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", -540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", -541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", -542,Alex's House,Granny's Gift,"MANDATORY,QUEST", -543,Desert,Exotic Spirits,"MANDATORY,QUEST", -544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", -545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Mutant Bug Lair,Dark Talisman,"MANDATORY,QUEST", -547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", -548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", -601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", -602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", -603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", -604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", -605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", -606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", -607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", -608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", -609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", -610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", -611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", -612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", -613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", -614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", -615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", -616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", -617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", -618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", -619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", -620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", -621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", -701,Secret Woods,Old Master Cannoli,MANDATORY, -702,Beach,Beach Bridge Repair,MANDATORY, -703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,BABY, -705,Farmhouse,Have Another Baby,BABY, -706,Farmhouse,Spouse Stardrop,, -707,Sewer,Krobus Stardrop,MANDATORY, -801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, -802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, -803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, -804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, -805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, -806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, -807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, -808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, -811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, -821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, -822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, -823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, -824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, -825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, -826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, -827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, -828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, -841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, -842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, -843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, -844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, -845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, -846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, -847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, -848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, -849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, -850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, -851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, -852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, -853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, -854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, -855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, -856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, -857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, -858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, -859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, -860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, -861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, -862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, -863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, -864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, -865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, -866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, -867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, -868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, -869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, -870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, -871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, -872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, -901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", -902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", -903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", -911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", -912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", -913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", -921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", -942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", -943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", -951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", -952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", -953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", -961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", -962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", -963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", -1001,Fishing,Fishsanity: Carp,FISHSANITY, -1002,Fishing,Fishsanity: Herring,FISHSANITY, -1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, -1004,Fishing,Fishsanity: Anchovy,FISHSANITY, -1005,Fishing,Fishsanity: Sardine,FISHSANITY, -1006,Fishing,Fishsanity: Sunfish,FISHSANITY, -1007,Fishing,Fishsanity: Perch,FISHSANITY, -1008,Fishing,Fishsanity: Chub,FISHSANITY, -1009,Fishing,Fishsanity: Bream,FISHSANITY, -1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, -1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, -1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, -1013,Fishing,Fishsanity: Walleye,FISHSANITY, -1014,Fishing,Fishsanity: Shad,FISHSANITY, -1015,Fishing,Fishsanity: Bullhead,FISHSANITY, -1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, -1017,Fishing,Fishsanity: Salmon,FISHSANITY, -1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, -1019,Fishing,Fishsanity: Tilapia,FISHSANITY, -1020,Fishing,Fishsanity: Woodskip,FISHSANITY, -1021,Fishing,Fishsanity: Flounder,FISHSANITY, -1022,Fishing,Fishsanity: Halibut,FISHSANITY, -1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", -1024,Fishing,Fishsanity: Slimejack,FISHSANITY, -1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, -1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, -1027,Fishing,Fishsanity: Pike,FISHSANITY, -1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, -1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", -1030,Fishing,Fishsanity: Albacore,FISHSANITY, -1031,Fishing,Fishsanity: Sandfish,FISHSANITY, -1032,Fishing,Fishsanity: Stonefish,FISHSANITY, -1033,Fishing,Fishsanity: Tuna,FISHSANITY, -1034,Fishing,Fishsanity: Eel,FISHSANITY, -1035,Fishing,Fishsanity: Catfish,FISHSANITY, -1036,Fishing,Fishsanity: Squid,FISHSANITY, -1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, -1038,Fishing,Fishsanity: Dorado,FISHSANITY, -1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, -1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, -1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, -1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", -1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, -1044,Fishing,Fishsanity: Lingcod,FISHSANITY, -1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, -1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, -1047,Fishing,Fishsanity: Octopus,FISHSANITY, -1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, -1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, -1050,Fishing,Fishsanity: Blobfish,FISHSANITY, -1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, -1052,Fishing,Fishsanity: Angler,FISHSANITY, -1053,Fishing,Fishsanity: Legend,FISHSANITY, -1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, -1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, -1056,Town,Fishsanity: Crayfish,FISHSANITY, -1057,Town,Fishsanity: Snail,FISHSANITY, -1058,Town,Fishsanity: Periwinkle,FISHSANITY, -1059,Beach,Fishsanity: Lobster,FISHSANITY, -1060,Beach,Fishsanity: Clam,FISHSANITY, -1061,Beach,Fishsanity: Crab,FISHSANITY, -1062,Beach,Fishsanity: Cockle,FISHSANITY, -1063,Beach,Fishsanity: Mussel,FISHSANITY, -1064,Beach,Fishsanity: Shrimp,FISHSANITY, -1065,Beach,Fishsanity: Oyster,FISHSANITY, -1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, -1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, -1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, -1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, -1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, -1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, -1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, -1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, -1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, -1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, -1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, -1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, -1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, -1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, -1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, -1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, -1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, -1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, -1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, -1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, -1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, -1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, -1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, -1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, -1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, -1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, -1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, -1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, -1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, -1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, -1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, -1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, -1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, -1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, -1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, -1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, -1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, -1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, -1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, -1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, -1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, -1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, -1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, -1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, -1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, -1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, -1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", -1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, -1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, -1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, -1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, -1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, -1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, -1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, -1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, -1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, -1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, -1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, -1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, -1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, -1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, -1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, -1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, -1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, -1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, -1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, -1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, -1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, -1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, -1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, -1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, -1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, -1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, -1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, -1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, -1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, -1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, -1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, -1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, -1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, -1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, -1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, -1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, -1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, -1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, -1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, -1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, -1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, -1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, -1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, -1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, -1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, -1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, -1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, -1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, -1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, -1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, -1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, -1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, -1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, -1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, -1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, -1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, -1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, -1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, -1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, -1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, -1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, -1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, -1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, -1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, -1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, -1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, -1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, -1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, -1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, -1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, -1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, -1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, -1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, -1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, -1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, -1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, -1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, -1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, -1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, -1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, -1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, -1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, -1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, -1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, -1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, -1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, -1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, -1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, -1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, -1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, -1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, -1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, -1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, -1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, -1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, -1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, -1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, -1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, -1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, -1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, -1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, -1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, -1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, -1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, -1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, -1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, -1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, -1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, -1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, -1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, -1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, -1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, -1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, -1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, -1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, -1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, -1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, -1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, -1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, -1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, -1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, -1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, -1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, -1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, -1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, -1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, -1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, -1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, -1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, -1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, -1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, -1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, -1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, -1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, -1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, -1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, -1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, -1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, -1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, -1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, -1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, -1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, -1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, -1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, -1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, -1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, -1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, -1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, -1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, -1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, -1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, -1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, -1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, -1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, -1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, -1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, -1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, -1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, -1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, -1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, -1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, -1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, -1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, -1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, -1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, -1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, -1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, -1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, -1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, -1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, -1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, -1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, -1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, -1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, -1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, -1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, -1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, -1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, -1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, -1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, -1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, -1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, -1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, -1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, -1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, -1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, -1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, -1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, -1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, -1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, -1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, -1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, -1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, -1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, -1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, -1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, -1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, -1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, -1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, -1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, -1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, -1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, -1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, -1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, -1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, -1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, -1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, -1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, -1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, -1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, -1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, -1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, -1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, -1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, -1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, -1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, -1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, -1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, -1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, -1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, -1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, -1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, -1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, -1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, -1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, -1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, -1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, -1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, -1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, -1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, -1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, -1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, -1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, -1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, -1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, -1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, -1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, -1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, -1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, -1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, -1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, -1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, -1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, -1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, -1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, -1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, -1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, -1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, -1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, -1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, -1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, -1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, -1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, -1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, -1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, -1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, -1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, -1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, -1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, -1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, -1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, -1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, -1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, -1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, -1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, -1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, -1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, -1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, -1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, -1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, -1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, -1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, -1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, -1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, -1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, -1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, -1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, -1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, -1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, -1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, -1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, -1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, -1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, -1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, -1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, -1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, -1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, -1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, -1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, -1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, -1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, -1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, -1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, -1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, -1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, -1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, -1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, -1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, -1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, -1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, -1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, -1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, -1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, -1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, -1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, -1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, -1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, -1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, -1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, -1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, -1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, -1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, -1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, -1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, -1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, -1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, -1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, -1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, -1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, -1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, -1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, -1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, -1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, -1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, -1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, -1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, -1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, -1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, -1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, -1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, -1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, -1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, -1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, -1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, -1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, -1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, -1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, -1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, -1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, -1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, -1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, -1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, -1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, -1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, -1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, -1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, -1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, -1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, -1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, -1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, -1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, -1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, -1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, -1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, -1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", -1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", -1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", -1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", -1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", -1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", -1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", -1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", -1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", -1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", -1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, -1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, -1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, -1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, -1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, -1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, -1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, -1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, -1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, -1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, -1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, -1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, -1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, -1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, -1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, -1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, -1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, -1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, -1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, -1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, -1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, -1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, -1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, -1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, -1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, -1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, -1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, -1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, -1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, -1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, -1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, -1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, -1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, -1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, -1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, -1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, -1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, -1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, -1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, -1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, -1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, -1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, -1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, -1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, -1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, -1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, -1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, -1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, -1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, -1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, -1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, -1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, -1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, -1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, -1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, -1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, -1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, -1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, -1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, -1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, -1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, -1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, -1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, -1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, -1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, -1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, -1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, -1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, -1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, -1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, -1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, -1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, -1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, -1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, -1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, -1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, -1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, -1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, -1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, -1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, -1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, -1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, -1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, -1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, -1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, -1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, -1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, -1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, -1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, -1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, -1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, -1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, -1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, -1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, -1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, -1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, -1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, -1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, -1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, -1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, -1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, -1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, -1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, -1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, -1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, -1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, -1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, -1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, -1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, -1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, -1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, -1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, -1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, -1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, -1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, -1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, -1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, -1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, -1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, -2001,Egg Festival,Egg Hunt Victory,FESTIVAL, -2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, -2003,Flower Dance,Dance with someone,FESTIVAL, -2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, -2005,Luau,Luau Soup,FESTIVAL, -2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, -2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, -2008,Stardew Valley Fair,Grange Display,FESTIVAL, -2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, -2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, -2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, -2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, -2013,Festival of Ice,Win Fishing Competition,FESTIVAL, -2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, -2015,Night Market,Mermaid Pearl,FESTIVAL, -2016,Night Market,Cone Hat,FESTIVAL_HARD, -2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, -2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, -2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, -2020,Night Market,Lupini: Red Eagle,FESTIVAL, -2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, -2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, -2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, -2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, -2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, -2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, -2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, -2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, -2029,Feast of the Winter Star,Secret Santa,FESTIVAL, -2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, -2031,Farm,Collect All Rarecrows,FESTIVAL, -2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, -2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, -2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, -2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, -2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, -2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, -2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, -2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, -2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, -2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, -2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, -2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, -2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, -2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, -2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, -2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, -2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, -2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, -2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, -2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", -2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, -2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, -2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, -2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", -2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", -2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", -2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", -2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", -2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", -2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", -2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", -2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", -2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, -2216,Field Office,Complete Island Field Office,GINGER_ISLAND, -2301,Farming,Harvest Amaranth,CROPSANITY, -2302,Farming,Harvest Artichoke,CROPSANITY, -2303,Farming,Harvest Beet,CROPSANITY, -2304,Farming,Harvest Blue Jazz,CROPSANITY, -2305,Farming,Harvest Blueberry,CROPSANITY, -2306,Farming,Harvest Bok Choy,CROPSANITY, -2307,Farming,Harvest Cauliflower,CROPSANITY, -2308,Farming,Harvest Corn,CROPSANITY, -2309,Farming,Harvest Cranberries,CROPSANITY, -2310,Farming,Harvest Eggplant,CROPSANITY, -2311,Farming,Harvest Fairy Rose,CROPSANITY, -2312,Farming,Harvest Garlic,CROPSANITY, -2313,Farming,Harvest Grape,CROPSANITY, -2314,Farming,Harvest Green Bean,CROPSANITY, -2315,Farming,Harvest Hops,CROPSANITY, -2316,Farming,Harvest Hot Pepper,CROPSANITY, -2317,Farming,Harvest Kale,CROPSANITY, -2318,Farming,Harvest Melon,CROPSANITY, -2319,Farming,Harvest Parsnip,CROPSANITY, -2320,Farming,Harvest Poppy,CROPSANITY, -2321,Farming,Harvest Potato,CROPSANITY, -2322,Farming,Harvest Pumpkin,CROPSANITY, -2323,Farming,Harvest Radish,CROPSANITY, -2324,Farming,Harvest Red Cabbage,CROPSANITY, -2325,Farming,Harvest Rhubarb,CROPSANITY, -2326,Farming,Harvest Starfruit,CROPSANITY, -2327,Farming,Harvest Strawberry,CROPSANITY, -2328,Farming,Harvest Summer Spangle,CROPSANITY, -2329,Farming,Harvest Sunflower,CROPSANITY, -2330,Farming,Harvest Tomato,CROPSANITY, -2331,Farming,Harvest Tulip,CROPSANITY, -2332,Farming,Harvest Unmilled Rice,CROPSANITY, -2333,Farming,Harvest Wheat,CROPSANITY, -2334,Farming,Harvest Yam,CROPSANITY, -2335,Farming,Harvest Cactus Fruit,CROPSANITY, -2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", -2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, -2339,Farming,Harvest Apple,CROPSANITY, -2340,Farming,Harvest Apricot,CROPSANITY, -2341,Farming,Harvest Cherry,CROPSANITY, -2342,Farming,Harvest Orange,CROPSANITY, -2343,Farming,Harvest Pomegranate,CROPSANITY, -2344,Farming,Harvest Peach,CROPSANITY, -2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", -2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farming,Harvest Coffee Bean,CROPSANITY, -2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2416,Shipping,Shipsanity: Anchor,SHIPSANITY, -2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, -2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, -2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, -2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, -2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, -2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, -2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, -2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, -2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, -2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, -2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, -2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, -2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, -2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, -2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, -2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, -2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, -2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, -2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, -2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, -2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, -2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, -2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, -2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, -2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, -2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, -2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, -2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, -2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, -2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, -2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, -2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, -2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2454,Shipping,Shipsanity: Coffee,SHIPSANITY, -2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, -2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, -2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, -2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, -2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, -2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, -2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, -2479,Shipping,Shipsanity: Bread,SHIPSANITY, -2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, -2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, -2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, -2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, -2484,Shipping,Shipsanity: Chowder,SHIPSANITY, -2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, -2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Shipping,Shipsanity: Cookies,SHIPSANITY, -2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, -2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, -2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, -2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, -2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, -2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, -2494,Shipping,Shipsanity: Escargot,SHIPSANITY, -2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, -2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, -2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, -2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, -2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, -2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, -2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, -2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, -2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, -2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, -2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, -2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, -2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, -2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, -2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, -2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, -2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, -2512,Shipping,Shipsanity: Omelet,SHIPSANITY, -2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, -2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, -2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, -2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, -2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, -2518,Shipping,Shipsanity: Pizza,SHIPSANITY, -2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, -2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, -2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, -2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, -2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, -2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, -2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, -2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, -2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, -2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, -2529,Shipping,Shipsanity: Salad,SHIPSANITY, -2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, -2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, -2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, -2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, -2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, -2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, -2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, -2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, -2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, -2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, -2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, -2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, -2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, -2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, -2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, -2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, -2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, -2547,Shipping,Shipsanity: Bait,SHIPSANITY, -2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, -2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, -2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, -2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, -2552,Shipping,Shipsanity: Bomb,SHIPSANITY, -2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, -2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, -2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, -2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, -2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, -2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, -2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, -2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, -2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, -2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, -2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, -2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, -2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, -2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, -2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, -2569,Shipping,Shipsanity: Gate,SHIPSANITY, -2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, -2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, -2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, -2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, -2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, -2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, -2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, -2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, -2578,Shipping,Shipsanity: Magnet,SHIPSANITY, -2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, -2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, -2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, -2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, -2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, -2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, -2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, -2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, -2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, -2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, -2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, -2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, -2591,Shipping,Shipsanity: Spinner,SHIPSANITY, -2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, -2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, -2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, -2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, -2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, -2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, -2598,Shipping,Shipsanity: Torch,SHIPSANITY, -2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, -2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, -2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, -2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, -2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, -2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", -2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, -2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, -2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, -2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, -2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, -2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", -2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", -2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", -2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", -2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", -2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", -2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", -2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", -2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", -2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", -2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", -2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", -2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", -2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", -2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", -2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", -2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", -2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", -2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", -2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", -2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", -2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", -2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", -2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", -2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", -2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", -2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", -2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", -2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", -2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", -2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", -2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", -2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", -2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", -2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", -2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", -2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", -2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", -2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", -2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", -2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", -2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", -2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", -2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", -2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", -2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", -2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", -2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", -2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", -2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", -2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", -2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", -2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", -2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", -2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", -2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, -2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2755,Shipping,Shipsanity: Oil,SHIPSANITY, -2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2757,Shipping,Shipsanity: Rice,SHIPSANITY, -2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2760,Shipping,Shipsanity: Sugar,SHIPSANITY, -2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, -2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, -2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, -2765,Shipping,Shipsanity: Alamite,SHIPSANITY, -2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, -2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, -2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, -2769,Shipping,Shipsanity: Baryte,SHIPSANITY, -2770,Shipping,Shipsanity: Basalt,SHIPSANITY, -2771,Shipping,Shipsanity: Bixite,SHIPSANITY, -2772,Shipping,Shipsanity: Calcite,SHIPSANITY, -2773,Shipping,Shipsanity: Celestine,SHIPSANITY, -2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2776,Shipping,Shipsanity: Diamond,SHIPSANITY, -2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, -2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, -2779,Shipping,Shipsanity: Emerald,SHIPSANITY, -2780,Shipping,Shipsanity: Esperite,SHIPSANITY, -2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, -2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, -2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, -2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, -2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, -2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, -2787,Shipping,Shipsanity: Geminite,SHIPSANITY, -2788,Shipping,Shipsanity: Geode,SHIPSANITY, -2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, -2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2791,Shipping,Shipsanity: Granite,SHIPSANITY, -2792,Shipping,Shipsanity: Helvite,SHIPSANITY, -2793,Shipping,Shipsanity: Hematite,SHIPSANITY, -2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2796,Shipping,Shipsanity: Jade,SHIPSANITY, -2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, -2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, -2799,Shipping,Shipsanity: Jasper,SHIPSANITY, -2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, -2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, -2802,Shipping,Shipsanity: Limestone,SHIPSANITY, -2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, -2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, -2805,Shipping,Shipsanity: Malachite,SHIPSANITY, -2806,Shipping,Shipsanity: Marble,SHIPSANITY, -2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, -2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, -2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, -2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, -2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, -2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, -2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, -2814,Shipping,Shipsanity: Opal,SHIPSANITY, -2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, -2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, -2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, -2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, -2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, -2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, -2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, -2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, -2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, -2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, -2825,Shipping,Shipsanity: Quartz,SHIPSANITY, -2826,Shipping,Shipsanity: Ruby,SHIPSANITY, -2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, -2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, -2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, -2830,Shipping,Shipsanity: Slate,SHIPSANITY, -2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, -2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, -2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, -2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, -2835,Shipping,Shipsanity: Topaz,SHIPSANITY, -2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, -2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", -2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, -2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, -2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, -2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, -2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, -2848,Shipping,Shipsanity: Hay,SHIPSANITY, -2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, -2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, -2851,Shipping,Shipsanity: Pearl,SHIPSANITY, -2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, -2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, -2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, -2855,Shipping,Shipsanity: White Algae,SHIPSANITY, -2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, -2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, -2858,Shipping,Shipsanity: Acorn,SHIPSANITY, -2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, -2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, -2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, -2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, -2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, -2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, -2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, -2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, -2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, -2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, -2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, -2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, -2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, -2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, -2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, -2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, -2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, -2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, -2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, -2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, -2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, -2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, -2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, -2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, -2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, -2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, -2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, -2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, -2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, -2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, -2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, -2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, -2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, -2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, -2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, -2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, -2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, -2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, -2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, -2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, -2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, -2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, -2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, -2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, -2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, -2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, -2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, -2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, -2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, -2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, -2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, -2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, -2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, -2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, -2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, -2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, -2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, -2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, -2918,Shipping,Shipsanity: Trash,SHIPSANITY, -2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, -2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", -2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", -2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", -2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", -2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", -2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", -2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", -2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", -2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", -2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", -2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", -2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", -2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", -2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", -2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", -2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", -2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", -2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", -2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", -2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", -2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", -2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Shipping,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", -2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", -2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", -2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", -2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", -2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", -3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", -3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", -3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", -3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", -3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", -3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", -3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", -3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", -3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", -3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", -3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3201,Kitchen,Cook Algae Soup,COOKSANITY, -3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", -3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, -3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", -3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", -3206,Kitchen,Cook Bean Hotpot,COOKSANITY, -3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", -3208,Kitchen,Cook Blueberry Tart,COOKSANITY, -3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", -3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", -3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", -3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, -3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", -3214,Kitchen,Cook Chowder,COOKSANITY, -3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", -3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", -3217,Kitchen,Cook Cookies,COOKSANITY, -3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", -3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", -3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, -3221,Kitchen,Cook Crispy Bass,COOKSANITY, -3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, -3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, -3224,Kitchen,Cook Escargot,COOKSANITY, -3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, -3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", -3227,Kitchen,Cook Fish Stew,COOKSANITY, -3228,Kitchen,Cook Fish Taco,COOKSANITY, -3229,Kitchen,Cook Fried Calamari,COOKSANITY, -3230,Kitchen,Cook Fried Eel,COOKSANITY, -3231,Kitchen,Cook Fried Egg,COOKSANITY, -3232,Kitchen,Cook Fried Mushroom,COOKSANITY, -3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", -3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", -3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", -3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", -3237,Kitchen,Cook Ice Cream,COOKSANITY, -3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", -3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", -3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", -3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", -3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", -3243,Kitchen,Cook Miner's Treat,COOKSANITY, -3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", -3245,Kitchen,Cook Pale Broth,COOKSANITY, -3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", -3247,Kitchen,Cook Parsnip Soup,COOKSANITY, -3248,Kitchen,Cook Pepper Poppers,COOKSANITY, -3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", -3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", -3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", -3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", -3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", -3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", -3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, -3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", -3257,Kitchen,Cook Red Plate,COOKSANITY, -3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, -3259,Kitchen,Cook Rice Pudding,COOKSANITY, -3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", -3261,Kitchen,Cook Roots Platter,COOKSANITY, -3262,Kitchen,Cook Salad,COOKSANITY, -3263,Kitchen,Cook Salmon Dinner,COOKSANITY, -3264,Kitchen,Cook Sashimi,COOKSANITY, -3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, -3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", -3267,Kitchen,Cook Spaghetti,COOKSANITY, -3268,Kitchen,Cook Spicy Eel,COOKSANITY, -3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, -3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", -3271,Kitchen,Cook Strange Bun,COOKSANITY, -3272,Kitchen,Cook Stuffing,COOKSANITY, -3273,Kitchen,Cook Super Meal,COOKSANITY, -3274,Kitchen,Cook Survival Burger,COOKSANITY, -3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, -3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", -3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, -3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", -3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", -3280,Kitchen,Cook Vegetable Medley,COOKSANITY, -3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, -3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", -3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3401,Farm,Craft Cherry Bomb,CRAFTSANITY, -3402,Farm,Craft Bomb,CRAFTSANITY, -3403,Farm,Craft Mega Bomb,CRAFTSANITY, -3404,Farm,Craft Gate,CRAFTSANITY, -3405,Farm,Craft Wood Fence,CRAFTSANITY, -3406,Farm,Craft Stone Fence,CRAFTSANITY, -3407,Farm,Craft Iron Fence,CRAFTSANITY, -3408,Farm,Craft Hardwood Fence,CRAFTSANITY, -3409,Farm,Craft Sprinkler,CRAFTSANITY, -3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, -3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, -3412,Farm,Craft Bee House,CRAFTSANITY, -3413,Farm,Craft Cask,CRAFTSANITY, -3414,Farm,Craft Cheese Press,CRAFTSANITY, -3415,Farm,Craft Keg,CRAFTSANITY, -3416,Farm,Craft Loom,CRAFTSANITY, -3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, -3418,Farm,Craft Oil Maker,CRAFTSANITY, -3419,Farm,Craft Preserves Jar,CRAFTSANITY, -3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, -3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, -3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, -3423,Farm,Craft Speed-Gro,CRAFTSANITY, -3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, -3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", -3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, -3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, -3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", -3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, -3430,Farm,Craft Spring Seeds,CRAFTSANITY, -3431,Farm,Craft Summer Seeds,CRAFTSANITY, -3432,Farm,Craft Fall Seeds,CRAFTSANITY, -3433,Farm,Craft Winter Seeds,CRAFTSANITY, -3434,Farm,Craft Ancient Seeds,CRAFTSANITY, -3435,Farm,Craft Grass Starter,CRAFTSANITY, -3436,Farm,Craft Tea Sapling,CRAFTSANITY, -3437,Farm,Craft Fiber Seeds,CRAFTSANITY, -3438,Farm,Craft Wood Floor,CRAFTSANITY, -3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, -3440,Farm,Craft Straw Floor,CRAFTSANITY, -3441,Farm,Craft Weathered Floor,CRAFTSANITY, -3442,Farm,Craft Crystal Floor,CRAFTSANITY, -3443,Farm,Craft Stone Floor,CRAFTSANITY, -3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, -3445,Farm,Craft Brick Floor,CRAFTSANITY, -3446,Farm,Craft Wood Path,CRAFTSANITY, -3447,Farm,Craft Gravel Path,CRAFTSANITY, -3448,Farm,Craft Cobblestone Path,CRAFTSANITY, -3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, -3450,Farm,Craft Crystal Path,CRAFTSANITY, -3451,Farm,Craft Spinner,CRAFTSANITY, -3452,Farm,Craft Trap Bobber,CRAFTSANITY, -3453,Farm,Craft Cork Bobber,CRAFTSANITY, -3454,Farm,Craft Quality Bobber,CRAFTSANITY, -3455,Farm,Craft Treasure Hunter,CRAFTSANITY, -3456,Farm,Craft Dressed Spinner,CRAFTSANITY, -3457,Farm,Craft Barbed Hook,CRAFTSANITY, -3458,Farm,Craft Magnet,CRAFTSANITY, -3459,Farm,Craft Bait,CRAFTSANITY, -3460,Farm,Craft Wild Bait,CRAFTSANITY, -3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", -3462,Farm,Craft Crab Pot,CRAFTSANITY, -3463,Farm,Craft Sturdy Ring,CRAFTSANITY, -3464,Farm,Craft Warrior Ring,CRAFTSANITY, -3465,Farm,Craft Ring of Yoba,CRAFTSANITY, -3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", -3467,Farm,Craft Glowstone Ring,CRAFTSANITY, -3468,Farm,Craft Iridium Band,CRAFTSANITY, -3469,Farm,Craft Wedding Ring,CRAFTSANITY, -3470,Farm,Craft Field Snack,CRAFTSANITY, -3471,Farm,Craft Bug Steak,CRAFTSANITY, -3472,Farm,Craft Life Elixir,CRAFTSANITY, -3473,Farm,Craft Oil of Garlic,CRAFTSANITY, -3474,Farm,Craft Monster Musk,CRAFTSANITY, -3475,Farm,Craft Fairy Dust,CRAFTSANITY, -3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, -3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, -3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, -3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, -3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", -3481,Farm,Craft Rain Totem,CRAFTSANITY, -3482,Farm,Craft Torch,CRAFTSANITY, -3483,Farm,Craft Campfire,CRAFTSANITY, -3484,Farm,Craft Wooden Brazier,CRAFTSANITY, -3485,Farm,Craft Stone Brazier,CRAFTSANITY, -3486,Farm,Craft Gold Brazier,CRAFTSANITY, -3487,Farm,Craft Carved Brazier,CRAFTSANITY, -3488,Farm,Craft Stump Brazier,CRAFTSANITY, -3489,Farm,Craft Barrel Brazier,CRAFTSANITY, -3490,Farm,Craft Skull Brazier,CRAFTSANITY, -3491,Farm,Craft Marble Brazier,CRAFTSANITY, -3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, -3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, -3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, -3495,Farm,Craft Bone Mill,CRAFTSANITY, -3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, -3497,Farm,Craft Crystalarium,CRAFTSANITY, -3498,Farm,Craft Furnace,CRAFTSANITY, -3499,Farm,Craft Geode Crusher,CRAFTSANITY, -3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", -3501,Farm,Craft Lightning Rod,CRAFTSANITY, -3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", -3503,Farm,Craft Recycling Machine,CRAFTSANITY, -3504,Farm,Craft Seed Maker,CRAFTSANITY, -3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, -3506,Farm,Craft Slime Incubator,CRAFTSANITY, -3507,Farm,Craft Solar Panel,CRAFTSANITY, -3508,Farm,Craft Tapper,CRAFTSANITY, -3509,Farm,Craft Worm Bin,CRAFTSANITY, -3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, -3511,Farm,Craft Wicked Statue,CRAFTSANITY, -3512,Farm,Craft Flute Block,CRAFTSANITY, -3513,Farm,Craft Drum Block,CRAFTSANITY, -3514,Farm,Craft Chest,CRAFTSANITY, -3515,Farm,Craft Stone Chest,CRAFTSANITY, -3516,Farm,Craft Wood Sign,CRAFTSANITY, -3517,Farm,Craft Stone Sign,CRAFTSANITY, -3518,Farm,Craft Dark Sign,CRAFTSANITY, -3519,Farm,Craft Garden Pot,CRAFTSANITY, -3520,Farm,Craft Scarecrow,CRAFTSANITY, -3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, -3522,Farm,Craft Staircase,CRAFTSANITY, -3523,Farm,Craft Explosive Ammo,CRAFTSANITY, -3524,Farm,Craft Transmute (Fe),CRAFTSANITY, -3525,Farm,Craft Transmute (Au),CRAFTSANITY, -3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, -3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, -3528,Farm,Craft Farm Computer,CRAFTSANITY, -3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", -3530,Farm,Craft Cookout Kit,CRAFTSANITY, -3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, -3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, -3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, -3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, -3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, -3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, -3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, -3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, -3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, -3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, -3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, -3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, -3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", -3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, -3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, -3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, -3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, -3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, -3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, -3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, -3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, -3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, -3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, -3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, -5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic -5502,Magic Altar,Analyze: Till,MANDATORY,Magic -5503,Magic Altar,Analyze: Water,MANDATORY,Magic -5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic -5505,Magic Altar,Analyze: Evac,MANDATORY,Magic -5506,Magic Altar,Analyze: Haste,MANDATORY,Magic -5507,Magic Altar,Analyze: Heal,MANDATORY,Magic -5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic -5509,Magic Altar,Analyze: Descend,MANDATORY,Magic -5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic -5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic -5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic -5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic -5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic -5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic -5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic -5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic -5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic -5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic -5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic -5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic -6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas -6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas -6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas -6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas -6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas -6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas -6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas -6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas -6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas -6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas -6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas -6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas -6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas -6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas -6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba -6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba -6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba -6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba -6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba -6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba -6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba -6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba -6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba -6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba -6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) -6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) -6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) -6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) -6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) -6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) -6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) -6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) -6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) -6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) -6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC -6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC -6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC -6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC -6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC -6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC -6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC -6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC -6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC -6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC -6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC -6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC -6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC -6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC -6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick -6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick -6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick -6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick -6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick -6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick -6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick -6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick -6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick -6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick -6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick -6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick -6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick -6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick -6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC -6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC -6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC -6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC -6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC -6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC -6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC -6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC -6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC -6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC -6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC -6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC -6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC -6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC -6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited -6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited -6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited -6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited -6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited -6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited -6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited -6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited -6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited -6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited -6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited -6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited -6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited -6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited -6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene -6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene -6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene -6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene -6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene -6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene -6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene -6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene -6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene -6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene -6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene -6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene -6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene -6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene -6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC -6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC -6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC -6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC -6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC -6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC -6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC -6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC -6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC -6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC -6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley -6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley -6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley -6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley -6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley -6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley -6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley -6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley -6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley -6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley -6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley -6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley -6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley -6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley -6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded -6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded -6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded -6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded -6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded -6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded -6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded -6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded -6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded -6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded -6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded -6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded -6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded -6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded -6153,Highlands,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6154,Highlands,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6155,Highlands,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6156,Highlands,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6157,Highlands,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6158,Highlands,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6159,Highlands,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6160,Highlands,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6161,Highlands,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6162,Highlands,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6163,Highlands,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded -6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded -6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded -6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded -6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded -6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded -6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded -6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded -6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded -6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded -6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded -6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded -6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded -6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded -6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded -6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded -6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded -6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded -6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded -6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded -6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded -6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded -6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded -6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded -6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded -6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded -6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded -6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded -6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded -6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded -6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded -6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded -6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded -6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded -6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded -6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded -6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded -6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded -6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded -6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded -6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded -6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded -6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded -6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded -6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded -6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded -6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded -6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded -6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded -6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded -6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded -6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded -6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded -6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded -6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded -6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded -6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded -6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded -6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded -6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded -6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded -6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded -6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded -6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded -6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded -6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded -6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded -6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded -6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6273,Blue Moon Vineyard,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded -6274,Blue Moon Vineyard,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded -6275,Blue Moon Vineyard,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded -6276,Blue Moon Vineyard,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded -6277,Blue Moon Vineyard,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded -6278,Blue Moon Vineyard,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded -6279,Blue Moon Vineyard,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded -6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded -6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded -6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded -6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded -6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded -6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded -6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded -6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded -6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded -6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded -6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded -6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded -6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded -6303,Witch's Swamp,Friendsanity: Goblin 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6304,Witch's Swamp,Friendsanity: Goblin 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6305,Witch's Swamp,Friendsanity: Goblin 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6306,Witch's Swamp,Friendsanity: Goblin 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6307,Witch's Swamp,Friendsanity: Goblin 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6308,Witch's Swamp,Friendsanity: Goblin 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6309,Witch's Swamp,Friendsanity: Goblin 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6310,Witch's Swamp,Friendsanity: Goblin 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6311,Witch's Swamp,Friendsanity: Goblin 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6312,Witch's Swamp,Friendsanity: Goblin 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch -6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch -6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch -6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch -6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch -6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch -6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch -6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch -6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch -6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch -7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack -7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod -7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods -7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods -7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods -7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods -7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods -7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods -7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods -7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods -7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods -7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods -7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods -7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods -7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods -7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods -7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods -7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods -7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods -7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator -7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator -7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator -7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator -7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator -7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator -7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator -7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods -7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic -7402,Farm,Craft Travel Core,CRAFTSANITY,Magic -7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded -7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded -7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded -7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic -7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic -7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) -7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC -7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC -7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC -7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded -7509,Grandpa's Shed Interior,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded -7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded -7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded -7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded -7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,,Distant Lands - Witch Swamp Overhaul -7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul -7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul -7522,Witch's Swamp,Witch's order,,Distant Lands - Witch Swamp Overhaul -7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded -7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded -7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded -7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded -7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded -7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded -7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded -7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded -7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded -7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded -7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded -7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded -7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded -7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded -7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7706,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7708,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded -7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded -7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded -7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded -7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded -7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded -7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded -7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded -7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded -7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded -7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded -7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded -7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded -7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded -7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded -7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul -7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul -8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic -8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic -8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded -8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded -8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded -8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded -8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded -8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded -8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded -8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded -8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded -8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded -8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded -8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded -8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded -8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded -8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded -8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded -8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded -8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded -8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded -8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded -8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded -8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded -8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded -8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded -8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded -8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded -8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology -8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology -8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology -8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology -8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology -8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology -8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology -8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology -8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology -8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology -8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology -8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology -8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology -8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology -8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology -8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology -8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology -8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology -8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology -8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology -8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology -8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology -8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology -8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology -8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology -8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology -8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology -8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology -8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology -8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology -8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology -8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology -8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology -8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology -8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology -8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology -8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology -8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology -8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology -8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology -8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology -8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology -8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology -8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology -8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology -8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology -8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology -8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology -8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology -8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology -8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology -8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology -8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology -8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology -8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology -8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology -8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology -8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology -8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology -8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology -8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology -8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology -8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology -8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology -8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology -8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology -8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology -8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology -8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology -8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology -8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology -8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology -8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology -8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology -8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology -8203,Shipping,Shipsanity: Brown Amanita,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +id,region,name,tags,mod_name +1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", +32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", +34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", +35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", +37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +80,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +84,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +85,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +87,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +88,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +101,Pierre's General Store,Large Pack,BACKPACK, +102,Pierre's General Store,Deluxe Pack,BACKPACK, +103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", +202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", +203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", +204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", +205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", +206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", +207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", +208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", +209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", +210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", +211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", +212,Quarry Mine,Grim Reaper statue,MANDATORY, +213,The Mines,The Mines Entrance Cutscene,MANDATORY, +214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, +215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, +216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, +217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, +218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, +219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, +220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, +221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, +222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, +223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, +224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, +225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, +226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, +227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, +228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, +229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, +230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, +231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, +232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, +233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, +234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, +235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, +236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, +237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, +251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", +301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", +302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", +303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", +304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", +305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", +306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", +307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", +308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", +309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", +310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", +311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", +332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", +333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", +334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", +335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", +336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", +337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", +338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", +339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", +340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", +341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, +402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, +403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, +404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, +405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, +406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, +407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, +408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, +409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, +410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, +411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, +412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, +413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, +414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, +415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, +416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, +417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, +418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, +501,Town,Introductions,"MANDATORY,QUEST", +502,Town,How To Win Friends,"MANDATORY,QUEST", +503,Farm,Getting Started,"MANDATORY,QUEST", +504,Farm,Raising Animals,"MANDATORY,QUEST", +505,Farm,Advancement,"MANDATORY,QUEST", +506,Museum,Archaeology,"MANDATORY,QUEST", +507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", +508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", +509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", +510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", +511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", +512,Sam's House,Jodi's Request,"MANDATORY,QUEST", +513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", +514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", +515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", +516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", +517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", +518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", +519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", +520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", +521,Alex's House,Knee Therapy,"MANDATORY,QUEST", +522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", +524,Desert,The Mysterious Qi,"MANDATORY,QUEST", +525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", +526,Town,A Winter Mystery,"MANDATORY,QUEST", +527,Secret Woods,Strange Note,"MANDATORY,QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", +529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", +530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", +531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", +532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", +533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", +534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", +535,Sam's House,Fish Casserole,"MANDATORY,QUEST", +536,Fishing,Catch A Squid,"MANDATORY,QUEST", +537,Saloon,Fish Stew,"MANDATORY,QUEST", +538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", +539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", +540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", +541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", +542,Alex's House,Granny's Gift,"MANDATORY,QUEST", +543,Desert,Exotic Spirits,"MANDATORY,QUEST", +544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", +545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", +546,Mutant Bug Lair,Dark Talisman,"MANDATORY,QUEST", +547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", +548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", +601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", +602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", +603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", +604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", +605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", +606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", +607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", +608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", +609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", +610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", +611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", +612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", +613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", +614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", +615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", +616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", +617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", +618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", +619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", +620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", +621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", +701,Secret Woods,Old Master Cannoli,MANDATORY, +702,Beach,Beach Bridge Repair,MANDATORY, +703,Desert,Galaxy Sword Shrine,MANDATORY, +704,Farmhouse,Have a Baby,BABY, +705,Farmhouse,Have Another Baby,BABY, +706,Farmhouse,Spouse Stardrop,, +707,Sewer,Krobus Stardrop,MANDATORY, +801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, +802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, +803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, +804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, +805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, +806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, +807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, +808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, +811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, +812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, +821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, +822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, +823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, +824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, +825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, +826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, +827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, +828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, +841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, +842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, +843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, +844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, +845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, +846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, +847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, +848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, +849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, +850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, +851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, +852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, +853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, +854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, +855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, +856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, +857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, +858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, +859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, +860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, +861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, +862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, +863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, +864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, +865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, +866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, +867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, +868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, +869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, +870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, +871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, +872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, +901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", +902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", +903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", +911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", +912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", +913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", +921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", +942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", +943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", +951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", +952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", +953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", +961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", +962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", +963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", +1001,Fishing,Fishsanity: Carp,FISHSANITY, +1002,Fishing,Fishsanity: Herring,FISHSANITY, +1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, +1004,Fishing,Fishsanity: Anchovy,FISHSANITY, +1005,Fishing,Fishsanity: Sardine,FISHSANITY, +1006,Fishing,Fishsanity: Sunfish,FISHSANITY, +1007,Fishing,Fishsanity: Perch,FISHSANITY, +1008,Fishing,Fishsanity: Chub,FISHSANITY, +1009,Fishing,Fishsanity: Bream,FISHSANITY, +1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, +1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, +1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, +1013,Fishing,Fishsanity: Walleye,FISHSANITY, +1014,Fishing,Fishsanity: Shad,FISHSANITY, +1015,Fishing,Fishsanity: Bullhead,FISHSANITY, +1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, +1017,Fishing,Fishsanity: Salmon,FISHSANITY, +1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, +1019,Fishing,Fishsanity: Tilapia,FISHSANITY, +1020,Fishing,Fishsanity: Woodskip,FISHSANITY, +1021,Fishing,Fishsanity: Flounder,FISHSANITY, +1022,Fishing,Fishsanity: Halibut,FISHSANITY, +1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", +1024,Fishing,Fishsanity: Slimejack,FISHSANITY, +1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, +1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, +1027,Fishing,Fishsanity: Pike,FISHSANITY, +1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, +1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", +1030,Fishing,Fishsanity: Albacore,FISHSANITY, +1031,Fishing,Fishsanity: Sandfish,FISHSANITY, +1032,Fishing,Fishsanity: Stonefish,FISHSANITY, +1033,Fishing,Fishsanity: Tuna,FISHSANITY, +1034,Fishing,Fishsanity: Eel,FISHSANITY, +1035,Fishing,Fishsanity: Catfish,FISHSANITY, +1036,Fishing,Fishsanity: Squid,FISHSANITY, +1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, +1038,Fishing,Fishsanity: Dorado,FISHSANITY, +1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, +1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, +1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, +1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", +1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, +1044,Fishing,Fishsanity: Lingcod,FISHSANITY, +1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, +1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, +1047,Fishing,Fishsanity: Octopus,FISHSANITY, +1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, +1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, +1050,Fishing,Fishsanity: Blobfish,FISHSANITY, +1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, +1052,Fishing,Fishsanity: Angler,FISHSANITY, +1053,Fishing,Fishsanity: Legend,FISHSANITY, +1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, +1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, +1056,Town,Fishsanity: Crayfish,FISHSANITY, +1057,Town,Fishsanity: Snail,FISHSANITY, +1058,Town,Fishsanity: Periwinkle,FISHSANITY, +1059,Beach,Fishsanity: Lobster,FISHSANITY, +1060,Beach,Fishsanity: Clam,FISHSANITY, +1061,Beach,Fishsanity: Crab,FISHSANITY, +1062,Beach,Fishsanity: Cockle,FISHSANITY, +1063,Beach,Fishsanity: Mussel,FISHSANITY, +1064,Beach,Fishsanity: Shrimp,FISHSANITY, +1065,Beach,Fishsanity: Oyster,FISHSANITY, +1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, +1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, +1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, +1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, +1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, +1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, +1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, +1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, +1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, +1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, +1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, +1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, +1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, +1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, +1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, +1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, +1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, +1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, +1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, +1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, +1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, +1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, +1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, +1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, +1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, +1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, +1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, +1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, +1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, +1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, +1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, +1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, +1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, +1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, +1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, +1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, +1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, +1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, +1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, +1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, +1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, +1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, +1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, +1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, +1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, +1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, +1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", +1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, +1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, +1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, +1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, +1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, +1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, +1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, +1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, +1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, +1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, +1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, +1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, +1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, +1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, +1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, +1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, +1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, +1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, +1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, +1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, +1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, +1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, +1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, +1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, +1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, +1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, +1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, +1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, +1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, +1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, +1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, +1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, +1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, +1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, +1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, +1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, +1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, +1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, +1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, +1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, +1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, +1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, +1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, +1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, +1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, +1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, +1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, +1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, +1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, +1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, +1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, +1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, +1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, +1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, +1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, +1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, +1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, +1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, +1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, +1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, +1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, +1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, +1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, +1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, +1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, +1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, +1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, +1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, +1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, +1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, +1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, +1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, +1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, +1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, +1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, +1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, +1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, +1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, +1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, +1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, +1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, +1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, +1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, +1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, +1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, +1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, +1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, +1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, +1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, +1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, +1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, +1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, +1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, +1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, +1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, +1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, +1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, +1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, +1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, +1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, +1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, +1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, +1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, +1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, +1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, +1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, +1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, +1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, +1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, +1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, +1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, +1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, +1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, +1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, +1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, +1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, +1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, +1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, +1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, +1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, +1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, +1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, +1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, +1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, +1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, +1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, +1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, +1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, +1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, +1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, +1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, +1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, +1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, +1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, +1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, +1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, +1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, +1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, +1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, +1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, +1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, +1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, +1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, +1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, +1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, +1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, +1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, +1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, +1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, +1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, +1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, +1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, +1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, +1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, +1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, +1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, +1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, +1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, +1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, +1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, +1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, +1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, +1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, +1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, +1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, +1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, +1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, +1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, +1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, +1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, +1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, +1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, +1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, +1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, +1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, +1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, +1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, +1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, +1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, +1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, +1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, +1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, +1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, +1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, +1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, +1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, +1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, +1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, +1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, +1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, +1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, +1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, +1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, +1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, +1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, +1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, +1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, +1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, +1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, +1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, +1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, +1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, +1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, +1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, +1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, +1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, +1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, +1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, +1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, +1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, +1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, +1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, +1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, +1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, +1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, +1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, +1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, +1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, +1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, +1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, +1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, +1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, +1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, +1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, +1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, +1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, +1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, +1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, +1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, +1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, +1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, +1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, +1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, +1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, +1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, +1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, +1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, +1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, +1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, +1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, +1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, +1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, +1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, +1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, +1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, +1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, +1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, +1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, +1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, +1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, +1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, +1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, +1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, +1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, +1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, +1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, +1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, +1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, +1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, +1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, +1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, +1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, +1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, +1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, +1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, +1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, +1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, +1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, +1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, +1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, +1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, +1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, +1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, +1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, +1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, +1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, +1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, +1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, +1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, +1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, +1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, +1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, +1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, +1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, +1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, +1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, +1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, +1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, +1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, +1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, +1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, +1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, +1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, +1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, +1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, +1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, +1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, +1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, +1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, +1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, +1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, +1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, +1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, +1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, +1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, +1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, +1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, +1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, +1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, +1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, +1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, +1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, +1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, +1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, +1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, +1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, +1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, +1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, +1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, +1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, +1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, +1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, +1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, +1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, +1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, +1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, +1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, +1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, +1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, +1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, +1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, +1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, +1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, +1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, +1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, +1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, +1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, +1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, +1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, +1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, +1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, +1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, +1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, +1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, +1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, +1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, +1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, +1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, +1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, +1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, +1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, +1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, +1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, +1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, +1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, +1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", +1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", +1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", +1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", +1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", +1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", +1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", +1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", +1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", +1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", +1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, +1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, +1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, +1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, +1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, +1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, +1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, +1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, +1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, +1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, +1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, +1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, +1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, +1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, +1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, +1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, +1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, +1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, +1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, +1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, +1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, +1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, +1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, +1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, +1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, +1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, +1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, +1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, +1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, +1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, +1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, +1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, +1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, +1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, +1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, +1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, +1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, +1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, +1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, +1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, +1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, +1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, +1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, +1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, +1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, +1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, +1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, +1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, +1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, +1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, +1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, +1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, +1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, +1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, +1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, +1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, +1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, +1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, +1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, +1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, +1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, +1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, +1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, +1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, +1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, +1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, +1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, +1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, +1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, +1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, +1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, +1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, +1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, +1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, +1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, +1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, +1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, +1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, +1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, +1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, +1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, +1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, +1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, +1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, +1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, +1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, +1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, +1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, +1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, +1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, +1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, +1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, +1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, +1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, +1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, +1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, +1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, +1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, +1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, +1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, +1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, +1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, +1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, +1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, +1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, +1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, +1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, +1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, +1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, +1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, +1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, +1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, +1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, +1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, +1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, +1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, +1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, +1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, +1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, +2001,Egg Festival,Egg Hunt Victory,FESTIVAL, +2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, +2003,Flower Dance,Dance with someone,FESTIVAL, +2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, +2005,Luau,Luau Soup,FESTIVAL, +2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, +2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, +2008,Stardew Valley Fair,Grange Display,FESTIVAL, +2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, +2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, +2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, +2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, +2013,Festival of Ice,Win Fishing Competition,FESTIVAL, +2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, +2015,Night Market,Mermaid Pearl,FESTIVAL, +2016,Night Market,Cone Hat,FESTIVAL_HARD, +2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, +2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, +2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, +2020,Night Market,Lupini: Red Eagle,FESTIVAL, +2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, +2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, +2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, +2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, +2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, +2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, +2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, +2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, +2029,Feast of the Winter Star,Secret Santa,FESTIVAL, +2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, +2031,Farm,Collect All Rarecrows,FESTIVAL, +2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, +2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, +2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, +2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, +2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, +2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, +2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, +2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, +2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, +2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, +2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, +2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, +2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, +2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, +2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, +2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, +2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, +2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, +2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, +2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", +2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, +2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, +2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, +2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", +2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", +2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", +2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", +2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", +2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", +2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", +2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", +2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", +2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, +2216,Field Office,Complete Island Field Office,GINGER_ISLAND, +2301,Farming,Harvest Amaranth,CROPSANITY, +2302,Farming,Harvest Artichoke,CROPSANITY, +2303,Farming,Harvest Beet,CROPSANITY, +2304,Farming,Harvest Blue Jazz,CROPSANITY, +2305,Farming,Harvest Blueberry,CROPSANITY, +2306,Farming,Harvest Bok Choy,CROPSANITY, +2307,Farming,Harvest Cauliflower,CROPSANITY, +2308,Farming,Harvest Corn,CROPSANITY, +2309,Farming,Harvest Cranberries,CROPSANITY, +2310,Farming,Harvest Eggplant,CROPSANITY, +2311,Farming,Harvest Fairy Rose,CROPSANITY, +2312,Farming,Harvest Garlic,CROPSANITY, +2313,Farming,Harvest Grape,CROPSANITY, +2314,Farming,Harvest Green Bean,CROPSANITY, +2315,Farming,Harvest Hops,CROPSANITY, +2316,Farming,Harvest Hot Pepper,CROPSANITY, +2317,Farming,Harvest Kale,CROPSANITY, +2318,Farming,Harvest Melon,CROPSANITY, +2319,Farming,Harvest Parsnip,CROPSANITY, +2320,Farming,Harvest Poppy,CROPSANITY, +2321,Farming,Harvest Potato,CROPSANITY, +2322,Farming,Harvest Pumpkin,CROPSANITY, +2323,Farming,Harvest Radish,CROPSANITY, +2324,Farming,Harvest Red Cabbage,CROPSANITY, +2325,Farming,Harvest Rhubarb,CROPSANITY, +2326,Farming,Harvest Starfruit,CROPSANITY, +2327,Farming,Harvest Strawberry,CROPSANITY, +2328,Farming,Harvest Summer Spangle,CROPSANITY, +2329,Farming,Harvest Sunflower,CROPSANITY, +2330,Farming,Harvest Tomato,CROPSANITY, +2331,Farming,Harvest Tulip,CROPSANITY, +2332,Farming,Harvest Unmilled Rice,CROPSANITY, +2333,Farming,Harvest Wheat,CROPSANITY, +2334,Farming,Harvest Yam,CROPSANITY, +2335,Farming,Harvest Cactus Fruit,CROPSANITY, +2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", +2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", +2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, +2339,Farming,Harvest Apple,CROPSANITY, +2340,Farming,Harvest Apricot,CROPSANITY, +2341,Farming,Harvest Cherry,CROPSANITY, +2342,Farming,Harvest Orange,CROPSANITY, +2343,Farming,Harvest Pomegranate,CROPSANITY, +2344,Farming,Harvest Peach,CROPSANITY, +2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", +2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", +2347,Farming,Harvest Coffee Bean,CROPSANITY, +2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Shipping,Shipsanity: Anchor,SHIPSANITY, +2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, +2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, +2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, +2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, +2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, +2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, +2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, +2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Shipping,Shipsanity: Coffee,SHIPSANITY, +2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, +2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, +2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Shipping,Shipsanity: Bread,SHIPSANITY, +2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, +2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Shipping,Shipsanity: Chowder,SHIPSANITY, +2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, +2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Shipping,Shipsanity: Cookies,SHIPSANITY, +2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Shipping,Shipsanity: Escargot,SHIPSANITY, +2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, +2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, +2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, +2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, +2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, +2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, +2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, +2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Shipping,Shipsanity: Omelet,SHIPSANITY, +2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, +2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, +2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, +2518,Shipping,Shipsanity: Pizza,SHIPSANITY, +2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, +2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, +2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, +2529,Shipping,Shipsanity: Salad,SHIPSANITY, +2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, +2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, +2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, +2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, +2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, +2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, +2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, +2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, +2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, +2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Shipping,Shipsanity: Bait,SHIPSANITY, +2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Shipping,Shipsanity: Bomb,SHIPSANITY, +2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, +2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, +2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, +2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, +2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, +2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, +2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, +2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, +2569,Shipping,Shipsanity: Gate,SHIPSANITY, +2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, +2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, +2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, +2578,Shipping,Shipsanity: Magnet,SHIPSANITY, +2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, +2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, +2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Shipping,Shipsanity: Spinner,SHIPSANITY, +2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, +2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, +2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, +2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, +2598,Shipping,Shipsanity: Torch,SHIPSANITY, +2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", +2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, +2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, +2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, +2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, +2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, +2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, +2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Shipping,Shipsanity: Oil,SHIPSANITY, +2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Shipping,Shipsanity: Rice,SHIPSANITY, +2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Shipping,Shipsanity: Sugar,SHIPSANITY, +2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, +2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, +2765,Shipping,Shipsanity: Alamite,SHIPSANITY, +2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, +2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, +2769,Shipping,Shipsanity: Baryte,SHIPSANITY, +2770,Shipping,Shipsanity: Basalt,SHIPSANITY, +2771,Shipping,Shipsanity: Bixite,SHIPSANITY, +2772,Shipping,Shipsanity: Calcite,SHIPSANITY, +2773,Shipping,Shipsanity: Celestine,SHIPSANITY, +2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Shipping,Shipsanity: Diamond,SHIPSANITY, +2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, +2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Shipping,Shipsanity: Emerald,SHIPSANITY, +2780,Shipping,Shipsanity: Esperite,SHIPSANITY, +2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, +2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Shipping,Shipsanity: Geminite,SHIPSANITY, +2788,Shipping,Shipsanity: Geode,SHIPSANITY, +2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Shipping,Shipsanity: Granite,SHIPSANITY, +2792,Shipping,Shipsanity: Helvite,SHIPSANITY, +2793,Shipping,Shipsanity: Hematite,SHIPSANITY, +2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Shipping,Shipsanity: Jade,SHIPSANITY, +2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, +2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, +2799,Shipping,Shipsanity: Jasper,SHIPSANITY, +2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, +2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Shipping,Shipsanity: Limestone,SHIPSANITY, +2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, +2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, +2805,Shipping,Shipsanity: Malachite,SHIPSANITY, +2806,Shipping,Shipsanity: Marble,SHIPSANITY, +2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, +2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, +2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, +2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, +2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, +2814,Shipping,Shipsanity: Opal,SHIPSANITY, +2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, +2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, +2825,Shipping,Shipsanity: Quartz,SHIPSANITY, +2826,Shipping,Shipsanity: Ruby,SHIPSANITY, +2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, +2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Shipping,Shipsanity: Slate,SHIPSANITY, +2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, +2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, +2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, +2835,Shipping,Shipsanity: Topaz,SHIPSANITY, +2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, +2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", +2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, +2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, +2848,Shipping,Shipsanity: Hay,SHIPSANITY, +2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Shipping,Shipsanity: Pearl,SHIPSANITY, +2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, +2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Shipping,Shipsanity: White Algae,SHIPSANITY, +2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, +2858,Shipping,Shipsanity: Acorn,SHIPSANITY, +2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, +2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, +2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, +2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, +2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, +2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, +2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, +2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, +2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, +2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, +2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Shipping,Shipsanity: Trash,SHIPSANITY, +2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, +2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", +2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Shipping,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", +2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", +3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", +3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", +3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", +3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", +3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", +3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", +3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", +3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", +3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", +3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3201,Kitchen,Cook Algae Soup,COOKSANITY, +3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", +3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, +3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", +3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", +3206,Kitchen,Cook Bean Hotpot,COOKSANITY, +3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", +3208,Kitchen,Cook Blueberry Tart,COOKSANITY, +3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", +3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", +3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", +3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, +3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", +3214,Kitchen,Cook Chowder,COOKSANITY, +3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", +3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", +3217,Kitchen,Cook Cookies,COOKSANITY, +3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", +3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", +3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, +3221,Kitchen,Cook Crispy Bass,COOKSANITY, +3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, +3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, +3224,Kitchen,Cook Escargot,COOKSANITY, +3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, +3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", +3227,Kitchen,Cook Fish Stew,COOKSANITY, +3228,Kitchen,Cook Fish Taco,COOKSANITY, +3229,Kitchen,Cook Fried Calamari,COOKSANITY, +3230,Kitchen,Cook Fried Eel,COOKSANITY, +3231,Kitchen,Cook Fried Egg,COOKSANITY, +3232,Kitchen,Cook Fried Mushroom,COOKSANITY, +3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", +3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", +3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", +3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", +3237,Kitchen,Cook Ice Cream,COOKSANITY, +3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", +3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", +3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", +3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", +3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", +3243,Kitchen,Cook Miner's Treat,COOKSANITY, +3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", +3245,Kitchen,Cook Pale Broth,COOKSANITY, +3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", +3247,Kitchen,Cook Parsnip Soup,COOKSANITY, +3248,Kitchen,Cook Pepper Poppers,COOKSANITY, +3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", +3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", +3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", +3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", +3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", +3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", +3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, +3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", +3257,Kitchen,Cook Red Plate,COOKSANITY, +3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, +3259,Kitchen,Cook Rice Pudding,COOKSANITY, +3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", +3261,Kitchen,Cook Roots Platter,COOKSANITY, +3262,Kitchen,Cook Salad,COOKSANITY, +3263,Kitchen,Cook Salmon Dinner,COOKSANITY, +3264,Kitchen,Cook Sashimi,COOKSANITY, +3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, +3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", +3267,Kitchen,Cook Spaghetti,COOKSANITY, +3268,Kitchen,Cook Spicy Eel,COOKSANITY, +3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, +3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", +3271,Kitchen,Cook Strange Bun,COOKSANITY, +3272,Kitchen,Cook Stuffing,COOKSANITY, +3273,Kitchen,Cook Super Meal,COOKSANITY, +3274,Kitchen,Cook Survival Burger,COOKSANITY, +3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, +3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", +3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, +3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", +3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", +3280,Kitchen,Cook Vegetable Medley,COOKSANITY, +3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, +3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3401,Farm,Craft Cherry Bomb,CRAFTSANITY, +3402,Farm,Craft Bomb,CRAFTSANITY, +3403,Farm,Craft Mega Bomb,CRAFTSANITY, +3404,Farm,Craft Gate,CRAFTSANITY, +3405,Farm,Craft Wood Fence,CRAFTSANITY, +3406,Farm,Craft Stone Fence,CRAFTSANITY, +3407,Farm,Craft Iron Fence,CRAFTSANITY, +3408,Farm,Craft Hardwood Fence,CRAFTSANITY, +3409,Farm,Craft Sprinkler,CRAFTSANITY, +3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, +3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, +3412,Farm,Craft Bee House,CRAFTSANITY, +3413,Farm,Craft Cask,CRAFTSANITY, +3414,Farm,Craft Cheese Press,CRAFTSANITY, +3415,Farm,Craft Keg,CRAFTSANITY, +3416,Farm,Craft Loom,CRAFTSANITY, +3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, +3418,Farm,Craft Oil Maker,CRAFTSANITY, +3419,Farm,Craft Preserves Jar,CRAFTSANITY, +3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, +3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, +3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, +3423,Farm,Craft Speed-Gro,CRAFTSANITY, +3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, +3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", +3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, +3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, +3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", +3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, +3430,Farm,Craft Spring Seeds,CRAFTSANITY, +3431,Farm,Craft Summer Seeds,CRAFTSANITY, +3432,Farm,Craft Fall Seeds,CRAFTSANITY, +3433,Farm,Craft Winter Seeds,CRAFTSANITY, +3434,Farm,Craft Ancient Seeds,CRAFTSANITY, +3435,Farm,Craft Grass Starter,CRAFTSANITY, +3436,Farm,Craft Tea Sapling,CRAFTSANITY, +3437,Farm,Craft Fiber Seeds,CRAFTSANITY, +3438,Farm,Craft Wood Floor,CRAFTSANITY, +3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, +3440,Farm,Craft Straw Floor,CRAFTSANITY, +3441,Farm,Craft Weathered Floor,CRAFTSANITY, +3442,Farm,Craft Crystal Floor,CRAFTSANITY, +3443,Farm,Craft Stone Floor,CRAFTSANITY, +3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, +3445,Farm,Craft Brick Floor,CRAFTSANITY, +3446,Farm,Craft Wood Path,CRAFTSANITY, +3447,Farm,Craft Gravel Path,CRAFTSANITY, +3448,Farm,Craft Cobblestone Path,CRAFTSANITY, +3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, +3450,Farm,Craft Crystal Path,CRAFTSANITY, +3451,Farm,Craft Spinner,CRAFTSANITY, +3452,Farm,Craft Trap Bobber,CRAFTSANITY, +3453,Farm,Craft Cork Bobber,CRAFTSANITY, +3454,Farm,Craft Quality Bobber,CRAFTSANITY, +3455,Farm,Craft Treasure Hunter,CRAFTSANITY, +3456,Farm,Craft Dressed Spinner,CRAFTSANITY, +3457,Farm,Craft Barbed Hook,CRAFTSANITY, +3458,Farm,Craft Magnet,CRAFTSANITY, +3459,Farm,Craft Bait,CRAFTSANITY, +3460,Farm,Craft Wild Bait,CRAFTSANITY, +3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", +3462,Farm,Craft Crab Pot,CRAFTSANITY, +3463,Farm,Craft Sturdy Ring,CRAFTSANITY, +3464,Farm,Craft Warrior Ring,CRAFTSANITY, +3465,Farm,Craft Ring of Yoba,CRAFTSANITY, +3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", +3467,Farm,Craft Glowstone Ring,CRAFTSANITY, +3468,Farm,Craft Iridium Band,CRAFTSANITY, +3469,Farm,Craft Wedding Ring,CRAFTSANITY, +3470,Farm,Craft Field Snack,CRAFTSANITY, +3471,Farm,Craft Bug Steak,CRAFTSANITY, +3472,Farm,Craft Life Elixir,CRAFTSANITY, +3473,Farm,Craft Oil of Garlic,CRAFTSANITY, +3474,Farm,Craft Monster Musk,CRAFTSANITY, +3475,Farm,Craft Fairy Dust,CRAFTSANITY, +3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, +3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, +3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, +3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, +3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", +3481,Farm,Craft Rain Totem,CRAFTSANITY, +3482,Farm,Craft Torch,CRAFTSANITY, +3483,Farm,Craft Campfire,CRAFTSANITY, +3484,Farm,Craft Wooden Brazier,CRAFTSANITY, +3485,Farm,Craft Stone Brazier,CRAFTSANITY, +3486,Farm,Craft Gold Brazier,CRAFTSANITY, +3487,Farm,Craft Carved Brazier,CRAFTSANITY, +3488,Farm,Craft Stump Brazier,CRAFTSANITY, +3489,Farm,Craft Barrel Brazier,CRAFTSANITY, +3490,Farm,Craft Skull Brazier,CRAFTSANITY, +3491,Farm,Craft Marble Brazier,CRAFTSANITY, +3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, +3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, +3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, +3495,Farm,Craft Bone Mill,CRAFTSANITY, +3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, +3497,Farm,Craft Crystalarium,CRAFTSANITY, +3498,Farm,Craft Furnace,CRAFTSANITY, +3499,Farm,Craft Geode Crusher,CRAFTSANITY, +3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", +3501,Farm,Craft Lightning Rod,CRAFTSANITY, +3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", +3503,Farm,Craft Recycling Machine,CRAFTSANITY, +3504,Farm,Craft Seed Maker,CRAFTSANITY, +3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, +3506,Farm,Craft Slime Incubator,CRAFTSANITY, +3507,Farm,Craft Solar Panel,CRAFTSANITY, +3508,Farm,Craft Tapper,CRAFTSANITY, +3509,Farm,Craft Worm Bin,CRAFTSANITY, +3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, +3511,Farm,Craft Wicked Statue,CRAFTSANITY, +3512,Farm,Craft Flute Block,CRAFTSANITY, +3513,Farm,Craft Drum Block,CRAFTSANITY, +3514,Farm,Craft Chest,CRAFTSANITY, +3515,Farm,Craft Stone Chest,CRAFTSANITY, +3516,Farm,Craft Wood Sign,CRAFTSANITY, +3517,Farm,Craft Stone Sign,CRAFTSANITY, +3518,Farm,Craft Dark Sign,CRAFTSANITY, +3519,Farm,Craft Garden Pot,CRAFTSANITY, +3520,Farm,Craft Scarecrow,CRAFTSANITY, +3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, +3522,Farm,Craft Staircase,CRAFTSANITY, +3523,Farm,Craft Explosive Ammo,CRAFTSANITY, +3524,Farm,Craft Transmute (Fe),CRAFTSANITY, +3525,Farm,Craft Transmute (Au),CRAFTSANITY, +3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, +3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, +3528,Farm,Craft Farm Computer,CRAFTSANITY, +3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", +3530,Farm,Craft Cookout Kit,CRAFTSANITY, +3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, +3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, +3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, +3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, +3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, +3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, +3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, +3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, +3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, +3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, +3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, +3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, +3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", +3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, +3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, +3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, +3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, +3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, +3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, +3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, +3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, +3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, +3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, +3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, +5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic +5502,Magic Altar,Analyze: Till,MANDATORY,Magic +5503,Magic Altar,Analyze: Water,MANDATORY,Magic +5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic +5505,Magic Altar,Analyze: Evac,MANDATORY,Magic +5506,Magic Altar,Analyze: Haste,MANDATORY,Magic +5507,Magic Altar,Analyze: Heal,MANDATORY,Magic +5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic +5509,Magic Altar,Analyze: Descend,MANDATORY,Magic +5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic +5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic +5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic +5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic +5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic +5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic +5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic +5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic +5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic +5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic +5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic +6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas +6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas +6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas +6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas +6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas +6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas +6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas +6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas +6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas +6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas +6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas +6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas +6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas +6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas +6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba +6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba +6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba +6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba +6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba +6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba +6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba +6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba +6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba +6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba +6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) +6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) +6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) +6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) +6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) +6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) +6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) +6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) +6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) +6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) +6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC +6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC +6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC +6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC +6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC +6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC +6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC +6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC +6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC +6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC +6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC +6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC +6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC +6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC +6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick +6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick +6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick +6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick +6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick +6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick +6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick +6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick +6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick +6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick +6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick +6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick +6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick +6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick +6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC +6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC +6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC +6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC +6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC +6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC +6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC +6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC +6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC +6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC +6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC +6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC +6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC +6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC +6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited +6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited +6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited +6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited +6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited +6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited +6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited +6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited +6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited +6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited +6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited +6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited +6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited +6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited +6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene +6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene +6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene +6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene +6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene +6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene +6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene +6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene +6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene +6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene +6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene +6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene +6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene +6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene +6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC +6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC +6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC +6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC +6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC +6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC +6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC +6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC +6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC +6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC +6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley +6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley +6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley +6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley +6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley +6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley +6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley +6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley +6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley +6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley +6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley +6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley +6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley +6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded +6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded +6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded +6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded +6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded +6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded +6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded +6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded +6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded +6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded +6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded +6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded +6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded +6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded +6153,Highlands,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Highlands,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Highlands,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Highlands,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Highlands,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Highlands,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Highlands,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Highlands,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Highlands,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Highlands,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Highlands,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded +6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded +6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded +6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded +6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded +6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded +6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded +6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded +6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded +6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded +6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded +6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded +6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded +6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded +6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded +6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded +6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded +6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded +6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded +6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded +6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded +6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded +6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded +6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded +6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded +6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded +6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded +6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded +6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded +6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded +6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded +6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded +6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded +6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded +6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded +6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded +6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded +6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded +6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded +6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded +6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded +6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded +6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded +6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded +6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded +6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded +6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded +6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded +6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded +6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded +6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded +6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded +6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded +6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded +6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded +6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded +6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded +6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded +6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded +6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded +6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded +6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded +6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded +6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded +6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded +6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded +6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded +6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded +6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6273,Blue Moon Vineyard,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded +6274,Blue Moon Vineyard,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded +6275,Blue Moon Vineyard,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded +6276,Blue Moon Vineyard,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded +6277,Blue Moon Vineyard,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded +6278,Blue Moon Vineyard,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded +6279,Blue Moon Vineyard,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded +6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded +6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded +6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded +6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded +6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded +6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded +6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded +6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded +6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded +6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded +6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded +6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded +6303,Witch's Swamp,Friendsanity: Goblin 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6304,Witch's Swamp,Friendsanity: Goblin 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6305,Witch's Swamp,Friendsanity: Goblin 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6306,Witch's Swamp,Friendsanity: Goblin 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6307,Witch's Swamp,Friendsanity: Goblin 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6308,Witch's Swamp,Friendsanity: Goblin 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6309,Witch's Swamp,Friendsanity: Goblin 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6310,Witch's Swamp,Friendsanity: Goblin 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6311,Witch's Swamp,Friendsanity: Goblin 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6312,Witch's Swamp,Friendsanity: Goblin 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch +6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch +6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch +6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch +6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch +6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch +6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch +6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch +6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch +6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch +7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack +7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod +7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods +7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods +7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods +7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods +7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods +7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods +7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods +7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods +7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods +7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods +7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods +7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods +7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods +7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods +7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods +7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods +7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods +7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator +7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator +7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator +7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator +7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator +7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator +7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator +7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods +7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic +7402,Farm,Craft Travel Core,CRAFTSANITY,Magic +7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded +7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded +7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic +7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic +7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) +7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) +7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC +7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC +7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC +7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded +7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded +7509,Grandpa's Shed Interior,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded +7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded +7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded +7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded +7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded +7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7519,Witch's Swamp,Corrupted Crops Task,,Distant Lands - Witch Swamp Overhaul +7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul +7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,,Distant Lands - Witch Swamp Overhaul +7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded +7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded +7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded +7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded +7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded +7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded +7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded +7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded +7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded +7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded +7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded +7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded +7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded +7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7706,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded +7708,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded +7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded +7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded +7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded +7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded +7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded +7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded +7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded +7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded +7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded +7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded +7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded +7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded +7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul +7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul +8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic +8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded +8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded +8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded +8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded +8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded +8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded +8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded +8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded +8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded +8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded +8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded +8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded +8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded +8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded +8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded +8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded +8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded +8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded +8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded +8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded +8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded +8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded +8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded +8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology +8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology +8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology +8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology +8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology +8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology +8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology +8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology +8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology +8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology +8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology +8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology +8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology +8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology +8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology +8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology +8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology +8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology +8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology +8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology +8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology +8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology +8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology +8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology +8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology +8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology +8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology +8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology +8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology +8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology +8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology +8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology +8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology +8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology +8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology +8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology +8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology +8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology +8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology +8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology +8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology +8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology +8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology +8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology +8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology +8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology +8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology +8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology +8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology +8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology +8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology +8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology +8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology +8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology +8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology +8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology +8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology +8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology +8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology +8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology +8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology +8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology +8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology +8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology +8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology +8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology +8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology +8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology +8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology +8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology +8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology +8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology +8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology +8203,Shipping,Shipsanity: Brown Amanita,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul From 2707fe14e51cfbfcfde173ef665e530b73709194 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 4 Dec 2023 01:24:56 -0600 Subject: [PATCH 293/482] Utilize a weapons count method --- worlds/stardew_valley/items.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index aeb7124f27c6..4359d365c964 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -234,17 +234,13 @@ def create_weapons(item_factory: StardewItemFactory, options: StardewValleyOptio items.extend(item_factory(item) for item in [APWeapon.slingshot] * 2) monstersanity = options.monstersanity if monstersanity == Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons - items.extend(item_factory(item) for item in [APWeapon.weapon] * 5) - if ModNames.sve in options.mods: - items.append(APWeapon.weapon) + items.extend(item_factory(item) for item in [APWeapon.weapon] * weapons_count(options)) items.extend(item_factory(item) for item in [APWeapon.footwear] * 3) # 1-2 | 3-4 | 6-7-8 return - items.extend(item_factory(item) for item in [APWeapon.sword] * 5) - items.extend(item_factory(item) for item in [APWeapon.club] * 5) - items.extend(item_factory(item) for item in [APWeapon.dagger] * 5) - if ModNames.sve in options.mods: - items.extend(item_factory(item) for item in [APWeapon.sword, APWeapon.club, APWeapon.dagger]) + items.extend(item_factory(item) for item in [APWeapon.sword] * weapons_count(options)) + items.extend(item_factory(item) for item in [APWeapon.club] * weapons_count(options)) + items.extend(item_factory(item) for item in [APWeapon.dagger] * weapons_count(options)) items.extend(item_factory(item) for item in [APWeapon.footwear] * 4) # 1-2 | 3-4 | 6-7-8 | 11-13 if monstersanity == Monstersanity.option_goals or monstersanity == Monstersanity.option_one_per_category or \ monstersanity == Monstersanity.option_short_goals or monstersanity == Monstersanity.option_very_short_goals: @@ -602,6 +598,13 @@ def create_unique_filler_items(item_factory: StardewItemFactory, options: Starde return items +def weapons_count(options: StardewValleyOptions): + weapon_count = 5 + if ModNames.sve in options.mods: + weapon_count += 1 + return weapon_count + + def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random, items_already_added: List[Item], number_locations: int) -> List[Item]: From 1fc23c92a9d347172674beeb6c86059c44623ae7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 4 Dec 2023 03:07:42 -0600 Subject: [PATCH 294/482] Make new recipe source --- worlds/stardew_valley/data/recipe_data.py | 23 ++++++++++++------- worlds/stardew_valley/data/recipe_source.py | 16 +++++++++++++ worlds/stardew_valley/logic/cooking_logic.py | 6 ++++- worlds/stardew_valley/mods/logic/sve_logic.py | 18 ++------------- worlds/stardew_valley/rules.py | 4 +--- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 5e8d16b6a355..55dad717ca3c 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -1,6 +1,6 @@ from typing import Dict, List, Optional from ..mods.mod_data import ModNames -from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource +from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource, ShopFriendshipSource from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood from ..strings.crop_names import Fruit, Vegetable, SVEFruit, DistantLandsCrop @@ -43,6 +43,11 @@ def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str return create_recipe(name, ingredients, source, mod_name) +def friendship_and_shop_recipe(name: str, friend: str, hearts: int, region: str, price: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe: + source = ShopFriendshipSource(friend, hearts, region, price) + return create_recipe(name, ingredients, source, mod_name) + + def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int]) -> CookingRecipe: source = SkillSource(skill, level) return create_recipe(name, ingredients, source) @@ -171,22 +176,24 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 12500, {Forageable.salmonberry: 15, Forageable.blackberry: 15, Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve) -big_bark_burger = shop_recipe(SVEMeal.big_bark_burger, Region.saloon, 5500, {SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, ModNames.sve) +big_bark_burger = friendship_and_shop_recipe(SVEMeal.big_bark_burger, NPC.gus, 5, Region.saloon, 5500, + {SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, ModNames.sve) flower_cookie = shop_recipe(SVEMeal.flower_cookie, SVERegion.bear_shop, 8750, {SVEForage.ferngill_primrose: 1, SVEForage.goldenrod: 1, SVEForage.winter_star_rose: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.large_egg: 1}, ModNames.sve) frog_legs = shop_recipe(SVEMeal.frog_legs, Region.adventurer_guild, 2000, {SVEFish.frog: 1, Ingredient.oil: 1, Ingredient.wheat_flour: 1}, ModNames.sve) -glazed_butterfish = shop_recipe(SVEMeal.glazed_butterfish, Region.saloon, 4000, {SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, - ModNames.sve) +glazed_butterfish = friendship_and_shop_recipe(SVEMeal.glazed_butterfish, NPC.gus, 10, Region.saloon, 4000, + {SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, ModNames.sve) mixed_berry_pie = shop_recipe(SVEMeal.mixed_berry_pie, Region.saloon, 3500, {Fruit.strawberry: 6, SVEFruit.salal_berry: 6, Forageable.blackberry: 6, SVEForage.bearberrys: 6, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}, ModNames.sve) -mushroom_berry_rice = shop_recipe(SVEMeal.mushroom_berry_rice, Region.adventurer_guild, 1500, {SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, +mushroom_berry_rice = friendship_and_shop_recipe(SVEMeal.mushroom_berry_rice, ModNPC.marlon, 6, Region.adventurer_guild, 1500, {SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, Ingredient.rice: 1, Ingredient.sugar: 2}, ModNames.sve) seaweed_salad = shop_recipe(SVEMeal.seaweed_salad, Region.fish_shop, 1250, {SVEFish.dulse_seaweed: 2, WaterItem.seaweed: 2, Ingredient.oil: 1}, ModNames.sve) -void_delight = shop_recipe(SVEMeal.void_delight, Region.sewer, 5000, {SVEFish.void_eel: 1, Loot.void_essence: 50, Loot.solar_essence: 20}, ModNames.sve) -void_salmon_sushi = shop_recipe(SVEMeal.void_salmon_sushi, Region.sewer, 5000, {Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, - ModNames.sve) +void_delight = friendship_and_shop_recipe(SVEMeal.void_delight, NPC.krobus, 10, Region.sewer, 5000, + {SVEFish.void_eel: 1, Loot.void_essence: 50, Loot.solar_essence: 20}, ModNames.sve) +void_salmon_sushi = friendship_and_shop_recipe(SVEMeal.void_salmon_sushi, NPC.krobus, 10, Region.sewer, 5000, + {Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, ModNames.sve) mushroom_kebab = friendship_recipe(DistantLandsMeal.mushroom_kebab, ModNPC.goblin, 2, {Forageable.chanterelle: 1, Forageable.common_mushroom: 1, Forageable.red_mushroom: 1, Material.wood: 1}, ModNames.distant_lands) diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index f02685628fb8..168234ee311f 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -96,6 +96,22 @@ def __repr__(self): return f"ShopSource at {self.region} costing {self.price}g" +class ShopFriendshipSource(RecipeSource): + friend: str + hearts: int + region: str + price: int + + def __init__(self, friend: str, hearts: int, region: str, price: int): + self.friend = friend + self.hearts = hearts + self.region = region + self.price = price + + def __repr__(self): + return f"ShopFriendshipSource at {self.region} costing {self.price}g when {self.friend} has {self.hearts} hearts" + + class FestivalShopSource(ShopSource): def __init__(self, region: str, price: int): diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index b6c47f23fc8b..380f64c70b07 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -14,7 +14,7 @@ from .skill_logic import SkillLogicMixin from .time_logic import TimeLogicMixin from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \ - QueenOfSauceSource, CookingRecipe, \ + QueenOfSauceSource, CookingRecipe, ShopFriendshipSource, \ all_cooking_recipes_by_name from ..data.recipe_source import CutsceneSource, ShopTradeSource from ..locations import locations_by_tag, LocationTags @@ -66,6 +66,8 @@ def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule: return self.logic.cooking.received_recipe(meal_name) if isinstance(source, QueenOfSauceSource) and self.options.chefsanity & Chefsanity.option_queen_of_sauce: return self.logic.cooking.received_recipe(meal_name) + if isinstance(source, ShopFriendshipSource) and self.options.chefsanity & Chefsanity.option_friendship: + return self.logic.cooking.received_recipe(meal_name) return self.logic.cooking.can_learn_recipe(source) @cache_self1 @@ -84,6 +86,8 @@ def can_learn_recipe(self, source: RecipeSource) -> StardewRule: return self.logic.relationship.has_hearts(source.friend, source.hearts) if isinstance(source, QueenOfSauceSource): return self.logic.action.can_watch(Channel.queen_of_sauce) & self.logic.season.has(source.season) + if isinstance(source, ShopFriendshipSource): + return self.logic.money.can_spend_at(source.region, source.price) & self.logic.relationship.has_hearts(source.friend, source.hearts) return False_() @cache_self1 diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 5c00d0218de9..0ff348f57725 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -4,7 +4,6 @@ from ...logic.base_logic import BaseLogicMixin, BaseLogic from ...logic.combat_logic import CombatLogicMixin from ...logic.cooking_logic import CookingLogicMixin -from ...logic.fishing_logic import FishingLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin from ...logic.quest_logic import QuestLogicMixin @@ -15,9 +14,7 @@ from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes -from ...strings.food_names import SVEMeal -from ...strings.villager_names import NPC, ModNPC -from ...stardew_rule import Or, True_ +from ...stardew_rule import Or class SVELogicMixin(BaseLogicMixin): @@ -27,7 +24,7 @@ def __init__(self, *args, **kwargs): class SVELogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, QuestLogicMixin, RegionLogicMixin, RelationshipLogicMixin, TimeLogicMixin, ToolLogicMixin, -FishingLogicMixin, CookingLogicMixin, MoneyLogicMixin, CombatLogicMixin, SeasonLogicMixin]]): + CookingLogicMixin, MoneyLogicMixin, CombatLogicMixin, SeasonLogicMixin]]): def initialize_rules(self): self.registry.sve_location_rules.update({ SVELocation.tempered_galaxy_sword: self.logic.money.can_spend_at(SVERegion.alesia_shop, 350000), @@ -39,14 +36,3 @@ def initialize_rules(self): def has_any_rune(self): rune_list = SVERunes.nexus_items return Or(*(self.logic.received(rune) for rune in rune_list)) - - def append_sve_recipe_rules(self, recipe: str): - if recipe == SVEMeal.glazed_butterfish: - return self.logic.relationship.has_hearts(NPC.gus, 10) - if recipe == SVEMeal.big_bark_burger: - return self.logic.relationship.has_hearts(NPC.gus, 5) - if recipe == SVEMeal.mushroom_berry_rice: - return self.logic.relationship.has_hearts(ModNPC.marlon, 6) - if recipe == SVEMeal.void_delight: - return self.logic.relationship.has_hearts(NPC.krobus, 10) - return True_() diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index cfae137a6dfa..020975a0ece3 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -736,9 +736,7 @@ def set_chefsanity_rules(all_location_names: List[str], logic: StardewLogic, mul recipe_name = location.name[:-len(chefsanity_suffix)] recipe = all_cooking_recipes_by_name[recipe_name] learn_rule = logic.cooking.can_learn_recipe(recipe.source) - friendship_purchase_rule = logic.mod.sve.append_sve_recipe_rules(recipe_name) - full_rule = learn_rule & friendship_purchase_rule - MultiWorldRules.set_rule(multiworld.get_location(location.name, player), full_rule) + MultiWorldRules.set_rule(multiworld.get_location(location.name, player), learn_rule) def set_craftsanity_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): From db055910cd3e6e8494bd0d327b11ba0ff3ff3600 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 4 Dec 2023 03:08:08 -0600 Subject: [PATCH 295/482] Fix locations and cropsanity logic --- worlds/stardew_valley/data/locations.csv | 10 +++++----- worlds/stardew_valley/locations.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 5a43e8e617fd..08cdec469271 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2551,14 +2551,14 @@ id,region,name,tags,mod_name 7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul 7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded 7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded 7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded 7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded 7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index aae45ae2af24..d52c3ba27deb 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -171,7 +171,7 @@ def extend_cropsanity_locations(randomized_locations: List[LocationData], option if options.cropsanity == Cropsanity.option_disabled: return - cropsanity_locations = [item for item in locations_by_tag[LocationTags.CROPSANITY] if item.mod_name in options.mods or not item.mod_name] + cropsanity_locations = [item for item in locations_by_tag[LocationTags.CROPSANITY] if not item.mod_name or item.mod_name in options.mods] cropsanity_locations = filter_ginger_island(options, cropsanity_locations) randomized_locations.extend(cropsanity_locations) From f0ba730d0a5638bcb569f793157f103e956e3e76 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 4 Dec 2023 03:08:26 -0600 Subject: [PATCH 296/482] Fix item and quest logic --- worlds/stardew_valley/mods/logic/item_logic.py | 11 +++++------ worlds/stardew_valley/mods/logic/quests_logic.py | 9 ++++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 43012a608232..8dc90c8263e9 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -128,14 +128,13 @@ def get_distant_lands_item_rules(self): DistantLandsForageable.swamp_herb: self.logic.region.can_reach(Region.witch_swamp), DistantLandsForageable.brown_amanita: self.logic.region.can_reach(Region.witch_swamp), DistantLandsFish.purple_algae: self.logic.fishing.can_fish_at(Region.witch_swamp), - DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.pseudo_cropsanity_check(DistantLandsSeed.vile_ancient_fruit), - DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.pseudo_cropsanity_check(DistantLandsSeed.void_mint), - DistantLandsCrop.void_mint: self.logic.has(DistantLandsSeed.void_mint), - DistantLandsCrop.vile_ancient_fruit: self.logic.has(DistantLandsSeed.vile_ancient_fruit) + DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.seed_check_if_usual_source(DistantLandsSeed.vile_ancient_fruit), + DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.seed_check_if_usual_source(DistantLandsSeed.void_mint), + DistantLandsCrop.void_mint: self.logic.has(DistantLandsSeed.void_mint) & self.logic.season.has_any_not_winter(), + DistantLandsCrop.vile_ancient_fruit: self.logic.has(DistantLandsSeed.vile_ancient_fruit) & self.logic.season.has_any_not_winter() } - # Items that don't behave enough like a crop but enough to warrant a portion of the cropsanity logic. - def pseudo_cropsanity_check(self, seed_name: str): + def seed_check_if_usual_source(self, seed_name: str): if self.options.cropsanity == Cropsanity.option_disabled: return True_() return self.logic.received(seed_name) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 97c83092b249..16d90e2cfa9e 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -88,13 +88,12 @@ def _get_distant_lands_quest_rules(self): return {} return{ - ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.region.can_reach(Region.witch_swamp) & - self.logic.has(Fertilizer.quality), - ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.quality), - ModQuest.ANewPot: self.logic.region.can_reach(Region.witch_swamp) & self.logic.region.can_reach(Region.saloon) & + ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.has(Fertilizer.deluxe), + ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.deluxe), + ModQuest.ANewPot: self.logic.region.can_reach(Region.saloon) & self.logic.region.can_reach(Region.sam_house) & self.logic.region.can_reach(Region.pierre_store) & self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron), - ModQuest.FancyBlanketTask: self.logic.region.can_reach(Region.witch_swamp) & self.logic.region.can_reach(Region.haley_house) & self.logic.has(AnimalProduct.wool) & + ModQuest.FancyBlanketTask: self.logic.region.can_reach(Region.haley_house) & self.logic.has(AnimalProduct.wool) & self.logic.has(ArtisanGood.cloth) } From 8a3debf557fc0ab84e2583daaee85a34d3837c68 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 12:09:02 -0600 Subject: [PATCH 297/482] Make two quests GI required --- worlds/stardew_valley/data/locations.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 08cdec469271..3992b80062e8 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2531,10 +2531,10 @@ id,region,name,tags,mod_name 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded 7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,,Distant Lands - Witch Swamp Overhaul +7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul 7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul 7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul -7522,Witch's Swamp,Witch's order,,Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul 7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded From 6f5f694ca676f6e235b88e6ea9cdeeba8ed0f947 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 12:10:54 -0600 Subject: [PATCH 298/482] Use has_seed_unlocked as name --- worlds/stardew_valley/mods/logic/item_logic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 8dc90c8263e9..7a6c148d4964 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -128,13 +128,13 @@ def get_distant_lands_item_rules(self): DistantLandsForageable.swamp_herb: self.logic.region.can_reach(Region.witch_swamp), DistantLandsForageable.brown_amanita: self.logic.region.can_reach(Region.witch_swamp), DistantLandsFish.purple_algae: self.logic.fishing.can_fish_at(Region.witch_swamp), - DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.seed_check_if_usual_source(DistantLandsSeed.vile_ancient_fruit), - DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.seed_check_if_usual_source(DistantLandsSeed.void_mint), + DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.has_seed_unlocked(DistantLandsSeed.vile_ancient_fruit), + DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.has_seed_unlocked(DistantLandsSeed.void_mint), DistantLandsCrop.void_mint: self.logic.has(DistantLandsSeed.void_mint) & self.logic.season.has_any_not_winter(), DistantLandsCrop.vile_ancient_fruit: self.logic.has(DistantLandsSeed.vile_ancient_fruit) & self.logic.season.has_any_not_winter() } - def seed_check_if_usual_source(self, seed_name: str): + def has_seed_unlocked(self, seed_name: str): if self.options.cropsanity == Cropsanity.option_disabled: return True_() return self.logic.received(seed_name) From cbf6bc9c1afc60f7c41a6a669d92b92d29f4eeb3 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 12:11:52 -0600 Subject: [PATCH 299/482] Swap season order --- worlds/stardew_valley/mods/logic/item_logic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 7a6c148d4964..fb1ffa1c0afc 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -130,8 +130,8 @@ def get_distant_lands_item_rules(self): DistantLandsFish.purple_algae: self.logic.fishing.can_fish_at(Region.witch_swamp), DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.has_seed_unlocked(DistantLandsSeed.vile_ancient_fruit), DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.has_seed_unlocked(DistantLandsSeed.void_mint), - DistantLandsCrop.void_mint: self.logic.has(DistantLandsSeed.void_mint) & self.logic.season.has_any_not_winter(), - DistantLandsCrop.vile_ancient_fruit: self.logic.has(DistantLandsSeed.vile_ancient_fruit) & self.logic.season.has_any_not_winter() + DistantLandsCrop.void_mint: self.logic.season.has_any_not_winter() & self.logic.has(DistantLandsSeed.void_mint), + DistantLandsCrop.vile_ancient_fruit: self.logic.season.has_any_not_winter() & self.logic.has(DistantLandsSeed.vile_ancient_fruit), } def has_seed_unlocked(self, seed_name: str): From 59f3b9b048712e7c108d372690a3d8ff7eebf28a Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 12:13:40 -0600 Subject: [PATCH 300/482] Make weapons_count only run once --- worlds/stardew_valley/items.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 4359d365c964..46bd2f59344f 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -231,16 +231,17 @@ def create_backpack_items(item_factory: StardewItemFactory, options: StardewVall def create_weapons(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + weapons = weapons_count(options) items.extend(item_factory(item) for item in [APWeapon.slingshot] * 2) monstersanity = options.monstersanity if monstersanity == Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons - items.extend(item_factory(item) for item in [APWeapon.weapon] * weapons_count(options)) + items.extend(item_factory(item) for item in [APWeapon.weapon] * weapons) items.extend(item_factory(item) for item in [APWeapon.footwear] * 3) # 1-2 | 3-4 | 6-7-8 return - items.extend(item_factory(item) for item in [APWeapon.sword] * weapons_count(options)) - items.extend(item_factory(item) for item in [APWeapon.club] * weapons_count(options)) - items.extend(item_factory(item) for item in [APWeapon.dagger] * weapons_count(options)) + items.extend(item_factory(item) for item in [APWeapon.sword] * weapons) + items.extend(item_factory(item) for item in [APWeapon.club] * weapons) + items.extend(item_factory(item) for item in [APWeapon.dagger] * weapons) items.extend(item_factory(item) for item in [APWeapon.footwear] * 4) # 1-2 | 3-4 | 6-7-8 | 11-13 if monstersanity == Monstersanity.option_goals or monstersanity == Monstersanity.option_one_per_category or \ monstersanity == Monstersanity.option_short_goals or monstersanity == Monstersanity.option_very_short_goals: From 0f411985f28db266e0372236bd6b6a3c439633c4 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 18:07:43 -0600 Subject: [PATCH 301/482] Combining runes to avoid patcher error --- worlds/stardew_valley/data/items.csv | 8 ++++---- worlds/stardew_valley/rules.py | 8 ++++---- worlds/stardew_valley/strings/ap_names/mods/mod_items.py | 8 +++----- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 1ee00327e922..14f4e85fb8b2 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -805,12 +805,12 @@ id,name,classification,groups,mod_name 10504,Krobus' Protection,useful,,Stardew Valley Expanded 10505,Kittyfish Spell,progression,,Stardew Valley Expanded 10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded -10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo and Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded 10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded 10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded -10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded -10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded +10510,Nexus: Outpost Runes,filler,DEPRECATED,Stardew Valley Expanded +10511,Nexus: Farm and Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded +10512,Nexus: Wizard Runes,filler,DEPRECATED,Stardew Valley Expanded 10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded 10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 020975a0ece3..f57f40d2d5e1 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -914,17 +914,17 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.aurora_warp_to_aurora, player), logic.received("Nexus: Aurora Vineyard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.farm_warp_to_farm, player), - logic.received("Nexus: Farm Runes")) + logic.received("Nexus: Farm and Wizard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.guild_warp_to_guild, player), logic.received("Nexus: Adventurer's Guild Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.junimo_warp_to_junimo, player), - logic.received("Nexus: Junimo Woods Runes")) + logic.received("Nexus: Junimo and Outpost Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.spring_warp_to_spring, player), logic.received("Nexus: Sprite Spring Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.outpost_warp_to_outpost, player), - logic.received("Nexus: Outpost Runes")) + logic.received("Nexus: Junimo and Outpost Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_warp_to_wizard, player), - logic.received("Nexus: Wizard Runes")) + logic.received("Nexus: Farm and Wizard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), logic.relationship.has_hearts(ModNPC.apples, 10)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index ed7c991295b7..1e5f39493dbe 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -26,12 +26,10 @@ class SVELocation: class SVERunes: nexus_guild = "Nexus: Adventurer's Guild Runes" - nexus_junimo = "Nexus: Junimo Woods Runes" + nexus_junimo_outpost = "Nexus: Junimo and Outpost Runes" nexus_aurora = "Nexus: Aurora Vineyard Runes" nexus_spring = "Nexus: Sprite Spring Runes" - nexus_outpost = "Nexus: Outpost Runes" - nexus_farm = "Nexus: Farm Runes" - nexus_wizard = "Nexus: Wizard Runes" + nexus_farm_wizard = "Nexus: Farm and Wizard Runes" - nexus_items: List[str] = [nexus_wizard, nexus_farm, nexus_outpost, nexus_spring, nexus_aurora, nexus_guild, nexus_junimo] + nexus_items: List[str] = [nexus_farm_wizard, nexus_spring, nexus_aurora, nexus_guild, nexus_junimo_outpost] From 78254fe32f82f13a0d09ab59b66dee75de846149 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 20:19:55 -0600 Subject: [PATCH 302/482] Mark items as progression, fix tests. --- worlds/stardew_valley/data/items.csv | 4 ++-- worlds/stardew_valley/test/mods/TestMods.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 14f4e85fb8b2..dc547f76e709 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -808,9 +808,9 @@ id,name,classification,groups,mod_name 10507,Nexus: Junimo and Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded 10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded 10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,filler,DEPRECATED,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,DEPRECATED,Stardew Valley Expanded 10511,Nexus: Farm and Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded -10512,Nexus: Wizard Runes,filler,DEPRECATED,Stardew Valley Expanded +10512,Nexus: Wizard Runes,progression,DEPRECATED,Stardew Valley Expanded 10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded 10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index b020328976c9..17a16cc6d0bc 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -63,6 +63,7 @@ def test_all_progression_items_are_added_to_the_pool(self): all_created_items = [item.name for item in self.multiworld.itempool] # Ignore all the stuff that the algorithm chooses one of, instead of all, to fulfill logical progression items_to_ignore = [event.name for event in items.events] + items_to_ignore.extend(deprecated.name for deprecated in items.items_by_group[Group.DEPRECATED]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) @@ -90,6 +91,7 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): all_created_items = [item.name for item in self.multiworld.itempool] # Ignore all the stuff that the algorithm chooses one of, instead of all, to fulfill logical progression items_to_ignore = [event.name for event in items.events] + items_to_ignore.extend(deprecated.name for deprecated in items.items_by_group[Group.DEPRECATED]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) From cb7f19c965fc91a4eec40701f2457d7991b05f82 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 5 Dec 2023 22:02:06 -0500 Subject: [PATCH 303/482] - Improve documentation --- worlds/stardew_valley/options.py | 8 +++++++- worlds/stardew_valley/test/TestGeneration.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 98ac0247054f..9ede66ed2a47 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -112,17 +112,23 @@ class BundleRandomization(Choice): class BundlePrice(Choice): """How many items are needed for the community center bundles? + Minimum: Every bundle will require only one item Very Cheap: Every bundle will require 2 items fewer than usual Cheap: Every bundle will require 1 item fewer than usual Normal: Every bundle will require the vanilla number of items - Expensive: Every bundle will require 1 extra item when applicable""" + Expensive: Every bundle will require 1 extra item + Very Expensive: Every bundle will require 2 extra items + Maximum: Every bundle will require many extra items""" internal_name = "bundle_price" display_name = "Bundle Price" default = 0 + option_minimum = -8 option_very_cheap = -2 option_cheap = -1 option_normal = 0 option_expensive = 1 + option_very_expensive = 2 + option_maximum = 8 class EntranceRandomization(Choice): diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 07a071809e5b..939ace5a58a2 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -396,7 +396,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2640 + expected_locations = 2693 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) From 5ab0aea1fc8e6cb179659721ec047d82b24a7dc3 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 5 Dec 2023 22:40:12 -0500 Subject: [PATCH 304/482] - Rebase from main --- worlds/stardew_valley/items.py | 17 ++++++++--------- worlds/stardew_valley/logic/logic.py | 8 +++++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 46bd2f59344f..4105a51d67c0 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -624,8 +624,8 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options priority_filler_items.extend(trap_items) exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true - all_filler_packs = get_all_filler_items(include_traps, exclude_ginger_island) - priority_filler_items = remove_excluded_items(priority_filler_items, exclude_ginger_island) + all_filler_packs = remove_excluded_items(get_all_filler_items(include_traps, exclude_ginger_island), options) + priority_filler_items = remove_excluded_items(priority_filler_items, options) number_priority_items = len(priority_filler_items) required_resource_pack = number_locations - len(items_already_added) @@ -667,9 +667,8 @@ def filter_deprecated_items(items: List[ItemData]) -> List[ItemData]: return [item for item in items if Group.DEPRECATED not in item.groups] -def filter_ginger_island_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: - include_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false - return [item for item in items if include_island or Group.GINGER_ISLAND not in item.groups] +def filter_ginger_island_items(exclude_island: bool, items: List[ItemData]) -> List[ItemData]: + return [item for item in items if not exclude_island or Group.GINGER_ISLAND not in item.groups] def filter_mod_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: @@ -678,7 +677,7 @@ def filter_mod_items(options: StardewValleyOptions, items: List[ItemData]) -> Li def remove_excluded_items(items, options): deprecated_filter = filter_deprecated_items(items) - ginger_island_filter = filter_ginger_island_items(options, deprecated_filter) + ginger_island_filter = filter_ginger_island_items(options.exclude_ginger_island == ExcludeGingerIsland.option_true, deprecated_filter) mod_filter = filter_mod_items(options, ginger_island_filter) return mod_filter @@ -692,12 +691,12 @@ def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool): all_filler_packs.extend(items_by_group[Group.TRASH]) if include_traps: all_filler_packs.extend(items_by_group[Group.TRAP]) - all_filler_packs = remove_excluded_packs(all_filler_packs, exclude_ginger_island) + all_filler_packs = filter_ginger_island_items(exclude_ginger_island, all_filler_packs) return all_filler_packs -def get_stardrop_classification(world_options) -> ItemClassification: - return ItemClassification.progression_skip_balancing if world_is_perfection(world_options) else ItemClassification.useful +def get_stardrop_classification(options) -> ItemClassification: + return ItemClassification.progression_skip_balancing if world_is_perfection(options) or world_is_stardrops(options) else ItemClassification.useful def world_is_perfection(options) -> bool: diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index be9e0ae82b6c..c591f0414dd8 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -649,6 +649,7 @@ def has_walnut(self, number: int) -> StardewRule: reach_west = self.region.can_reach(Region.island_west) reach_hut = self.region.can_reach(Region.leo_hut) reach_southeast = self.region.can_reach(Region.island_south_east) + reach_field_office = self.region.can_reach(Region.field_office) reach_pirate_cove = self.region.can_reach(Region.pirate_cove) reach_outside_areas = And(reach_south, reach_north, reach_west, reach_hut) reach_volcano_regions = [self.region.can_reach(Region.volcano), @@ -657,13 +658,13 @@ def has_walnut(self, number: int) -> StardewRule: self.region.can_reach(Region.volcano_floor_10)] reach_volcano = Or(*reach_volcano_regions) reach_all_volcano = And(*reach_volcano_regions) - reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano] + reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano, reach_field_office] reach_caves = And(self.region.can_reach(Region.qi_walnut_room), self.region.can_reach(Region.dig_site), self.region.can_reach(Region.gourmand_frog_cave), self.region.can_reach(Region.colored_crystals_cave), self.region.can_reach(Region.shipwreck), self.received(APWeapon.slingshot)) reach_entire_island = And(reach_outside_areas, reach_all_volcano, - reach_caves, reach_southeast, reach_pirate_cove) + reach_caves, reach_southeast, reach_field_office, reach_pirate_cove) if number <= 5: return Or(reach_south, reach_north, reach_west, reach_volcano) if number <= 10: @@ -676,7 +677,8 @@ def has_walnut(self, number: int) -> StardewRule: return reach_entire_island gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz) return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ - self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) + self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) & \ + self.can_complete_field_office() def has_all_stardrops(self) -> StardewRule: other_rules = [] From 36389d8eb73ce88943575af74615bc75454d190f Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 5 Dec 2023 23:05:12 -0500 Subject: [PATCH 305/482] explain room while explaining location accesss --- worlds/stardew_valley/stardew_rule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index a3357e338305..9a509d6a3332 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -662,11 +662,11 @@ def get_difficulty(self): return 1 def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - # FIXME this should be in core if self.resolution_hint == 'Location': spot = state.multiworld.get_location(self.spot, self.player) - # TODO explain virtual reach for room access_rule = spot.access_rule + if isinstance(access_rule, StardewRule): + access_rule = And(access_rule, Reach(spot.parent_region.name, "Region", self.player)) elif self.resolution_hint == 'Entrance': spot = state.multiworld.get_entrance(self.spot, self.player) access_rule = spot.access_rule From e598f9bde85548f8ea43e1a9633854f60a9158c0 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 5 Dec 2023 23:13:21 -0500 Subject: [PATCH 306/482] remove default true rule on location --- worlds/stardew_valley/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 008f87725e5b..a73addd74956 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -112,7 +112,6 @@ def create_region(name: str, exits: Iterable[str]) -> Region: def add_location(name: str, code: Optional[int], region: str): region = world_regions[region] location = StardewLocation(self.player, name, code, region) - location.access_rule = lambda _: True region.locations.append(location) create_locations(add_location, self.modified_bundles, self.options, self.multiworld.random) @@ -321,7 +320,6 @@ def get_filler_item_rules(self): for player in link_group["players"]: player_options = self.multiworld.worlds[player].options if self.multiworld.game[player] != self.game: - continue if player_options.trap_items == TrapItems.option_no_traps: include_traps = False From f586f97134a196e5f6ce7acfe9617647cf0b60e9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 5 Dec 2023 23:16:35 -0500 Subject: [PATCH 307/482] - Fixed Qi bundles --- worlds/stardew_valley/bundles/bundle.py | 48 ++++++++++++++------ worlds/stardew_valley/bundles/bundle_room.py | 5 +- worlds/stardew_valley/data/bundle_data.py | 2 +- worlds/stardew_valley/data/locations.csv | 46 +++++++++++-------- worlds/stardew_valley/items.py | 2 - worlds/stardew_valley/logic/money_logic.py | 13 ++++-- 6 files changed, 74 insertions(+), 42 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index 583c0c92c659..68b1c397340a 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -2,6 +2,7 @@ from typing import List from .bundle_item import BundleItem +from ..options import BundlePrice from ..strings.currency_names import Currency @@ -39,10 +40,13 @@ def __init__(self, room: str, name: str, items: List[BundleItem], number_possibl def extend_from(template, items: List[BundleItem]): return BundleTemplate(template.room, template.name, items, template.number_possible_items, template.number_required_items) - def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: - number_required = self.number_required_items + price_difference - if price_difference > 0 and self.number_possible_items > 10: - number_required += price_difference + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + if bundle_price_option == BundlePrice.option_minimum: + number_required = 1 + elif bundle_price_option == BundlePrice.option_maximum: + number_required = 8 + else: + number_required = self.number_required_items + bundle_price_option.value number_required = max(1, number_required) filtered_items = [item for item in self.items if allow_island_items or not item.requires_island] number_items = len(filtered_items) @@ -68,12 +72,18 @@ def __init__(self, room: str, name: str, item: BundleItem): super().__init__(room, name, [item], 1, 1) self.item = item - def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: - currency_amount = self.get_currency_amount(price_difference) + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + currency_amount = self.get_currency_amount(bundle_price_option) return Bundle(self.room, self.name, [BundleItem(self.item.item_name, currency_amount)], 1) - def get_currency_amount(self, price_difference): - price_multiplier = round(1 + (price_difference * 0.4), 2) + def get_currency_amount(self, bundle_price_option: BundlePrice): + if bundle_price_option == BundlePrice.option_minimum: + price_multiplier = 0.1 + elif bundle_price_option == BundlePrice.option_maximum: + price_multiplier = 4 + else: + price_multiplier = round(1 + (bundle_price_option.value * 0.4), 2) + currency_amount = int(self.item.amount * price_multiplier) return currency_amount @@ -87,8 +97,8 @@ class MoneyBundleTemplate(CurrencyBundleTemplate): def __init__(self, room: str, item: BundleItem): super().__init__(room, "", item) - def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: - currency_amount = self.get_currency_amount(price_difference) + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + currency_amount = self.get_currency_amount(bundle_price_option) currency_name = "g" if currency_amount >= 1000: unit_amount = currency_amount % 1000 @@ -99,8 +109,13 @@ def create_bundle(self, price_difference: int, random: Random, allow_island_item name = f"{currency_display}{currency_name} Bundle" return Bundle(self.room, name, [BundleItem(self.item.item_name, currency_amount)], 1) - def get_currency_amount(self, price_difference): - price_multiplier = round(1 + (price_difference * 0.4), 2) + def get_currency_amount(self, bundle_price_option: BundlePrice): + if bundle_price_option == BundlePrice.option_minimum: + price_multiplier = 0.1 + elif bundle_price_option == BundlePrice.option_maximum: + price_multiplier = 4 + else: + price_multiplier = round(1 + (bundle_price_option.value * 0.4), 2) currency_amount = int(self.item.amount * price_multiplier) return currency_amount @@ -119,8 +134,13 @@ def __init__(self, room: str, name: str, categories: List[List[BundleItem]], num super().__init__(room, name, [], number_possible_items, number_required_items) self.categories = categories - def create_bundle(self, price_difference: int, random: Random, allow_island_items: bool) -> Bundle: - number_required = self.number_required_items + price_difference + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + if bundle_price_option == BundlePrice.option_minimum: + number_required = 1 + elif bundle_price_option == BundlePrice.option_maximum: + number_required = 8 + else: + number_required = self.number_required_items + bundle_price_option.value number_categories = len(self.categories) number_chosen_categories = self.number_possible_items if number_chosen_categories < number_required: diff --git a/worlds/stardew_valley/bundles/bundle_room.py b/worlds/stardew_valley/bundles/bundle_room.py index b2c84a1fa9c0..688e8ed5ba36 100644 --- a/worlds/stardew_valley/bundles/bundle_room.py +++ b/worlds/stardew_valley/bundles/bundle_room.py @@ -2,6 +2,7 @@ from typing import List from .bundle import Bundle, BundleTemplate +from ..options import BundlePrice class BundleRoom: @@ -23,7 +24,7 @@ def __init__(self, name: str, bundles: List[BundleTemplate], number_bundles: int self.bundles = bundles self.number_bundles = number_bundles - def create_bundle_room(self, price_difference: int, random: Random, allow_island_items: bool): + def create_bundle_room(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool): filtered_bundles = [bundle for bundle in self.bundles if allow_island_items or not bundle.requires_island] chosen_bundles = random.sample(filtered_bundles, self.number_bundles) - return BundleRoom(self.name, [bundle.create_bundle(price_difference, random, allow_island_items) for bundle in chosen_bundles]) + return BundleRoom(self.name, [bundle.create_bundle(bundle_price_option, random, allow_island_items) for bundle in chosen_bundles]) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 833639208849..a7957e2081ee 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -696,7 +696,7 @@ vault_walnut_hunter_items = BundleItem(Currency.golden_walnut, 25) vault_walnut_hunter_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.walnut_hunter, vault_walnut_hunter_items) -vault_qi_helper_items = BundleItem(Currency.qi_gem, 25) +vault_qi_helper_items = IslandBundleItem(Currency.qi_gem, 25) vault_qi_helper_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.qi_helper, vault_qi_helper_items) vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3992b80062e8..3ad7c050b225 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -65,26 +65,34 @@ id,region,name,tags,mod_name 70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -74,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -75,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -76,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -77,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -80,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -81,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -82,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -83,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -84,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -85,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +73,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +74,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +75,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +76,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +77,Vault,250g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +78,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +79,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +80,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +81,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +82,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +83,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +84,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +85,Vault,"4,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -87,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -88,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -89,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -90,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -91,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -92,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -93,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -94,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -95,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +87,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +88,Vault,"9,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +89,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +90,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +91,Vault,"18,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,"20,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,"40,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,"45,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +96,Vault,"100,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +97,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +98,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +99,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +100,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", 101,Pierre's General Store,Large Pack,BACKPACK, 102,Pierre's General Store,Deluxe Pack,BACKPACK, 103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 4105a51d67c0..c67af886fee1 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -512,8 +512,6 @@ def create_special_order_qi_rewards(item_factory: StardewItemFactory, options: S if options.bundle_randomization >= BundleRandomization.option_remixed: qi_gem_rewards.append("15 Qi Gems") qi_gem_rewards.append("15 Qi Gems") - if options.bundle_price >= BundlePrice.option_expensive: - qi_gem_rewards.append("15 Qi Gems") if options.special_order_locations == SpecialOrderLocations.option_board_qi: qi_gem_rewards.extend(["100 Qi Gems", "10 Qi Gems", "40 Qi Gems", "25 Qi Gems", "25 Qi Gems", diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 9e27fd2038fb..a601aa867515 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -7,13 +7,14 @@ from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin +from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, HasProgressionPercent, False_ from ..strings.currency_names import Currency from ..strings.region_names import Region from ..strings.ap_names.event_names import Event -qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "40 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", - "25 Qi Gems", "20 Qi Gems", "10 Qi Gems", "15 Qi Gems", "15 Qi Gems", "15 Qi Gems") +qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", + "20 Qi Gems", "15 Qi Gems", "10 Qi Gems") class MoneyLogicMixin(BaseLogicMixin): @@ -56,8 +57,12 @@ def can_trade(self, currency: str, amount: int) -> StardewRule: if currency == Currency.qi_coin: return self.logic.region.can_reach(Region.casino) & self.logic.buff.has_max_luck() if currency == Currency.qi_gem: - number_rewards = min(13, max(1, (amount // 10))) - return self.logic.received(qi_gem_rewards, number_rewards) + if self.options.special_order_locations == SpecialOrderLocations.option_board_qi: + number_rewards = min(len(qi_gem_rewards), max(1, (amount // 10))) + return self.logic.received(qi_gem_rewards, number_rewards) + number_rewards = 2 + return self.logic.received(qi_gem_rewards, number_rewards) & self.logic.region.can_reach(Region.qi_walnut_room) & \ + self.logic.region.can_reach(Region.saloon) & self.can_have_earned_total(5000) if currency == Currency.golden_walnut: return self.can_spend_walnut(amount) From a1a9a10a7d0bd88e5c332d3ed1fe1f973ef792c2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 5 Dec 2023 23:26:45 -0500 Subject: [PATCH 308/482] - Fixed early shipping bin --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/items.py | 2 +- worlds/stardew_valley/options.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index a73addd74956..a3c669870af1 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -181,7 +181,7 @@ def precollect_starting_season(self): self.multiworld.push_precollected(starting_season) def setup_early_items(self): - if self.options.building_progression & BuildingProgression.option_progressive_early_shipping_bin: + if self.options.building_progression & BuildingProgression.early_shipping_bin: self.multiworld.early_items[self.player]["Shipping Bin"] = 1 if self.options.backpack_progression == BackpackProgression.option_early_progressive: diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index c67af886fee1..fb12879c7191 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -315,7 +315,7 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, options: Starde items.append(item_factory("Fish Pond")) items.append(item_factory("Stable")) items.append(item_factory("Slime Hutch")) - needs_early_bin = building_option & BuildingProgression.option_progressive_early_shipping_bin + needs_early_bin = building_option & BuildingProgression.early_shipping_bin has_shipsanity = options.shipsanity != Shipsanity.option_none need_shipping = needs_early_bin or has_shipsanity or world_is_perfection(options) items.append(item_factory("Shipping Bin", ItemClassification.progression if need_shipping else ItemClassification.useful)) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 9ede66ed2a47..8bc9373f987e 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -263,6 +263,7 @@ class BuildingProgression(Choice): option_progressive = 0b0001 # 1 option_progressive_cheap = 0b0101 # 5 option_progressive_very_cheap = 0b1001 # 9 + early_shipping_bin = 0b0010 # 2 option_progressive_early_shipping_bin = 0b0011 # 3 option_progressive_early_shipping_bin_cheap = 0b0111 # 7 option_progressive_early_shipping_bin_very_cheap = 0b1011 # 11 From 53797cf7845d50a4feb11479508fcc1b373c9daf Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 6 Dec 2023 00:17:15 -0500 Subject: [PATCH 309/482] - Fix cache for failing tests --- worlds/stardew_valley/stardew_rule.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 9a509d6a3332..e5ffde8476c5 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from collections import deque from dataclasses import dataclass, field -from functools import cached_property, cache +from functools import cached_property from itertools import chain from threading import Lock from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional @@ -648,7 +648,6 @@ class Reach(StardewRule): resolution_hint: str player: int - @cache def __new__(cls, *args, **kwargs): return super().__new__(cls) From 50c01829dfc7d1388afc1c303f9e904b4abcf859 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 5 Dec 2023 23:10:59 -0600 Subject: [PATCH 310/482] Fix Highlands Names --- worlds/stardew_valley/data/locations.csv | 34 +++++++++---------- worlds/stardew_valley/mods/mod_regions.py | 4 ++- .../stardew_valley/strings/entrance_names.py | 9 ++--- worlds/stardew_valley/strings/region_names.py | 5 +-- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3ad7c050b225..13fb31ea06c3 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2312,20 +2312,20 @@ id,region,name,tags,mod_name 6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded 6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded 6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded -6153,Highlands,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6154,Highlands,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6155,Highlands,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6156,Highlands,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6157,Highlands,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6158,Highlands,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6159,Highlands,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6160,Highlands,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6161,Highlands,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6162,Highlands,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6163,Highlands,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6164,Highlands,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6165,Highlands,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6166,Highlands,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6153,Highlands Outside,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Highlands Outside,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Highlands Outside,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Highlands Outside,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Highlands Outside,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Highlands Outside,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Highlands Outside,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Highlands Outside,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Highlands Outside,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Highlands Outside,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Highlands Outside,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Highlands Outside,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Highlands Outside,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Highlands Outside,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded 6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded 6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded 6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2574,15 +2574,15 @@ id,region,name,tags,mod_name 7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded 7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7654,Highlands,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7654,Lance's House Main,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded 7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded 7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded 7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded 7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7706,Highlands,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7706,Highlands Outside,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7708,Highlands,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7708,Highlands Outside,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded 7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded 7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 54d9894ca91e..c84b55dc85fd 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -180,7 +180,8 @@ RegionData(SVERegion.highlands, [SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave]), RegionData(SVERegion.highlands_cavern, [SVEEntrance.to_dwarf_prison]), RegionData(SVERegion.dwarf_prison), - RegionData(SVERegion.lances_house, [SVEEntrance.lance_ladder_to_highlands]), + RegionData(SVERegion.lances_house, [SVEEntrance.lance_to_ladder]), + RegionData(SVERegion.lances_ladder, [SVEEntrance.lance_ladder_to_highlands]), RegionData(SVERegion.forest_west, [SVEEntrance.forest_west_to_spring, SVEEntrance.west_to_aurora, SVEEntrance.use_bear_shop]), RegionData(SVERegion.aurora_vineyard, [SVEEntrance.to_aurora_basement]), @@ -253,6 +254,7 @@ ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder), ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 221dc6347a85..838cb571fbd3 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -298,7 +298,7 @@ class SVEEntrance: guild_to_interior = "Guild Summit to Adventurer's Guild" guild_to_mines = "Guild Summit to The Mines" summit_to_boat = "Guild Summit to Marlon's Boat" - summit_to_highlands = "Guild Summit to Highlands" + summit_to_highlands = "Guild Summit to Highlands Outside" to_aurora_basement = "Aurora Vineyard to Aurora Vineyard Basement" outpost_to_badlands_entrance = "Galmoran Outpost to Badlands Entrance" use_alesia_shop = "Talk to Alesia" @@ -308,10 +308,11 @@ class SVEEntrance: to_susan_house = "Railroad to Susan's House" enter_summit = "Railroad to Summit" fable_reef_to_guild = "Fable Reef to First Slash Guild" - highlands_to_lance = "Highlands to Lance's House Main" - highlands_to_cave = "Highlands to Highlands Cavern" + highlands_to_lance = "Highlands Outside to Lance's House Main" + lance_to_ladder = "Lance's House Main to Lance's House Ladder" + highlands_to_cave = "Highlands Outside to Highlands Cavern" to_dwarf_prison = "Highlands Cavern to Highlands Cavern Prison" - lance_ladder_to_highlands = "Lance's House Ladder to Highlands" + lance_ladder_to_highlands = "Lance's House Ladder to Highlands Outside" forest_west_to_spring = "Forest West to Sprite Spring" west_to_aurora = "Forest West to Aurora Vineyard" use_bear_shop = "Talk to Bear Shop" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 89acc85903d2..52c07975fc1e 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -241,10 +241,11 @@ class SVERegion: guild_summit = "Guild Summit" fable_reef = "Fable Reef" first_slash_guild = "First Slash Guild" - highlands = "Highlands" + highlands = "Highlands Outside" highlands_cavern = "Highlands Cavern" dwarf_prison = "Highlands Cavern Prison" - lances_house = "Lance's House" + lances_house = "Lance's House Main" + lances_ladder = "Lance's House Ladder" forest_west = "Forest West" aurora_vineyard = "Aurora Vineyard" aurora_vineyard_basement = "Aurora Vineyard Basement" From 8424f253be3255a02a42b1a00dff4c14633c064e Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 5 Dec 2023 23:29:23 -0500 Subject: [PATCH 311/482] rewrite comments --- worlds/stardew_valley/stardew_rule.py | 30 ++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index e5ffde8476c5..7171a01f1f2c 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -319,22 +319,22 @@ def short_circuit_evaluation(self, rule): def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: """ - The idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. + The global idea here is the same as short-circuiting operators, applied to evaluation and rule simplification. """ - # Directly checking last rule that evaluated to complement, in case state has not changed. + # Directly checking last rule that short-circuited, in case state has not changed. if self._last_short_circuiting_rule: if self._last_short_circuiting_rule(state) is self.complement.value: return self.short_circuit_evaluation(self._last_short_circuiting_rule) self._last_short_circuiting_rule = None - # Combinable rules are considered already simplified, so we evaluate them right away. + # Combinable rules are considered already simplified, so we evaluate them right away to go faster. for rule in self.combinable_rules.values(): if rule(state) is self.complement.value: return self.short_circuit_evaluation(rule) if self.simplification_state.is_simplified: - # The expression is fully simplified, so we can only evaluate. + # The rule is fully simplified, so now we can only evaluate. for rule in self.simplification_state.simplified_rules: if rule(state) is self.complement.value: return self.short_circuit_evaluation(rule) @@ -345,21 +345,23 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul def evaluate_while_simplifying_stateful(self, state): local_state = self.simplification_state try: - # Creating a new copy, so we don't modify the rules while we're already evaluating it. + # Creating a new copy, so we don't modify the rules while we're already evaluating it. This can happen if a rule is used for an entrance and a + # location. When evaluating a given rule what requires access to a region, the region cache can get an update. If it does, we could enter this rule + # again. Since the simplification is stateful, the set of simplified rules can be modified while it's being iterated on, and cause a crash. + # # After investigation, for millions of call to this method, copy were acquired 425 times. # Merging simplification state in parent call was deemed useless. if not local_state.acquire(): local_state = local_state.acquire_copy() self.simplification_state = local_state - # Evaluating what has already been simplified. - # The assumption is that the rules that used to evaluate to complement might complement again, so we can leave early. + # Evaluating what has already been simplified. First it will be faster than simplifying "new" rules, but we also assume that if we reach this point + # and there are already are simplified rule, one of these rules has short-circuited, and might again, so we can leave early. for rule in local_state.simplified_rules: if rule(state) is self.complement.value: return self.short_circuit_evaluation(rule) - # If the iterator is None, it means we have not start simplifying. - # Otherwise, we will continue simplification where we left. + # If the queue is None, it means we have not start simplifying. Otherwise, we will continue simplification where we left. if local_state.rules_to_simplify is None: rules_to_simplify = frozenset(local_state.original_simplifiable_rules) if self.complement in rules_to_simplify: @@ -373,7 +375,7 @@ def evaluate_while_simplifying_stateful(self, state): if result is not None: return result - # The whole rule has been simplified and evaluated without finding complement. + # The whole rule has been simplified and evaluated without short-circuit. return self, self.identity.value finally: local_state.release() @@ -381,17 +383,17 @@ def evaluate_while_simplifying_stateful(self, state): def evaluate_rule_while_simplifying_stateful(self, local_state, state): simplified, value = local_state.rules_to_simplify[0].evaluate_while_simplifying(state) - # Identity is removed from the resulting simplification. + # Identity is removed from the resulting simplification since it does not affect the result. if simplified is self.identity: return - # If we find a complement here, we know the rule will always resolve to its value. + # If we find a complement here, we know the rule will always short-circuit, what ever the state. if simplified is self.complement: return self.short_circuit_simplification() - # Keep the simplified rule to be reused. + # Keep the simplified rule to be reevaluated later. local_state.simplified_rules.add(simplified) - # Now we use the value, to exit early if it evaluates to the complement. + # Now we use the value to short-circuit if it is the complement. if value is self.complement.value: return self.short_circuit_evaluation(simplified) From 41202161c98adeb178dc013f87cdf9d521d2304c Mon Sep 17 00:00:00 2001 From: Jouramie Date: Wed, 6 Dec 2023 00:01:11 -0500 Subject: [PATCH 312/482] add more logic and review tests --- worlds/stardew_valley/stardew_rule.py | 6 +-- worlds/stardew_valley/test/TestStardewRule.py | 50 +++++-------------- 2 files changed, 16 insertions(+), 40 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 7171a01f1f2c..35ddfddcb37b 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -234,6 +234,9 @@ def release(self): class AggregatingStardewRule(StardewRule, ABC): + """ + Logic for both "And" and "Or" rules. + """ identity: LiteralStardewRule complement: LiteralStardewRule symbol: str @@ -408,13 +411,10 @@ def __eq__(self, other): self.simplification_state.original_simplifiable_rules == self.simplification_state.original_simplifiable_rules) def __hash__(self): - # TODO since other_rules will be changed after simplification, a simplified rule will have a different hashcode than its original. - # Ideally, two rules with the same simplification would be equal... return hash((self.combinable_rules, self.simplification_state.original_simplifiable_rules)) def simplify(self) -> StardewRule: logger.debug(f"Unoptimized 'simplified' called on {self}") - # TODO is this needed now that we're using an iterator ? if self.simplification_state.is_simplified: return self diff --git a/worlds/stardew_valley/test/TestStardewRule.py b/worlds/stardew_valley/test/TestStardewRule.py index 7f384e3e8cd2..89317d90e4e2 100644 --- a/worlds/stardew_valley/test/TestStardewRule.py +++ b/worlds/stardew_valley/test/TestStardewRule.py @@ -1,63 +1,39 @@ import unittest -from unittest import skip from unittest.mock import MagicMock, Mock -from ..stardew_rule import Received, Has, False_, And, Or, True_, HasProgressionPercent, false_, true_ +from ..stardew_rule import Received, And, Or, HasProgressionPercent, false_, true_ class TestSimplification(unittest.TestCase): - def test_simplify_true_in_and(self): - rules = { - "Wood": True_(), - "Rock": True_(), - } - summer = Received("Summer", 0, 1) - self.assertEqual(summer, (Has("Wood", rules) & summer & Has("Rock", rules)).simplify()) - - def test_simplify_false_in_or(self): - rules = { - "Wood": False_(), - "Rock": False_(), - } - summer = Received("Summer", 0, 1) - self.assertEqual(summer, (Has("Wood", rules) | summer | Has("Rock", rules)).simplify()) + """ + Those feature of simplifying the rules when they are built have proven to improve the fill speed considerably. + """ def test_simplify_and_and_and(self): rule = And(Received('Summer', 0, 1), Received('Fall', 0, 1)) & And(Received('Winter', 0, 1), Received('Spring', 0, 1)) - self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule) def test_simplify_and_in_and(self): - """ - Those feature of simplifying the rules when they are built have proven to improve the fill speed considerably. - """ rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), And(Received('Winter', 0, 1), Received('Spring', 0, 1))) - self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule) - @skip("This feature has been disabled and that seems to save time") def test_simplify_duplicated_and(self): + # This only works because "Received"s are combinable. rule = And(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), And(Received('Summer', 0, 1), Received('Fall', 0, 1))) - self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) + self.assertEqual(And(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule) def test_simplify_or_or_or(self): rule = Or(Received('Summer', 0, 1), Received('Fall', 0, 1)) | Or(Received('Winter', 0, 1), Received('Spring', 0, 1)) - self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule) 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))) - self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule.simplify()) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1), Received('Winter', 0, 1), Received('Spring', 0, 1)), rule) - @skip("This feature has been disabled and that seems to save time") 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))) - self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule.simplify()) - - def test_simplify_true_in_or(self): - rule = Or(True_(), Received('Summer', 0, 1)) - self.assertEqual(True_(), rule.simplify()) - - def test_simplify_false_in_and(self): - rule = And(False_(), Received('Summer', 0, 1)) - self.assertEqual(False_(), rule.simplify()) + rule = Or(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), Or(Received('Summer', 0, 1), Received('Fall', 0, 1))) + self.assertEqual(Or(Received('Summer', 0, 1), Received('Fall', 0, 1)), rule) class TestHasProgressionPercentSimplification(unittest.TestCase): From 6b92e2a807afb2722a34c2d9f5491715378f5635 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Wed, 6 Dec 2023 00:16:58 -0500 Subject: [PATCH 313/482] remove old simplify --- worlds/stardew_valley/stardew_rule.py | 69 ++++++--------------------- 1 file changed, 15 insertions(+), 54 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 35ddfddcb37b..274e0fd315af 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -58,8 +58,9 @@ class StardewRule(ABC): def __call__(self, state: CollectionState) -> bool: raise NotImplementedError + @abstractmethod def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self.simplify(), self(state) + raise NotImplementedError def __or__(self, other) -> StardewRule: if other is true_ or other is false_ or type(other) is Or: @@ -77,9 +78,6 @@ def __and__(self, other) -> StardewRule: def get_difficulty(self): raise NotImplementedError - def simplify(self) -> StardewRule: - return self - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, expected) @@ -413,42 +411,6 @@ def __eq__(self, other): def __hash__(self): return hash((self.combinable_rules, self.simplification_state.original_simplifiable_rules)) - def simplify(self) -> StardewRule: - logger.debug(f"Unoptimized 'simplified' called on {self}") - if self.simplification_state.is_simplified: - return self - - if self.simplification_state.rules_to_simplify is None: - rules_to_simplify = frozenset(self.simplification_state.original_simplifiable_rules) - if self.complement in rules_to_simplify: - return self.short_circuit_simplification()[0] - - self.simplification_state.rules_to_simplify = deque(rules_to_simplify) - - # TODO this should lock state - while self.simplification_state.rules_to_simplify: - rule = self.simplification_state.rules_to_simplify.pop() - simplified = rule.simplify() - - if simplified is self.identity or simplified in self.simplification_state.simplified_rules: - continue - - if simplified is self.complement: - return self.short_circuit_simplification()[0] - - self.simplification_state.simplified_rules.add(simplified) - - if not self.simplification_state.simplified_rules and not self.combinable_rules: - return self.identity - - if len(self.simplification_state.simplified_rules) == 1 and not self.combinable_rules: - return next(iter(self.simplification_state.simplified_rules)) - - if not self.simplification_state.simplified_rules and len(self.combinable_rules) == 1: - return next(iter(self.combinable_rules.values())) - - return self - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, expected, self.original_rules) @@ -553,14 +515,6 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul def __call__(self, state: CollectionState) -> bool: return self.evaluate_while_simplifying(state)[1] - def simplify(self): - if self._simplified: - return self - - self.rules = [rule.simplify() for rule in self.rules] - self._simplified = True - return self - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, expected, self.rules) @@ -604,6 +558,9 @@ def __call__(self, state: CollectionState) -> bool: return True return False + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, expected, [Received(i, self.player, 1) for i in self.items]) @@ -635,6 +592,9 @@ def value(self): def __call__(self, state: CollectionState) -> bool: return state.has(self.item, self.player, self.count) + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + def __repr__(self): if self.count == 1: return f"Received {self.item}" @@ -656,6 +616,9 @@ def __new__(cls, *args, **kwargs): def __call__(self, state: CollectionState) -> bool: return state.can_reach(self.spot, self.resolution_hint, self.player) + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + def __repr__(self): return f"Reach {self.resolution_hint} {self.spot}" @@ -691,16 +654,11 @@ def __init__(self, item: str, other_rules: Dict[str, StardewRule]): self.other_rules = other_rules def __call__(self, state: CollectionState) -> bool: - # TODO eval & simplify - self.simplify() - return self.other_rules[self.item](state) + return self.evaluate_while_simplifying(state)[1] def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self.other_rules[self.item].evaluate_while_simplifying(state) - def simplify(self) -> StardewRule: - return self.other_rules[self.item].simplify() - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, expected, [self.other_rules[self.item]]) @@ -750,6 +708,9 @@ def __call__(self, state: CollectionState) -> bool: return True return False + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + def __repr__(self): return f"HasProgressionPercent {self.percent}" From 79bd872b47bfb9185688575171ef469e281a26eb Mon Sep 17 00:00:00 2001 From: Jouramie Date: Wed, 6 Dec 2023 00:23:26 -0500 Subject: [PATCH 314/482] add manual cache --- worlds/stardew_valley/stardew_rule.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 274e0fd315af..86490269f7b6 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -610,8 +610,13 @@ class Reach(StardewRule): resolution_hint: str player: int - def __new__(cls, *args, **kwargs): - return super().__new__(cls) + def __new__(cls, *args, _cache={}, **kwargs): # noqa + try: + return _cache[args] + except KeyError: + instance = super().__new__(cls) + _cache[args] = instance + return instance def __call__(self, state: CollectionState) -> bool: return state.can_reach(self.spot, self.resolution_hint, self.player) From ea7b9ca45dd0e9fe42250ea93f4f2620b7d8ebca Mon Sep 17 00:00:00 2001 From: Jouramie Date: Wed, 6 Dec 2023 00:36:50 -0500 Subject: [PATCH 315/482] k removing the cache...... --- worlds/stardew_valley/stardew_rule.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 86490269f7b6..2b1a2c0f76ac 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -610,14 +610,6 @@ class Reach(StardewRule): resolution_hint: str player: int - def __new__(cls, *args, _cache={}, **kwargs): # noqa - try: - return _cache[args] - except KeyError: - instance = super().__new__(cls) - _cache[args] = instance - return instance - def __call__(self, state: CollectionState) -> bool: return state.can_reach(self.spot, self.resolution_hint, self.player) From f8f302ba5b0344ab34df428a6205a8ea42eec363 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 6 Dec 2023 14:37:47 -0500 Subject: [PATCH 316/482] - Add skeleton requirement to fragments of the past --- worlds/stardew_valley/logic/special_order_logic.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 097424352801..7d2e2f6a7d1d 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -9,6 +9,7 @@ from .has_logic import HasLogicMixin from .mine_logic import MineLogicMixin from .money_logic import MoneyLogicMixin +from .monster_logic import MonsterLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin @@ -30,6 +31,7 @@ from ..strings.material_names import Material from ..strings.metal_names import Mineral from ..strings.monster_drop_names import Loot +from ..strings.monster_names import Monster from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.special_order_names import SpecialOrder @@ -46,7 +48,7 @@ def __init__(self, *args, **kwargs): class SpecialOrderLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, MoneyLogicMixin, ShippingLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, RelationshipLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, CookingLogicMixin, BuffLogicMixin, - AbilityLogicMixin, SpecialOrderLogicMixin]]): + AbilityLogicMixin, SpecialOrderLogicMixin, MonsterLogicMixin]]): def initialize_rules(self): self.update_rules({ @@ -60,7 +62,8 @@ def initialize_rules(self): self.logic.has(Mineral.emerald) & self.logic.has(Mineral.jade) & self.logic.has(Mineral.amethyst) & self.logic.has(ArtisanGood.cloth), SpecialOrder.gifts_for_george: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.logic.region.can_reach(Region.dig_site) & self.logic.tool.has_tool(Tool.pickaxe), + SpecialOrder.fragments_of_the_past: self.logic.region.can_reach(Region.dig_site) & self.logic.tool.has_tool(Tool.pickaxe) & + self.logic.monster.can_kill(Monster.skeleton), SpecialOrder.gus_famous_omelet: self.logic.has(AnimalProduct.any_egg), SpecialOrder.crop_order: self.logic.ability.can_farm_perfectly() & self.logic.received(Event.can_ship_items), SpecialOrder.community_cleanup: self.logic.skill.can_crab_pot, From f55cdd28170053576c4b7cfa0e129c9d3e5c8d32 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:29:21 -0500 Subject: [PATCH 317/482] Add item and location groups --- worlds/stardew_valley/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index a3c669870af1..7d7ba91b8b32 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -8,7 +8,7 @@ from .bundles.bundle_room import BundleRoom from .bundles.bundles import get_all_bundles from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs -from .locations import location_table, create_locations, LocationData +from .locations import location_table, create_locations, LocationData, locations_by_tag from .logic.bundle_logic import BundleLogic from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS @@ -64,6 +64,12 @@ class StardewValleyWorld(World): item_name_to_id = {name: data.code for name, data in item_table.items()} location_name_to_id = {name: data.code for name, data in location_table.items()} + item_name_groups = {group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() + in item_table else ""): + [item.name for item in items] for group, items in items_by_group.items()} + location_name_groups = {group.name.replace("_", " ").title(): [item.name for item in locations] + for group, locations in locations_by_tag.items()} + data_version = 3 required_client_version = (0, 4, 0) From 976bbeabd41dda0a9c11ceb9fb7ccb9f921176d8 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:19:17 -0500 Subject: [PATCH 318/482] Update worlds/stardew_valley/__init__.py --- worlds/stardew_valley/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 7d7ba91b8b32..d1dc5ed93013 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -67,7 +67,7 @@ class StardewValleyWorld(World): item_name_groups = {group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() in item_table else ""): [item.name for item in items] for group, items in items_by_group.items()} - location_name_groups = {group.name.replace("_", " ").title(): [item.name for item in locations] + location_name_groups = {group.name.replace("_", " ").title(): [location.name for location in locations] for group, locations in locations_by_tag.items()} data_version = 3 From 7c24b95b323f6613c1fd5b81606cc6f2b634b7d8 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:27:27 -0500 Subject: [PATCH 319/482] Add collision check to location name groups --- worlds/stardew_valley/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index d1dc5ed93013..8544207a8d64 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -67,9 +67,10 @@ class StardewValleyWorld(World): item_name_groups = {group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() in item_table else ""): [item.name for item in items] for group, items in items_by_group.items()} - location_name_groups = {group.name.replace("_", " ").title(): [location.name for location in locations] - for group, locations in locations_by_tag.items()} - + location_name_groups = {group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() + in locations_by_tag else ""): + [location.name for location in locations] for group, locations in locations_by_tag.items()} + data_version = 3 required_client_version = (0, 4, 0) From d5dca9b87b74bc5f411a7d6618607f9b6729407a Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 30 Nov 2023 20:04:41 -0500 Subject: [PATCH 320/482] - Make story quests optional [THIS REQUIRES NAMEDRANGE] # Conflicts: # worlds/stardew_valley/data/locations.csv # worlds/stardew_valley/options.py --- worlds/stardew_valley/data/locations.csv | 118 +++++++++++------------ worlds/stardew_valley/locations.py | 15 ++- worlds/stardew_valley/options.py | 20 ++-- worlds/stardew_valley/presets.py | 18 ++-- worlds/stardew_valley/rules.py | 8 +- worlds/stardew_valley/test/__init__.py | 8 +- 6 files changed, 101 insertions(+), 86 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 13fb31ea06c3..f374150fea50 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -225,54 +225,54 @@ id,region,name,tags,mod_name 416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, 417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, 418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, -501,Town,Introductions,"MANDATORY,QUEST", -502,Town,How To Win Friends,"MANDATORY,QUEST", -503,Farm,Getting Started,"MANDATORY,QUEST", -504,Farm,Raising Animals,"MANDATORY,QUEST", -505,Farm,Advancement,"MANDATORY,QUEST", -506,Museum,Archaeology,"MANDATORY,QUEST", -507,Wizard Tower,Meet The Wizard,"MANDATORY,QUEST", -508,The Mines - Floor 5,Forging Ahead,"MANDATORY,QUEST", -509,The Mines - Floor 10,Smelting,"MANDATORY,QUEST", -510,The Mines - Floor 15,Initiation,"MANDATORY,QUEST", -511,Forest,Robin's Lost Axe,"MANDATORY,QUEST", -512,Sam's House,Jodi's Request,"MANDATORY,QUEST", -513,Marnie's Ranch,"Mayor's ""Shorts""","MANDATORY,QUEST", -514,Tunnel Entrance,Blackberry Basket,"MANDATORY,QUEST", -515,Marnie's Ranch,Marnie's Request,"MANDATORY,QUEST", -516,Trailer,Pam Is Thirsty,"MANDATORY,QUEST", -517,Wizard Tower,A Dark Reagent,"MANDATORY,QUEST", -518,Marnie's Ranch,Cow's Delight,"MANDATORY,QUEST", -519,Skull Cavern Entrance,The Skull Key,"MANDATORY,QUEST", -520,Carpenter Shop,Crop Research,"MANDATORY,QUEST", -521,Alex's House,Knee Therapy,"MANDATORY,QUEST", -522,Carpenter Shop,Robin's Request,"MANDATORY,QUEST", -523,Skull Cavern Floor 25,Qi's Challenge,"MANDATORY,QUEST", -524,Desert,The Mysterious Qi,"MANDATORY,QUEST", -525,Pierre's General Store,Carving Pumpkins,"MANDATORY,QUEST", -526,Town,A Winter Mystery,"MANDATORY,QUEST", -527,Secret Woods,Strange Note,"MANDATORY,QUEST", -528,Skull Cavern Floor 100,Cryptic Note,"MANDATORY,QUEST", -529,Haley's House,Fresh Fruit,"MANDATORY,QUEST", -530,Carpenter Shop,Aquatic Research,"MANDATORY,QUEST", -531,Sam's House,A Soldier's Star,"MANDATORY,QUEST", -532,Mayor's Manor,Mayor's Need,"MANDATORY,QUEST", -533,Saloon,Wanted: Lobster,"MANDATORY,QUEST", -534,Trailer,Pam Needs Juice,"MANDATORY,QUEST", -535,Sam's House,Fish Casserole,"MANDATORY,QUEST", -536,Fishing,Catch A Squid,"MANDATORY,QUEST", -537,Saloon,Fish Stew,"MANDATORY,QUEST", -538,Pierre's General Store,Pierre's Notice,"MANDATORY,QUEST", -539,Clint's Blacksmith,Clint's Attempt,"MANDATORY,QUEST", -540,Haley's House,A Favor For Clint,"MANDATORY,QUEST", -541,Wizard Tower,Staff Of Power,"MANDATORY,QUEST", -542,Alex's House,Granny's Gift,"MANDATORY,QUEST", -543,Desert,Exotic Spirits,"MANDATORY,QUEST", -544,Fishing,Catch a Lingcod,"MANDATORY,QUEST", -545,Island West,The Pirate's Wife,"GINGER_ISLAND,MANDATORY,QUEST", -546,Mutant Bug Lair,Dark Talisman,"MANDATORY,QUEST", -547,Witch's Swamp,Goblin Problem,"MANDATORY,QUEST", -548,Witch's Hut,Magic Ink,"MANDATORY,QUEST", +501,Town,Introductions,"STORY_QUEST", +502,Town,How To Win Friends,"STORY_QUEST", +503,Farm,Getting Started,"STORY_QUEST", +504,Farm,Raising Animals,"STORY_QUEST", +505,Farm,Advancement,"STORY_QUEST", +506,Museum,Archaeology,"STORY_QUEST", +507,Wizard Tower,Meet The Wizard,"STORY_QUEST", +508,The Mines - Floor 5,Forging Ahead,"STORY_QUEST", +509,The Mines - Floor 10,Smelting,"STORY_QUEST", +510,The Mines - Floor 15,Initiation,"STORY_QUEST", +511,Forest,Robin's Lost Axe,"STORY_QUEST", +512,Sam's House,Jodi's Request,"STORY_QUEST", +513,Marnie's Ranch,"Mayor's ""Shorts""","STORY_QUEST", +514,Tunnel Entrance,Blackberry Basket,"STORY_QUEST", +515,Marnie's Ranch,Marnie's Request,"STORY_QUEST", +516,Trailer,Pam Is Thirsty,"STORY_QUEST", +517,Wizard Tower,A Dark Reagent,"STORY_QUEST", +518,Marnie's Ranch,Cow's Delight,"STORY_QUEST", +519,Skull Cavern Entrance,The Skull Key,"STORY_QUEST", +520,Carpenter Shop,Crop Research,"STORY_QUEST", +521,Alex's House,Knee Therapy,"STORY_QUEST", +522,Carpenter Shop,Robin's Request,"STORY_QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"STORY_QUEST", +524,Desert,The Mysterious Qi,"STORY_QUEST", +525,Pierre's General Store,Carving Pumpkins,"STORY_QUEST", +526,Town,A Winter Mystery,"STORY_QUEST", +527,Secret Woods,Strange Note,"STORY_QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"STORY_QUEST", +529,Haley's House,Fresh Fruit,"STORY_QUEST", +530,Carpenter Shop,Aquatic Research,"STORY_QUEST", +531,Sam's House,A Soldier's Star,"STORY_QUEST", +532,Mayor's Manor,Mayor's Need,"STORY_QUEST", +533,Saloon,Wanted: Lobster,"STORY_QUEST", +534,Trailer,Pam Needs Juice,"STORY_QUEST", +535,Sam's House,Fish Casserole,"STORY_QUEST", +536,Fishing,Catch A Squid,"STORY_QUEST", +537,Saloon,Fish Stew,"STORY_QUEST", +538,Pierre's General Store,Pierre's Notice,"STORY_QUEST", +539,Clint's Blacksmith,Clint's Attempt,"STORY_QUEST", +540,Haley's House,A Favor For Clint,"STORY_QUEST", +541,Wizard Tower,Staff Of Power,"STORY_QUEST", +542,Alex's House,Granny's Gift,"STORY_QUEST", +543,Desert,Exotic Spirits,"STORY_QUEST", +544,Fishing,Catch a Lingcod,"STORY_QUEST", +545,Island West,The Pirate's Wife,"GINGER_ISLAND,STORY_QUEST", +546,Mutant Bug Lair,Dark Talisman,"STORY_QUEST", +547,Witch's Swamp,Goblin Problem,"STORY_QUEST", +548,Witch's Hut,Magic Ink,"STORY_QUEST", 601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", 602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", 603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", @@ -2522,18 +2522,18 @@ id,region,name,tags,mod_name 7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -7501,Mountain,Missing Envelope,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Forest,Lost Emerald Ring,"MANDATORY,QUEST",Ayeisha - The Postal Worker (Custom NPC) -7503,Forest,Mr.Ginger's request,"MANDATORY,QUEST",Mister Ginger (cat npc) -7504,Forest,Juna's Drink Request,"MANDATORY,QUEST",Juna - Roommate NPC -7505,Forest,Juna's BFF Request,"MANDATORY,QUEST",Juna - Roommate NPC +7501,Mountain,Missing Envelope,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) +7503,Forest,Mr.Ginger's request,"STORY_QUEST",Mister Ginger (cat npc) +7504,Forest,Juna's Drink Request,"STORY_QUEST",Juna - Roommate NPC +7505,Forest,Juna's BFF Request,"STORY_QUEST",Juna - Roommate NPC 7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC -7507,Adventurer's Guild,Marlon's Boat,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7508,Railroad,The Railroad Boulder,"MANDATORY,QUEST",Stardew Valley Expanded -7509,Grandpa's Shed Interior,Grandpa's Shed,"MANDATORY,QUEST",Stardew Valley Expanded -7510,Aurora Vineyard,Aurora Vineyard,"MANDATORY,QUEST",Stardew Valley Expanded -7511,Adventurer's Guild,Monster Crops,"MANDATORY,QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul,"MANDATORY,QUEST",Stardew Valley Expanded +7507,Adventurer's Guild,Marlon's Boat,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7508,Railroad,The Railroad Boulder,"STORY_QUEST",Stardew Valley Expanded +7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded +7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded +7511,Adventurer's Guild,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7512,Sewer,Void Soul,"STORY_QUEST",Stardew Valley Expanded 7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index d52c3ba27deb..4f18b1cf808d 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -49,7 +49,7 @@ class LocationTags(enum.Enum): COMBAT_LEVEL = enum.auto() MINING_LEVEL = enum.auto() BUILDING_BLUEPRINT = enum.auto() - QUEST = enum.auto() + STORY_QUEST = enum.auto() ARCADE_MACHINE = enum.auto() ARCADE_MACHINE_VICTORY = enum.auto() JOTPK = enum.auto() @@ -176,8 +176,15 @@ def extend_cropsanity_locations(randomized_locations: List[LocationData], option randomized_locations.extend(cropsanity_locations) -def extend_help_wanted_quests(randomized_locations: List[LocationData], desired_number_of_quests: int): - for i in range(0, desired_number_of_quests): +def extend_quests_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + if options.quest_locations < 0: + return + + story_quest_locations = locations_by_tag[LocationTags.CROPSANITY] + story_quest_locations = filter_ginger_island(options, story_quest_locations) + randomized_locations.extend(story_quest_locations) + + for i in range(0, options.quest_locations.value): batch = i // 7 index_this_batch = i % 7 if index_this_batch < 4: @@ -461,7 +468,6 @@ def create_locations(location_collector: StardewLocationCollector, randomized_locations.extend(locations_by_tag[LocationTags.ARCADE_MACHINE]) extend_cropsanity_locations(randomized_locations, options) - extend_help_wanted_quests(randomized_locations, options.help_wanted_locations.value) extend_fishsanity_locations(randomized_locations, options, random) extend_museumsanity_locations(randomized_locations, options, random) extend_friendsanity_locations(randomized_locations, options) @@ -475,6 +481,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_cooksanity_locations(randomized_locations, options) extend_chefsanity_locations(randomized_locations, options) extend_craftsanity_locations(randomized_locations, options) + extend_quests_locations(randomized_locations, options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 8bc9373f987e..3962adec31af 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -315,19 +315,23 @@ class SpecialOrderLocations(Choice): option_board_qi = 2 -class HelpWantedLocations(NamedRange): - """Include location checks for Help Wanted quests - Out of every 7 quests, 4 will be item deliveries, and then 1 of each for: Fishing, Gathering and Slaying Monsters. - Choosing a multiple of 7 is recommended.""" - internal_name = "help_wanted_locations" +class QuestLocations(SpecialRange): + """Include location checks for quests + None: No quests are checks + Story: Only story quests are checks + Number: Story quests and help wanted quests are checks up to the specified amount. Multiple of 7 recommended + Out of every 7 help wanted quests, 4 will be item deliveries, and then 1 of each for: Fishing, Gathering and Slaying Monsters. + Extra Help wanted quests might be added if current settings don't have enough locations""" + internal_name = "quest_locations" default = 7 range_start = 0 range_end = 56 # step = 7 - display_name = "Number of Help Wanted locations" + display_name = "Quest Locations" special_range_names = { - "none": 0, + "none": -1, + "story": 0, "minimum": 7, "normal": 14, "lots": 28, @@ -681,7 +685,7 @@ class StardewValleyOptions(PerGameCommonOptions): elevator_progression: ElevatorProgression arcade_machine_locations: ArcadeMachineLocations special_order_locations: SpecialOrderLocations - help_wanted_locations: HelpWantedLocations + quest_locations: QuestLocations fishsanity: Fishsanity museumsanity: Museumsanity monstersanity: Monstersanity diff --git a/worlds/stardew_valley/presets.py b/worlds/stardew_valley/presets.py index 8823c52e5b20..7e229d6c8e53 100644 --- a/worlds/stardew_valley/presets.py +++ b/worlds/stardew_valley/presets.py @@ -3,7 +3,7 @@ from Options import Accessibility, ProgressionBalancing, DeathLink from .options import Goal, StartingMoney, ProfitMargin, BundleRandomization, BundlePrice, EntranceRandomization, SeasonRandomization, Cropsanity, \ BackpackProgression, ToolProgression, ElevatorProgression, SkillProgression, BuildingProgression, FestivalLocations, ArcadeMachineLocations, \ - SpecialOrderLocations, HelpWantedLocations, Fishsanity, Museumsanity, Friendsanity, FriendsanityHeartSize, NumberOfMovementBuffs, NumberOfLuckBuffs, \ + SpecialOrderLocations, QuestLocations, Fishsanity, Museumsanity, Friendsanity, FriendsanityHeartSize, NumberOfMovementBuffs, NumberOfLuckBuffs, \ ExcludeGingerIsland, TrapItems, MultipleDaySleepEnabled, MultipleDaySleepCost, ExperienceMultiplier, FriendshipMultiplier, DebrisMultiplier, QuickStart, \ Gifting @@ -26,7 +26,7 @@ FestivalLocations.internal_name: "random", ArcadeMachineLocations.internal_name: "random", SpecialOrderLocations.internal_name: "random", - HelpWantedLocations.internal_name: "random", + QuestLocations.internal_name: "random", Fishsanity.internal_name: "random", Museumsanity.internal_name: "random", Friendsanity.internal_name: "random", @@ -64,7 +64,7 @@ FestivalLocations.internal_name: FestivalLocations.option_easy, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: "minimum", + QuestLocations.internal_name: "minimum", Fishsanity.internal_name: Fishsanity.option_only_easy_fish, Museumsanity.internal_name: Museumsanity.option_milestones, Friendsanity.internal_name: Friendsanity.option_none, @@ -102,7 +102,7 @@ FestivalLocations.internal_name: FestivalLocations.option_hard, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_victories_easy, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_only, - HelpWantedLocations.internal_name: "normal", + QuestLocations.internal_name: "normal", Fishsanity.internal_name: Fishsanity.option_exclude_legendaries, Museumsanity.internal_name: Museumsanity.option_milestones, Friendsanity.internal_name: Friendsanity.option_starting_npcs, @@ -140,7 +140,7 @@ FestivalLocations.internal_name: FestivalLocations.option_hard, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - HelpWantedLocations.internal_name: "lots", + QuestLocations.internal_name: "lots", Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, Friendsanity.internal_name: Friendsanity.option_all, @@ -178,7 +178,7 @@ FestivalLocations.internal_name: FestivalLocations.option_hard, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - HelpWantedLocations.internal_name: "maximum", + QuestLocations.internal_name: "maximum", Fishsanity.internal_name: Fishsanity.option_special, Museumsanity.internal_name: Museumsanity.option_all, Friendsanity.internal_name: Friendsanity.option_all_with_marriage, @@ -216,7 +216,7 @@ FestivalLocations.internal_name: FestivalLocations.option_disabled, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: "none", + QuestLocations.internal_name: "none", Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, @@ -254,7 +254,7 @@ FestivalLocations.internal_name: FestivalLocations.option_disabled, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: "none", + QuestLocations.internal_name: "none", Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, @@ -292,7 +292,7 @@ FestivalLocations.internal_name: FestivalLocations.option_hard, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - HelpWantedLocations.internal_name: "maximum", + QuestLocations.internal_name: "maximum", Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, Friendsanity.internal_name: Friendsanity.option_all, diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index f57f40d2d5e1..eaeccc621145 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -450,7 +450,9 @@ def set_cropsanity_rules(all_location_names: List[str], logic: StardewLogic, mul def set_story_quests_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - for quest in locations.locations_by_tag[LocationTags.QUEST]: + if world_options.quest_locations < 0: + return + for quest in locations.locations_by_tag[LocationTags.STORY_QUEST]: if quest.name in all_location_names and (quest.mod_name is None or quest.mod_name in world_options.mods): MultiWorldRules.set_rule(multiworld.get_location(quest.name, player), logic.registry.quest_rules[quest.name]) @@ -485,7 +487,9 @@ def set_special_order_rules(all_location_names: List[str], logic: StardewLogic, def set_help_wanted_quests_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - help_wanted_number = world_options.help_wanted_locations.value + help_wanted_number = world_options.quest_locations.value + if help_wanted_number < 0: + return for i in range(0, help_wanted_number): set_number = i // 7 month_rule = logic.time.has_lived_months(set_number) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 43cb27a781f6..61fbb385d1d1 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -11,7 +11,7 @@ from .. import StardewValleyWorld from ..mods.mod_data import all_mods from ..options import Cropsanity, SkillProgression, SpecialOrderLocations, Friendsanity, NumberOfLuckBuffs, SeasonRandomization, ToolProgression, \ - ElevatorProgression, Museumsanity, BackpackProgression, BuildingProgression, ArcadeMachineLocations, HelpWantedLocations, Fishsanity, NumberOfMovementBuffs, \ + ElevatorProgression, Museumsanity, BackpackProgression, BuildingProgression, ArcadeMachineLocations, QuestLocations, Fishsanity, NumberOfMovementBuffs, \ BundleRandomization, BundlePrice, FestivalLocations, FriendsanityHeartSize, ExcludeGingerIsland, TrapItems, Goal, Mods, Monstersanity, Shipsanity, \ Cooksanity, Chefsanity, Craftsanity @@ -58,7 +58,7 @@ def get_minsanity_options(): ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: 0, + QuestLocations.internal_name: -1, Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, Monstersanity.internal_name: Monstersanity.option_none, @@ -93,7 +93,7 @@ def minimal_locations_maximal_items(): ElevatorProgression.internal_name: ElevatorProgression.option_vanilla, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, - HelpWantedLocations.internal_name: 0, + QuestLocations.internal_name: -1, Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, Monstersanity.internal_name: Monstersanity.option_none, @@ -170,7 +170,7 @@ def allsanity_options_without_mods(): ElevatorProgression.internal_name: ElevatorProgression.option_progressive, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - HelpWantedLocations.internal_name: 56, + QuestLocations.internal_name: 56, Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, Monstersanity.internal_name: Monstersanity.option_progressive_goals, From ce339b9b07f3f987dca5ac6e356386786b6e7ce0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Dec 2023 12:43:29 -0500 Subject: [PATCH 321/482] - Add Optional story quests option --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 4 +-- worlds/stardew_valley/items.py | 32 +++++++++++++++++++++--- worlds/stardew_valley/locations.py | 4 +-- worlds/stardew_valley/options.py | 17 +++++++++++-- 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index dc547f76e709..463935cc5dd8 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -263,7 +263,7 @@ id,name,classification,groups,mod_name 278,Livin' Off The Land,useful,TV_CHANNEL, 279,The Queen of Sauce,progression,TV_CHANNEL, 280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, -281,Sinister Signal,useful,TV_CHANNEL, +281,Sinister Signal,filler,TV_CHANNEL, 282,Dark Talisman,progression,, 283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, 284,Cute Baby,progression,BABY, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f374150fea50..e533fda24f6d 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2540,8 +2540,8 @@ id,region,name,tags,mod_name 7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded 7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7520,Witch's Swamp,A New Pot,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul -7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,QUEST",Distant Lands - Witch Swamp Overhaul +7520,Witch's Swamp,A New Pot,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul +7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul 7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul 7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index fb12879c7191..a294d53dc1d4 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -156,6 +156,10 @@ def initialize_item_table(): initialize_groups() +def get_too_many_items_error_message(locations_count: int, items_count: int) -> str: + return f"There should be at least as many locations [{locations_count}] as there are mandatory items [{items_count}]" + + def create_items(item_factory: StardewItemFactory, locations_count: int, items_to_exclude: List[Item], options: StardewValleyOptions, random: Random) -> List[Item]: items = [] @@ -165,8 +169,8 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t if item in unique_items: unique_items.remove(item) - assert len( - unique_items) <= locations_count, f"There should be at least as many locations [{locations_count}] as there are mandatory items [{len(unique_items)}]" + remove_items_if_no_room_for_them(unique_items, locations_count, random) + items += unique_items logger.debug(f"Created {len(unique_items)} unique items") @@ -181,6 +185,24 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t return items +def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count: int, random: Random): + if len(unique_items) <= locations_count: + return + + number_of_items_to_remove = len(unique_items) - locations_count + removable_items = [item for item in unique_items if item.classification == ItemClassification.filler or item.classification == ItemClassification.trap] + if len(removable_items) < number_of_items_to_remove: + logger.debug(f"Player has more items than locations, trying to remove {number_of_items_to_remove} random non-progression items") + removable_items = [item for item in unique_items if not item.classification & ItemClassification.progression] + else: + logger.debug(f"Player has more items than locations, trying to remove {number_of_items_to_remove} random filler items") + assert len(removable_items) >= number_of_items_to_remove, get_too_many_items_error_message(locations_count, len(unique_items)) + items_to_remove = random.sample(removable_items, number_of_items_to_remove) + for item in items_to_remove: + if item in unique_items: + unique_items.remove(item) + + def create_unique_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random) -> List[Item]: items = [] @@ -327,6 +349,8 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, options: Starde def create_special_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if options.quest_locations < 0: + return items.append(item_factory("Adventurer's Guild")) items.append(item_factory("Club Card")) items.append(item_factory("Magnifying Glass")) @@ -576,9 +600,9 @@ def create_deepwoods_pendants(item_factory: StardewItemFactory, options: Stardew def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): - exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true - if ModNames.sve not in options.mods: + if options.quest_locations < 0 or ModNames.sve not in options.mods: return + exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true items.extend([item_factory(item) for item in SVEQuestItem.sve_quest_items]) items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP] if item.mod_name == ModNames.sve]) if exclude_ginger_island: diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 4f18b1cf808d..6a8a669c5118 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -180,8 +180,8 @@ def extend_quests_locations(randomized_locations: List[LocationData], options: S if options.quest_locations < 0: return - story_quest_locations = locations_by_tag[LocationTags.CROPSANITY] - story_quest_locations = filter_ginger_island(options, story_quest_locations) + story_quest_locations = locations_by_tag[LocationTags.STORY_QUEST] + story_quest_locations = filter_disabled_locations(options, story_quest_locations) randomized_locations.extend(story_quest_locations) for i in range(0, options.quest_locations.value): diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 3962adec31af..c3d78babebd1 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -315,7 +315,7 @@ class SpecialOrderLocations(Choice): option_board_qi = 2 -class QuestLocations(SpecialRange): +class QuestLocations(NamedRange): """Include location checks for quests None: No quests are checks Story: Only story quests are checks @@ -443,7 +443,7 @@ class Cooksanity(Choice): option_all = 2 -class Chefsanity(Choice): +class Chefsanity(NamedRange): """Locations for leaning cooking recipes? Vanilla: All cooking recipes are learned normally Queen of Sauce: Every Queen of sauce episode is a check, all queen of sauce recipes are items @@ -455,6 +455,9 @@ class Chefsanity(Choice): internal_name = "chefsanity" display_name = "Chefsanity" default = 0 + range_start = 0 + range_end = 15 + option_none = 0b0000 # 0 option_queen_of_sauce = 0b0001 # 1 option_purchases = 0b0010 # 2 @@ -463,6 +466,16 @@ class Chefsanity(Choice): option_friendship = 0b1000 # 8 option_all = 0b1111 # 15 + special_range_names = { + "none": 0b0000, # 0 + "queen_of_sauce": 0b0001, # 1 + "purchases": 0b0010, # 2 + "qos_and_purchases": 0b0011, # 3 + "skills": 0b0100, # 4 + "friendship": 0b1000, # 8 + "all": 0b1111, # 15 + } + class Craftsanity(Choice): """Checks for crafting items? From 3afcdf4552fabcf482faee4ce32594908a900cde Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Dec 2023 20:08:15 -0500 Subject: [PATCH 322/482] - Fix some item link stuff --- worlds/stardew_valley/items.py | 24 +++++++++++++--------- worlds/stardew_valley/test/TestItemLink.py | 4 ++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index a294d53dc1d4..4eafd8277250 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -693,14 +693,18 @@ def filter_ginger_island_items(exclude_island: bool, items: List[ItemData]) -> L return [item for item in items if not exclude_island or Group.GINGER_ISLAND not in item.groups] -def filter_mod_items(options: StardewValleyOptions, items: List[ItemData]) -> List[ItemData]: - return [item for item in items if item.mod_name is None or item.mod_name in options.mods] +def filter_mod_items(mods: Set[str], items: List[ItemData]) -> List[ItemData]: + return [item for item in items if item.mod_name is None or item.mod_name in mods] -def remove_excluded_items(items, options): +def remove_excluded_items(items, options: StardewValleyOptions): + return remove_excluded_items_island_mods(items, options.exclude_ginger_island == ExcludeGingerIsland.option_true, options.mods.value) + + +def remove_excluded_items_island_mods(items, exclude_ginger_island: bool, mods: Set[str]): deprecated_filter = filter_deprecated_items(items) - ginger_island_filter = filter_ginger_island_items(options.exclude_ginger_island == ExcludeGingerIsland.option_true, deprecated_filter) - mod_filter = filter_mod_items(options, ginger_island_filter) + ginger_island_filter = filter_ginger_island_items(exclude_ginger_island, deprecated_filter) + mod_filter = filter_mod_items(mods, ginger_island_filter) return mod_filter @@ -709,12 +713,12 @@ def remove_limited_amount_packs(packs): def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool): - all_filler_packs = [pack for pack in items_by_group[Group.RESOURCE_PACK]] - all_filler_packs.extend(items_by_group[Group.TRASH]) + all_filler_items = [pack for pack in items_by_group[Group.RESOURCE_PACK]] + all_filler_items.extend(items_by_group[Group.TRASH]) if include_traps: - all_filler_packs.extend(items_by_group[Group.TRAP]) - all_filler_packs = filter_ginger_island_items(exclude_ginger_island, all_filler_packs) - return all_filler_packs + all_filler_items.extend(items_by_group[Group.TRAP]) + all_filler_items = remove_excluded_items_island_mods(all_filler_items, exclude_ginger_island, set()) + return all_filler_items def get_stardrop_classification(options) -> ItemClassification: diff --git a/worlds/stardew_valley/test/TestItemLink.py b/worlds/stardew_valley/test/TestItemLink.py index f55ab8ca347d..39bf553cab2d 100644 --- a/worlds/stardew_valley/test/TestItemLink.py +++ b/worlds/stardew_valley/test/TestItemLink.py @@ -9,7 +9,7 @@ class TestItemLinksEverythingIncluded(SVTestBase): options.TrapItems.internal_name: options.TrapItems.option_medium} def test_filler_of_all_types_generated(self): - max_number_filler = 115 + max_number_filler = 114 filler_generated = [] at_least_one_trap = False at_least_one_island = False @@ -60,7 +60,7 @@ class TestItemLinksNoTraps(SVTestBase): options.TrapItems.internal_name: options.TrapItems.option_no_traps} def test_filler_has_no_traps_but_has_island(self): - max_number_filler = 100 + max_number_filler = 99 filler_generated = [] at_least_one_island = False for i in range(0, max_iterations): From 53993dc9fd7895da7f16b00729ffa1f25427df50 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Dec 2023 20:27:32 -0500 Subject: [PATCH 323/482] - Fix shipping bin progression status --- worlds/stardew_valley/items.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 4eafd8277250..3539a2be624b 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -337,10 +337,7 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, options: Starde items.append(item_factory("Fish Pond")) items.append(item_factory("Stable")) items.append(item_factory("Slime Hutch")) - needs_early_bin = building_option & BuildingProgression.early_shipping_bin - has_shipsanity = options.shipsanity != Shipsanity.option_none - need_shipping = needs_early_bin or has_shipsanity or world_is_perfection(options) - items.append(item_factory("Shipping Bin", ItemClassification.progression if need_shipping else ItemClassification.useful)) + items.append(item_factory("Shipping Bin")) items.append(item_factory("Progressive House")) items.append(item_factory("Progressive House")) items.append(item_factory("Progressive House")) From 23ca02f0b6a9243ddaccf101c7024aac7179699f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Dec 2023 22:10:34 -0500 Subject: [PATCH 324/482] - Fix some quest items when disabling quests --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/data/craftable_data.py | 10 ++- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/recipe_source.py | 10 +++ worlds/stardew_valley/items.py | 10 +-- worlds/stardew_valley/logic/crafting_logic.py | 12 +++- worlds/stardew_valley/logic/logic.py | 6 +- worlds/stardew_valley/logic/quest_logic.py | 12 +++- worlds/stardew_valley/logic/wallet_logic.py | 5 +- .../mods/logic/special_orders_logic.py | 2 +- worlds/stardew_valley/rules.py | 19 ++---- .../strings/wallet_item_names.py | 3 + worlds/stardew_valley/test/TestGeneration.py | 14 ++--- worlds/stardew_valley/test/TestOptions.py | 16 +---- .../stardew_valley/test/TestOptionsPairs.py | 43 +++++++++++++ worlds/stardew_valley/test/TestRules.py | 61 ++++++------------- .../test/checks/world_checks.py | 7 ++- .../test/long/TestOptionsLong.py | 9 +-- 18 files changed, 133 insertions(+), 110 deletions(-) create mode 100644 worlds/stardew_valley/test/TestOptionsPairs.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 8544207a8d64..bfc7066d1bee 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -205,7 +205,7 @@ def setup_construction_events(self): def setup_quest_events(self): start_dark_talisman_quest = LocationData(None, RegionName.railroad, Event.start_dark_talisman_quest) - self.create_event_location(start_dark_talisman_quest, self.logic.wallet.has_rusty_key, Event.start_dark_talisman_quest) + self.create_event_location(start_dark_talisman_quest, self.logic.wallet.has_rusty_key(), Event.start_dark_talisman_quest) def setup_action_events(self): can_ship_event = LocationData(None, RegionName.shipping, Event.can_ship_items) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 2b48e8a1deb0..77d37cb6addd 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -2,7 +2,7 @@ from ..mods.mod_data import ModNames from .recipe_source import RecipeSource, StarterSource, QueenOfSauceSource, ShopSource, SkillSource, FriendshipSource, ShopTradeSource, CutsceneSource, \ - ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource + ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource, QuestSource from ..strings.artisan_good_names import ArtisanGood from ..strings.craftable_names import Bomb, Fence, Sprinkler, WildSeeds, Floor, Fishing, Ring, Consumable, Edible, Lighting, Storage, Furniture, Sign, Craftable, \ ModEdible, ModCraftable, ModMachine, ModFloor, ModConsumable @@ -18,6 +18,7 @@ from ..strings.material_names import Material from ..strings.metal_names import Ore, MetalBar, Fossil, Artifact, Mineral from ..strings.monster_drop_names import Loot +from ..strings.quest_names import Quest from ..strings.region_names import Region, SVERegion from ..strings.seed_names import Seed, TreeSeed from ..strings.skill_names import Skill, ModSkill @@ -80,6 +81,11 @@ def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredien return create_recipe(name, ingredients, source) +def quest_recipe(name: str, quest: str, ingredients: Dict[str, int]) -> CraftingRecipe: + source = QuestSource(quest) + return create_recipe(name, ingredients, source) + + def special_order_recipe(name: str, special_order: str, ingredients: Dict[str, int]) -> CraftingRecipe: source = SpecialOrderSource(special_order) return create_recipe(name, ingredients, source) @@ -193,7 +199,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, oil_of_garlic = skill_recipe(Edible.oil_of_garlic, Skill.combat, 6, {Vegetable.garlic: 10, Ingredient.oil: 1}) monster_musk = special_order_recipe(Consumable.monster_musk, SpecialOrder.prismatic_jelly, {Loot.bat_wing: 30, Loot.slime: 30}) -fairy_dust = ap_recipe(Consumable.fairy_dust, {Mineral.diamond: 1, Flower.fairy_rose: 1}) +fairy_dust = quest_recipe(Consumable.fairy_dust, Quest.the_pirates_wife, {Mineral.diamond: 1, Flower.fairy_rose: 1}) warp_totem_beach = skill_recipe(Consumable.warp_totem_beach, Skill.foraging, 6, {Material.hardwood: 1, WaterItem.coral: 2, Material.fiber: 10}) warp_totem_mountains = skill_recipe(Consumable.warp_totem_mountains, Skill.foraging, 7, {Material.hardwood: 1, MetalBar.iron: 1, Material.stone: 25}) warp_totem_farm = skill_recipe(Consumable.warp_totem_farm, Skill.foraging, 8, {Material.hardwood: 1, ArtisanGood.honey: 1, Material.fiber: 20}) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 463935cc5dd8..00667a416b72 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -78,7 +78,7 @@ id,name,classification,groups,mod_name 92,Slime Hutch,progression,BUILDING, 93,Shipping Bin,progression,BUILDING, 94,Beach Bridge,progression,, -95,Adventurer's Guild,progression,, +95,Adventurer's Guild,progression,DEPRECATED, 96,Club Card,progression,, 97,Magnifying Glass,progression,, 98,Bear's Knowledge,useful,, diff --git a/worlds/stardew_valley/data/recipe_source.py b/worlds/stardew_valley/data/recipe_source.py index 168234ee311f..8dd622e926e7 100644 --- a/worlds/stardew_valley/data/recipe_source.py +++ b/worlds/stardew_valley/data/recipe_source.py @@ -49,6 +49,16 @@ def __repr__(self): return f"QueenOfSauceSource at year {self.year} {self.season} {self.day}" +class QuestSource(RecipeSource): + quest: str + + def __init__(self, quest: str): + self.quest = quest + + def __repr__(self): + return f"QuestSource at quest {self.quest}" + + class FriendshipSource(RecipeSource): friend: str hearts: int diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 3539a2be624b..ce451b445934 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -348,11 +348,11 @@ def create_carpenter_buildings(item_factory: StardewItemFactory, options: Starde def create_special_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): if options.quest_locations < 0: return - items.append(item_factory("Adventurer's Guild")) - items.append(item_factory("Club Card")) - items.append(item_factory("Magnifying Glass")) - items.append(item_factory("Bear's Knowledge")) - items.append(item_factory("Iridium Snake Milk")) + # items.append(item_factory("Adventurer's Guild")) # Now unlocked always! + items.append(item_factory(Wallet.club_card)) + items.append(item_factory(Wallet.magnifying_glass)) + items.append(item_factory(Wallet.bears_knowledge)) + items.append(item_factory(Wallet.iridium_snake_milk)) items.append(item_factory("Fairy Dust Recipe")) if ModNames.sve in options.mods: create_special_quest_rewards_sve(item_factory, options, items) diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index be553cd3b198..b0b161bec298 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -5,6 +5,7 @@ from .base_logic import BaseLogicMixin, BaseLogic from .has_logic import HasLogicMixin from .money_logic import MoneyLogicMixin +from .quest_logic import QuestLogicMixin from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from .relationship_logic import RelationshipLogicMixin @@ -15,7 +16,7 @@ from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name from ..data.recipe_data import StarterSource, ShopSource, SkillSource, FriendshipSource from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, \ - FestivalShopSource + FestivalShopSource, QuestSource from ..locations import locations_by_tag, LocationTags from ..options import Craftsanity, SpecialOrderLocations, ExcludeGingerIsland from ..stardew_rule import StardewRule, True_, False_, And @@ -29,7 +30,7 @@ def __init__(self, *args, **kwargs): class CraftingLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, RelationshipLogicMixin, -SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin]]): +SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin, QuestLogicMixin]]): @cache_self1 def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: if recipe is None: @@ -48,6 +49,11 @@ def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: return self.logic.crafting.can_learn_recipe(recipe) else: return self.logic.crafting.received_recipe(recipe.item) + if isinstance(recipe.source, QuestSource): + if self.options.quest_locations < 0: + return self.logic.crafting.can_learn_recipe(recipe) + else: + return self.logic.crafting.received_recipe(recipe.item) if self.options.craftsanity == Craftsanity.option_none: return self.logic.crafting.can_learn_recipe(recipe) if isinstance(recipe.source, StarterSource) or isinstance(recipe.source, ShopTradeSource) or isinstance( @@ -73,6 +79,8 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: return self.logic.region.can_reach(recipe.source.region) & self.logic.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) if isinstance(recipe.source, FriendshipSource): return self.logic.relationship.has_hearts(recipe.source.friend, recipe.source.hearts) + if isinstance(recipe.source, QuestSource): + return self.logic.quest.can_complete_quest(recipe.source.quest) if isinstance(recipe.source, SpecialOrderSource): if self.options.special_order_locations == SpecialOrderLocations.option_disabled: return self.logic.special_order.can_complete_special_order(recipe.source.special_order) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index c591f0414dd8..66757405e8cb 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -271,7 +271,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Forageable.hay: self.building.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), Forageable.hazelnut: self.tool.can_forage(Season.fall), Forageable.holly: self.tool.can_forage(Season.winter), - Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), + Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & self.quest.has_magnifying_glass() & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), Forageable.leek: self.tool.can_forage(Season.spring), Forageable.magma_cap: self.tool.can_forage(Generic.any, Region.volcano_floor_5), Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods), @@ -279,7 +279,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Forageable.rainbow_shell: self.tool.can_forage(Season.summer, Region.beach), Forageable.red_mushroom: self.tool.can_forage(Season.summer, Region.secret_woods) | self.tool.can_forage(Season.fall, Region.secret_woods), Forageable.salmonberry: self.tool.can_forage(Season.spring), - Forageable.secret_note: self.received(Wallet.magnifying_glass) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), + Forageable.secret_note: self.quest.has_magnifying_glass() & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), Forageable.snow_yam: self.tool.can_forage(Season.winter, Region.beach, True), Forageable.spice_berry: self.tool.can_forage(Season.summer), Forageable.spring_onion: self.tool.can_forage(Season.spring), @@ -524,7 +524,7 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: self.bundle.can_complete_community_center, # CC Ceremony first point self.bundle.can_complete_community_center, # CC Ceremony second point self.received(Wallet.skull_key), # Skull Key obtained - self.wallet.has_rusty_key, # Rusty key obtained + self.wallet.has_rusty_key(), # Rusty key obtained ] return Count(12, rules_worth_a_point) diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 223384fe97cc..cdc02700b6fa 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -98,7 +98,7 @@ def initialize_rules(self): Quest.grannys_gift: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek) & self.logic.relationship.can_meet(NPC.evelyn), Quest.exotic_spirits: self.logic.season.has(Season.winter) & self.logic.has(Forageable.coconut) & self.logic.relationship.can_meet(NPC.gus), Quest.catch_a_lingcod: self.logic.season.has(Season.winter) & self.logic.has(Fish.lingcod) & self.logic.relationship.can_meet(NPC.willy), - Quest.dark_talisman: self.logic.region.can_reach(Region.railroad) & self.logic.wallet.has_rusty_key & self.logic.relationship.can_meet(NPC.krobus), + Quest.dark_talisman: self.logic.region.can_reach(Region.railroad) & self.logic.wallet.has_rusty_key() & self.logic.relationship.can_meet(NPC.krobus), Quest.goblin_problem: self.logic.region.can_reach(Region.witch_swamp), Quest.magic_ink: self.logic.relationship.can_meet(NPC.wizard), Quest.the_pirates_wife: self.logic.relationship.can_meet(NPC.kent) & self.logic.relationship.can_meet(NPC.gus) & @@ -111,3 +111,13 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): def can_complete_quest(self, quest: str) -> StardewRule: return Has(quest, self.registry.quest_rules) + + def has_club_card(self) -> StardewRule: + if self.options.quest_locations < 0: + return self.logic.quest.can_complete_quest(Quest.the_mysterious_qi) + return self.logic.received(Wallet.club_card) + + def has_magnifying_glass(self) -> StardewRule: + if self.options.quest_locations < 0: + return self.logic.quest.can_complete_quest(Quest.a_winter_mystery) + return self.logic.received(Wallet.magnifying_glass) diff --git a/worlds/stardew_valley/logic/wallet_logic.py b/worlds/stardew_valley/logic/wallet_logic.py index 34a1343f65f5..3a6d12640028 100644 --- a/worlds/stardew_valley/logic/wallet_logic.py +++ b/worlds/stardew_valley/logic/wallet_logic.py @@ -1,5 +1,3 @@ -from functools import cached_property - from .base_logic import BaseLogic, BaseLogicMixin from .received_logic import ReceivedLogicMixin from ..stardew_rule import StardewRule @@ -13,10 +11,9 @@ def __init__(self, *args, **kwargs): class WalletLogic(BaseLogic[ReceivedLogicMixin]): - @cached_property + def can_speak_dwarf(self) -> StardewRule: return self.logic.received(Wallet.dwarvish_translation_guide) - @cached_property def has_rusty_key(self) -> StardewRule: return self.logic.received(Wallet.rusty_key) diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index f06489aee7ed..d4d788bb8179 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -39,7 +39,7 @@ def get_modded_special_orders_rules(self): special_orders.update({ ModSpecialOrder.junas_monster_mash: self.logic.relationship.has_hearts(ModNPC.juna, 4) & self.registry.special_order_rules[SpecialOrder.a_curious_substance] & - self.logic.wallet.has_rusty_key & + self.logic.wallet.has_rusty_key() & self.logic.region.can_reach(Region.forest) & self.logic.has(Consumable.monster_musk) & self.logic.has("Energy Tonic") & self.logic.has(Material.sap) & self.logic.has(Loot.bug_meat) & self.logic.has(Edible.oil_of_garlic) & self.logic.has(Meal.strange_bun) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index eaeccc621145..4891051989a8 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -202,9 +202,9 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), - logic.wallet.has_rusty_key) + logic.wallet.has_rusty_key()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), - logic.wallet.has_rusty_key) + logic.wallet.has_rusty_key()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_abandoned_jojamart, player), logic.has_abandoned_jojamart()) movie_theater_rule = logic.has_movie_theater() @@ -219,13 +219,12 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_dangerous_skull_cavern, player), (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), - logic.wallet.can_speak_dwarf & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), logic.traveling_merchant.has_days()) set_farm_buildings_entrance_rules(logic, multiworld, player) - set_adventure_guild_entrance_rules(logic, multiworld, player, world_options) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), logic.received("Railroad Boulder Removed")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), @@ -235,7 +234,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), (logic.received(Event.start_dark_talisman_quest) & logic.relationship.can_meet(NPC.krobus)) | logic.mod.magic.can_blink()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), - logic.received("Club Card")) + logic.quest.has_club_card()) set_bedroom_entrance_rules(logic, multiworld, player, world_options) set_festival_entrance_rules(logic, multiworld, player) @@ -245,14 +244,6 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce)) -def set_adventure_guild_entrance_rules(logic, multiworld, player, world_options): - if ModNames.sve in world_options.mods: - entrance = multiworld.get_entrance(SVEEntrance.guild_to_interior, player) - else: - entrance = multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player) - MultiWorldRules.set_rule(entrance, logic.received("Adventurer's Guild")) - - def set_farm_buildings_entrance_rules(logic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk)) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk)) @@ -388,7 +379,7 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), - logic.wallet.can_speak_dwarf) + logic.wallet.can_speak_dwarf()) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, diff --git a/worlds/stardew_valley/strings/wallet_item_names.py b/worlds/stardew_valley/strings/wallet_item_names.py index e7c4eb9cb3c1..00ee6dbf9efd 100644 --- a/worlds/stardew_valley/strings/wallet_item_names.py +++ b/worlds/stardew_valley/strings/wallet_item_names.py @@ -1,6 +1,9 @@ class Wallet: + iridium_snake_milk = "Iridium Snake Milk" + bears_knowledge = "Bear's Knowledge" dwarvish_translation_guide = "Dwarvish Translation Guide" magnifying_glass = "Magnifying Glass" rusty_key = "Rusty Key" skull_key = "Skull Key" dark_talisman = "Dark Talisman" + club_card = "Club Card" diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 939ace5a58a2..cfde491336e1 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -37,6 +37,7 @@ def test_all_progression_items_are_added_to_the_pool(self): # Ignore all the stuff that the algorithm chooses one of, instead of all, to fulfill logical progression items_to_ignore = [event.name for event in items.events] items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None) + items_to_ignore.extend(deprecated.name for deprecated in items.items_by_group[Group.DEPRECATED]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) @@ -88,6 +89,7 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): # Ignore all the stuff that the algorithm chooses one of, instead of all, to fulfill logical progression items_to_ignore = [event.name for event in items.events] items_to_ignore.extend(item.name for item in items.all_items if item.mod_name is not None) + items_to_ignore.extend(deprecated.name for deprecated in items.items_by_group[Group.DEPRECATED]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) @@ -247,8 +249,7 @@ def generate_items_for_mine_115(self) -> List[Item]: swords = [self.get_item_by_name("Progressive Sword")] * 3 combat_levels = [self.get_item_by_name("Combat Level")] * 4 mining_levels = [self.get_item_by_name("Mining Level")] * 4 - guild = self.get_item_by_name("Adventurer's Guild") - return [*combat_levels, *mining_levels, *elevators, guild, *pickaxes, *swords] + return [*combat_levels, *mining_levels, *elevators, *pickaxes, *swords] def generate_items_for_extra_mine_levels(self, weapon_name: str) -> List[Item]: last_pickaxe = self.get_item_by_name("Progressive Pickaxe") @@ -299,30 +300,27 @@ def generate_items_for_mine_115(self) -> List[Item]: swords = [self.get_item_by_name("Progressive Sword")] * 3 combat_levels = [self.get_item_by_name("Combat Level")] * 4 mining_levels = [self.get_item_by_name("Mining Level")] * 4 - guild = self.get_item_by_name("Adventurer's Guild") bus = self.get_item_by_name("Bus Repair") skull_key = self.get_item_by_name("Skull Key") - return [*combat_levels, *mining_levels, guild, *pickaxes, *swords, bus, skull_key] + return [*combat_levels, *mining_levels, *pickaxes, *swords, bus, skull_key] def generate_items_for_skull_50(self) -> List[Item]: pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 3 swords = [self.get_item_by_name("Progressive Sword")] * 4 combat_levels = [self.get_item_by_name("Combat Level")] * 6 mining_levels = [self.get_item_by_name("Mining Level")] * 6 - guild = self.get_item_by_name("Adventurer's Guild") bus = self.get_item_by_name("Bus Repair") skull_key = self.get_item_by_name("Skull Key") - return [*combat_levels, *mining_levels, guild, *pickaxes, *swords, bus, skull_key] + return [*combat_levels, *mining_levels, *pickaxes, *swords, bus, skull_key] def generate_items_for_skull_100(self) -> List[Item]: pickaxes = [self.get_item_by_name("Progressive Pickaxe")] * 4 swords = [self.get_item_by_name("Progressive Sword")] * 5 combat_levels = [self.get_item_by_name("Combat Level")] * 8 mining_levels = [self.get_item_by_name("Mining Level")] * 8 - guild = self.get_item_by_name("Adventurer's Guild") bus = self.get_item_by_name("Bus Repair") skull_key = self.get_item_by_name("Skull Key") - return [*combat_levels, *mining_levels, guild, *pickaxes, *swords, bus, skull_key] + return [*combat_levels, *mining_levels, *pickaxes, *swords, bus, skull_key] class TestLocationGeneration(SVTestBase): diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 6b65675c4df2..e812380a8c3f 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -6,6 +6,7 @@ from BaseClasses import ItemClassification, MultiWorld from Options import NamedRange from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods, allsanity_options_with_mods +from .checks.world_checks import basic_checks from .. import StardewItem, items_by_group, Group, StardewValleyWorld from ..locations import locations_by_tag, LocationTags, location_table from ..options import ExcludeGingerIsland, ToolProgression, Goal, SeasonRandomization, TrapItems, SpecialOrderLocations, ArcadeMachineLocations @@ -18,21 +19,6 @@ TOOLS = {"Hoe", "Pickaxe", "Axe", "Watering Can", "Trash Can", "Fishing Rod"} -def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): - for item in multiworld.get_items(): - multiworld.state.collect(item) - victory = multiworld.find_item("Victory", 1) - can_reach_victory = victory.can_reach(multiworld.state) - tester.assertTrue(can_reach_victory, victory.access_rule.explain(multiworld.state)) - - -def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): - tester.assertIn(StardewItem("Victory", ItemClassification.progression, None, 1), multiworld.get_items()) - assert_can_win(tester, multiworld) - non_event_locations = [location for location in multiworld.get_locations() if not location.event] - tester.assertEqual(len(multiworld.itempool), len(non_event_locations)) - - def check_no_ginger_island(tester: unittest.TestCase, multiworld: MultiWorld): ginger_island_items = [item_data.name for item_data in items_by_group[Group.GINGER_ISLAND]] ginger_island_locations = [location_data.name for location_data in locations_by_tag[LocationTags.GINGER_ISLAND]] diff --git a/worlds/stardew_valley/test/TestOptionsPairs.py b/worlds/stardew_valley/test/TestOptionsPairs.py new file mode 100644 index 000000000000..949f9a74d7e9 --- /dev/null +++ b/worlds/stardew_valley/test/TestOptionsPairs.py @@ -0,0 +1,43 @@ +from . import SVTestBase +from .checks.world_checks import basic_checks +from ..options import Goal, QuestLocations + + +class TestCrypticNoteNoQuests(SVTestBase): + options = { + Goal.internal_name: Goal.option_cryptic_note, + QuestLocations.internal_name: "none" + } + + def test_given_option_pair_then_basic_checks(self): + basic_checks(self, self.multiworld) + + +class TestCompleteCollectionNoQuests(SVTestBase): + options = { + Goal.internal_name: Goal.option_complete_collection, + QuestLocations.internal_name: "none" + } + + def test_given_option_pair_then_basic_checks(self): + basic_checks(self, self.multiworld) + + +class TestProtectorOfTheValleyNoQuests(SVTestBase): + options = { + Goal.internal_name: Goal.option_protector_of_the_valley, + QuestLocations.internal_name: "none" + } + + def test_given_option_pair_then_basic_checks(self): + basic_checks(self, self.multiworld) + + +class TestCraftMasterNoQuests(SVTestBase): + options = { + Goal.internal_name: Goal.option_craft_master, + QuestLocations.internal_name: "none" + } + + def test_given_option_pair_then_basic_checks(self): + basic_checks(self, self.multiworld) diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index dd9c5aabe4ce..bbe58cd3c078 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -265,7 +265,6 @@ class TestWeaponsLogic(SVTestBase): } def test_mine(self): - self.collect(self.world.create_item("Adventurer's Guild")) 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) @@ -330,30 +329,6 @@ def GiveItemAndCheckReachableMine(self, item_name: str, reachable_level: int): self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state, expected=False)) -class TestMonstersanityProgressiveRules(SVTestBase): - options = { - options.Monstersanity.internal_name: options.Monstersanity.option_progressive_goals, - } - - def test_has_rules(self): - for location in self.multiworld.get_locations(self.player): - if "Monster Eradication: " not in location.name: - continue - self.assertFalse(self.world.logic.region.can_reach_location(location)(self.multiworld.state)) - - -class TestMonstersanitySplitRules(SVTestBase): - options = { - options.Monstersanity.internal_name: options.Monstersanity.option_split_goals, - } - - def test_has_rules(self): - for location in self.multiworld.get_locations(self.player): - if "Monster Eradication: " not in location.name: - continue - self.assertFalse(self.world.logic.region.can_reach_location(location)(self.multiworld.state)) - - class TestRecipeLearnLogic(SVTestBase): options = { BuildingProgression.internal_name: BuildingProgression.option_progressive, @@ -453,7 +428,6 @@ def test_can_craft_recipe(self): self.collect([self.world.create_item("Combat Level")] * 10) self.collect([self.world.create_item("Fishing Level")] * 10) self.collect_all_the_money() - self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False) self.assertFalse(rule(self.multiworld.state)) self.multiworld.state.collect(self.world.create_item("Marble Brazier Recipe"), event=False) @@ -560,14 +534,14 @@ class TestDonationLogicAll(SVTestBase): } def test_cannot_make_any_donation_without_museum_access(self): - guild_item = "Adventurer's Guild" - swap_museum_and_guild(self.multiworld, self.player) - collect_all_except(self.multiworld, guild_item) + 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(guild_item), event=False) + 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)) @@ -579,16 +553,16 @@ class TestDonationLogicRandomized(SVTestBase): } def test_cannot_make_any_donation_without_museum_access(self): - guild_item = "Adventurer's Guild" - swap_museum_and_guild(self.multiworld, self.player) - collect_all_except(self.multiworld, guild_item) + 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.multiworld.get_locations() if not location.event and 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(guild_item), event=False) + 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)) @@ -600,26 +574,26 @@ class TestDonationLogicMilestones(SVTestBase): } def test_cannot_make_any_donation_without_museum_access(self): - guild_item = "Adventurer's Guild" - swap_museum_and_guild(self.multiworld, self.player) - collect_all_except(self.multiworld, guild_item) + 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(guild_item), event=False) + 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_guild(multiworld, player): +def swap_museum_and_bathhouse(multiworld, player): museum_region = multiworld.get_region(Region.museum, player) - guild_region = multiworld.get_region(Region.adventurer_guild, player) + bathhouse_region = multiworld.get_region(Region.bathhouse_entrance, player) museum_entrance = multiworld.get_entrance(Entrance.town_to_museum, player) - guild_entrance = multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player) - museum_entrance.connect(guild_region) - guild_entrance.connect(museum_region) + bathhouse_entrance = multiworld.get_entrance(Entrance.enter_bathhouse_entrance, player) + museum_entrance.connect(bathhouse_region) + bathhouse_entrance.connect(museum_region) def collect_all_except(multiworld, item_to_not_collect: str): @@ -640,7 +614,6 @@ def test_earning_dating_heart_requires_dating(self): 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) - self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), 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) diff --git a/worlds/stardew_valley/test/checks/world_checks.py b/worlds/stardew_valley/test/checks/world_checks.py index 5ee20534b3e3..2d8bdd7f631c 100644 --- a/worlds/stardew_valley/test/checks/world_checks.py +++ b/worlds/stardew_valley/test/checks/world_checks.py @@ -32,4 +32,9 @@ def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): def assert_same_number_items_locations(tester: unittest.TestCase, multiworld: MultiWorld): non_event_locations = [location for location in multiworld.get_locations() if not location.event] - tester.assertEqual(len(multiworld.itempool), len(non_event_locations)) \ No newline at end of file + tester.assertEqual(len(multiworld.itempool), len(non_event_locations)) + + +def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): + assert_can_win(tester, multiworld) + assert_same_number_items_locations(tester, multiworld) \ No newline at end of file diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index f7f9ee8fd179..84319f3649c5 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -1,19 +1,12 @@ -import unittest from random import random from typing import Dict -from BaseClasses import MultiWorld from Options import NamedRange from .option_names import options_to_include -from worlds.stardew_valley.test.checks.world_checks import assert_can_win, assert_same_number_items_locations +from ..checks.world_checks import basic_checks from .. import setup_solo_multiworld, SVTestCase, SVTestBase -def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): - assert_can_win(tester, multiworld) - assert_same_number_items_locations(tester, multiworld) - - def get_option_choices(option) -> Dict[str, int]: if issubclass(option, NamedRange): return option.special_range_names From 2c29068e94835dac938ae15e78a09e6861eef311 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 7 Dec 2023 22:18:17 -0500 Subject: [PATCH 325/482] - Fix ItemLinkGroup class being gone(?) --- worlds/stardew_valley/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index bfc7066d1bee..e1276a1092ca 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -321,7 +321,7 @@ def generate_filler_item_pool_names(self): def get_filler_item_rules(self): if self.player in self.multiworld.groups: - link_group: ItemLinkGroup = self.multiworld.groups[self.player] + link_group = self.multiworld.groups[self.player] include_traps = True exclude_island = False for player in link_group["players"]: From 83acf5cd4e67c348ec24608ab4d0a018690c6033 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 12:12:04 -0500 Subject: [PATCH 326/482] - Added staircase resource pack --- worlds/stardew_valley/data/items.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 00667a416b72..89adee3ebb9b 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -721,6 +721,7 @@ id,name,classification,groups,mod_name 5263,Slime Egg-Press,useful,RESOURCE_PACK, 5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5266,Resource Pack: 5 Staircase,filler,"RESOURCE_PACK", 10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill 10002,Magic Level,progression,SKILL_LEVEL_UP,Magic 10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill From 6ed072e0766df3f98b7eaf87990afe9cae5e6972 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 12:12:49 -0500 Subject: [PATCH 327/482] - Added a test for pre rolled randomness --- .../test/long/TestPreRolledRandomness.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 worlds/stardew_valley/test/long/TestPreRolledRandomness.py diff --git a/worlds/stardew_valley/test/long/TestPreRolledRandomness.py b/worlds/stardew_valley/test/long/TestPreRolledRandomness.py new file mode 100644 index 000000000000..ee7d590497c9 --- /dev/null +++ b/worlds/stardew_valley/test/long/TestPreRolledRandomness.py @@ -0,0 +1,20 @@ +from random import random +from ..checks.world_checks import basic_checks +from .. import setup_solo_multiworld, SVTestCase +from ...options import EntranceRandomization, BundleRandomization, BundlePrice + + +class TestGeneratePreRolledRandomness(SVTestCase): + def test_given_pre_rolled_difficult_randomness_when_generate_then_basic_checks(self): + if self.skip_long_tests: + return + choices = {EntranceRandomization.internal_name: EntranceRandomization.option_buildings, + BundleRandomization.internal_name: BundleRandomization.option_remixed, + BundlePrice.internal_name: BundlePrice.option_maximum} + num_tests = 1000 + for i in range(num_tests): + seed = int(random() * pow(10, 18) - 1) + # seed = 738592514038774912 + with self.subTest(f"Entrance Randomizer and Remixed Bundles [SEED: {seed}]"): + multiworld = setup_solo_multiworld(choices, seed) + basic_checks(self, multiworld) \ No newline at end of file From eab3366066f07a220459796576f8e77d8d051f4e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 12:17:38 -0500 Subject: [PATCH 328/482] - Shipping bin is now always early --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/options.py | 16 ++++++---------- worlds/stardew_valley/presets.py | 8 ++++---- worlds/stardew_valley/test/TestRules.py | 2 +- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index e1276a1092ca..3feb0d82de35 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -188,7 +188,7 @@ def precollect_starting_season(self): self.multiworld.push_precollected(starting_season) def setup_early_items(self): - if self.options.building_progression & BuildingProgression.early_shipping_bin: + if self.options.building_progression & BuildingProgression.option_progressive: self.multiworld.early_items[self.player]["Shipping Bin"] = 1 if self.options.backpack_progression == BackpackProgression.option_early_progressive: diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index c3d78babebd1..22b170a86202 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -257,16 +257,12 @@ class BuildingProgression(Choice): internal_name = "building_progression" display_name = "Building Progression" default = 3 - option_vanilla = 0b0000 # 0 - option_vanilla_cheap = 0b0100 # 4 - option_vanilla_very_cheap = 0b1000 # 8 - option_progressive = 0b0001 # 1 - option_progressive_cheap = 0b0101 # 5 - option_progressive_very_cheap = 0b1001 # 9 - early_shipping_bin = 0b0010 # 2 - option_progressive_early_shipping_bin = 0b0011 # 3 - option_progressive_early_shipping_bin_cheap = 0b0111 # 7 - option_progressive_early_shipping_bin_very_cheap = 0b1011 # 11 + option_vanilla = 0b000 # 0 + option_vanilla_cheap = 0b010 # 2 + option_vanilla_very_cheap = 0b100 # 4 + option_progressive = 0b001 # 1 + option_progressive_cheap = 0b011 # 3 + option_progressive_very_cheap = 0b101 # 5 class FestivalLocations(Choice): diff --git a/worlds/stardew_valley/presets.py b/worlds/stardew_valley/presets.py index 7e229d6c8e53..03203c7549f3 100644 --- a/worlds/stardew_valley/presets.py +++ b/worlds/stardew_valley/presets.py @@ -60,7 +60,7 @@ ToolProgression.internal_name: ToolProgression.option_progressive, ElevatorProgression.internal_name: ElevatorProgression.option_progressive, SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_early_shipping_bin, + BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap, FestivalLocations.internal_name: FestivalLocations.option_easy, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, @@ -98,7 +98,7 @@ ToolProgression.internal_name: ToolProgression.option_progressive, ElevatorProgression.internal_name: ElevatorProgression.option_progressive_from_previous_floor, SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_early_shipping_bin, + BuildingProgression.internal_name: BuildingProgression.option_progressive_cheap, FestivalLocations.internal_name: FestivalLocations.option_hard, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_victories_easy, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_only, @@ -212,7 +212,7 @@ ToolProgression.internal_name: ToolProgression.option_progressive, ElevatorProgression.internal_name: ElevatorProgression.option_progressive_from_previous_floor, SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_early_shipping_bin, + BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap, FestivalLocations.internal_name: FestivalLocations.option_disabled, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_disabled, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_disabled, @@ -288,7 +288,7 @@ ToolProgression.internal_name: ToolProgression.option_progressive, ElevatorProgression.internal_name: ElevatorProgression.option_progressive, SkillProgression.internal_name: SkillProgression.option_progressive, - BuildingProgression.internal_name: BuildingProgression.option_progressive_early_shipping_bin, + BuildingProgression.internal_name: BuildingProgression.option_progressive, FestivalLocations.internal_name: FestivalLocations.option_hard, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, diff --git a/worlds/stardew_valley/test/TestRules.py b/worlds/stardew_valley/test/TestRules.py index bbe58cd3c078..573842fe562b 100644 --- a/worlds/stardew_valley/test/TestRules.py +++ b/worlds/stardew_valley/test/TestRules.py @@ -106,7 +106,7 @@ def test_vault_2500g_bundle(self): class TestBuildingLogic(SVTestBase): options = { - BuildingProgression.internal_name: BuildingProgression.option_progressive_early_shipping_bin + BuildingProgression.internal_name: BuildingProgression.option_progressive } def test_coop_blueprint(self): From f1c228c4e8bc8bd7e7c347523ab8567e5ce9214d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 12:59:02 -0500 Subject: [PATCH 329/482] - Fix an issue with starting items being wrongly double counted for total progression items received --- worlds/stardew_valley/__init__.py | 14 ++++++++++---- worlds/stardew_valley/items.py | 14 ++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 3feb0d82de35..c57e2fc8858e 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -163,8 +163,8 @@ def precollect_farm_type(self): if not chosen_farm_types: chosen_farm_types = all_farm_type_names - starting_season = self.create_item(self.multiworld.random.choice(chosen_farm_types)) - self.multiworld.push_precollected(starting_season) + starting_farm = self.create_starting_item(self.multiworld.random.choice(chosen_farm_types)) + self.multiworld.push_precollected(starting_farm) def precollect_starting_season(self): if self.options.season_randomization == SeasonRandomization.option_progressive: @@ -174,7 +174,7 @@ def precollect_starting_season(self): if self.options.season_randomization == SeasonRandomization.option_disabled: for season in season_pool: - self.multiworld.push_precollected(self.create_item(season)) + self.multiworld.push_precollected(self.create_starting_item(season)) return if [item for item in self.multiworld.precollected_items[self.player] @@ -184,7 +184,7 @@ def precollect_starting_season(self): if self.options.season_randomization == SeasonRandomization.option_randomized_not_winter: season_pool = [season for season in season_pool if season.name != "Winter"] - starting_season = self.create_item(self.multiworld.random.choice(season_pool)) + starting_season = self.create_starting_item(self.multiworld.random.choice(season_pool)) self.multiworld.push_precollected(starting_season) def setup_early_items(self): @@ -290,6 +290,12 @@ def create_item(self, item: Union[str, ItemData], override_classification: ItemC self.total_progression_items += 1 return StardewItem(item.name, override_classification, item.code, self.player) + def create_starting_item(self, item: Union[str, ItemData]) -> StardewItem: + if isinstance(item, str): + item = item_table[item] + + return StardewItem(item.name, item.classification, item.code, self.player) + def create_event_location(self, location_data: LocationData, rule: StardewRule = None, item: Optional[str] = None): if rule is None: rule = True_() diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index ce451b445934..aee920690ce9 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -165,9 +165,7 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t items = [] unique_items = create_unique_items(item_factory, options, random) - for item in items_to_exclude: - if item in unique_items: - unique_items.remove(item) + remove_items(items_to_exclude, unique_items) remove_items_if_no_room_for_them(unique_items, locations_count, random) @@ -185,6 +183,12 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t return items +def remove_items(items_to_remove, items): + for item in items_to_remove: + if item in items: + items.remove(item) + + def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count: int, random: Random): if len(unique_items) <= locations_count: return @@ -198,9 +202,7 @@ def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count: logger.debug(f"Player has more items than locations, trying to remove {number_of_items_to_remove} random filler items") assert len(removable_items) >= number_of_items_to_remove, get_too_many_items_error_message(locations_count, len(unique_items)) items_to_remove = random.sample(removable_items, number_of_items_to_remove) - for item in items_to_remove: - if item in unique_items: - unique_items.remove(item) + remove_items(item_deleter, items_to_remove, unique_items) def create_unique_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random) -> List[Item]: From 52cb403300de02feb6afa7bd2c00651b3eedd928 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 13:03:58 -0500 Subject: [PATCH 330/482] - remove leftover item deleter --- worlds/stardew_valley/items.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index aee920690ce9..16fd875c66d0 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -202,7 +202,7 @@ def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count: logger.debug(f"Player has more items than locations, trying to remove {number_of_items_to_remove} random filler items") assert len(removable_items) >= number_of_items_to_remove, get_too_many_items_error_message(locations_count, len(unique_items)) items_to_remove = random.sample(removable_items, number_of_items_to_remove) - remove_items(item_deleter, items_to_remove, unique_items) + remove_items(items_to_remove, unique_items) def create_unique_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random) -> List[Item]: From 01f5ead2c31b034bddfc337e4e0706f2a02b3874 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 6 Dec 2023 13:57:56 -0600 Subject: [PATCH 331/482] Fix some basic logic for Diamond Wand --- .../logic/relationship_logic.py | 2 ++ .../mods/logic/deepwoods_logic.py | 5 +++++ worlds/stardew_valley/mods/logic/sve_logic.py | 2 +- worlds/stardew_valley/rules.py | 8 ++++++-- worlds/stardew_valley/test/mods/TestMods.py | 20 +++++++++++++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index a2a5fd4b81b0..bea5e13ea4c5 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -122,6 +122,8 @@ def can_meet(self, npc: str) -> StardewRule: scarlett_summer = self.logic.season.has(Season.summer) & self.can_meet(ModNPC.susan) scarlett_fall = self.logic.season.has(Season.fall) & self.can_meet(ModNPC.sophia) rules.append(scarlett_job & (scarlett_spring | scarlett_summer | scarlett_fall)) + elif npc == ModNPC.morgan: + rules.append(self.logic.received("Morgan's Schooling")) return And(*rules) diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index dcd753c3f5e9..e9c9c7d57305 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -7,6 +7,7 @@ from ...logic.received_logic import ReceivedLogicMixin from ...logic.skill_logic import SkillLogicMixin from ...logic.tool_logic import ToolLogicMixin +from ...mods.mod_data import ModNames from ...options import SkillProgression, ElevatorProgression from ...stardew_rule import StardewRule, True_, And from ...strings.ap_names.transport_names import ModTransportation @@ -53,4 +54,8 @@ def can_chop_to_depth(self, floor: int) -> StardewRule: def can_pull_sword(self) -> StardewRule: rules = [self.logic.received("Pendant of Depths") & self.logic.received("Pendant of Community") & self.logic.received("Pendant of Elders"), self.logic.skill.has_total_level(40)] + if ModNames.luck_skill in self.options.mods: + rules.append(self.logic.received("Luck Level", 7)) + else: + rules.append(self.logic.has("Magic Rock Candy")) # You need more luck than this, but it'll push the logic down a ways; you can get the rest there. return And(*rules) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 0ff348f57725..4be398b962d5 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -14,6 +14,7 @@ from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes +from ...strings.quest_names import ModQuest from ...stardew_rule import Or @@ -30,7 +31,6 @@ def initialize_rules(self): SVELocation.tempered_galaxy_sword: self.logic.money.can_spend_at(SVERegion.alesia_shop, 350000), SVELocation.tempered_galaxy_dagger: self.logic.money.can_spend_at(SVERegion.isaac_shop, 600000), SVELocation.tempered_galaxy_hammer: self.logic.money.can_spend_at(SVERegion.isaac_shop, 400000), - SVELocation.diamond_wand: self.logic.quest.can_complete_quest(SVELocation.monster_crops) & self.logic.region.can_reach(SVERegion.lances_house), }) def has_any_rune(self): diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 4891051989a8..ea8fdd7c6dab 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -20,6 +20,7 @@ from .stardew_rule import And from .strings.ap_names.event_names import Event from .strings.ap_names.transport_names import Transportation +from .strings.ap_names.mods.mod_items import SVELocation from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building from .strings.bundle_names import CCRoom @@ -32,7 +33,7 @@ from .strings.material_names import Material from .strings.metal_names import MetalBar from .strings.quest_names import Quest, ModQuest -from .strings.region_names import Region +from .strings.region_names import Region, SVERegion from .strings.season_names import Season from .strings.skill_names import ModSkill, Skill from .strings.tool_names import Tool, ToolMaterial @@ -925,10 +926,11 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), logic.quest.can_complete_quest(ModQuest.GrandpasShed)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) + logic.mod.sve.initialize_rules() for location in logic.registry.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), logic.registry.sve_location_rules[location]) @@ -942,3 +944,5 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla logic.received("Marlon's Boat Paddle")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), logic.received("Fable Reef Portal")) + MultiWorldRules.set_rule(multiworld.get_location(SVELocation.diamond_wand, player), + logic.quest.can_complete_quest(ModQuest.MonsterCrops) & logic.region.can_reach(SVERegion.lances_house)) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 17a16cc6d0bc..d6fc893cac33 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -48,6 +48,26 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi # return # assume the rest will work as well +class TestBaseLocationDependencies(SVTestBase): + options = { + Mods.internal_name: all_mods + } + + def test_lance_chest_requires_quest(self): + item_list = ["Spring", "Summer", "Fall", "Winter", "Marlon's Boat Paddle"] + item_list.extend(weapon for weapon in ["Progressive Weapon"]*3) + item_list.extend(tool for tool in ["Progressive Axe", "Progressive Pickaxe"]*2) + random.shuffle(item_list) + world_items = [] + rule = self.world.logic.region.can_reach_location("Lance's Diamond Wand") + for item in item_list: + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state)) + current_item = self.world.create_item(item) + self.multiworld.state.collect(current_item, event=False) + world_items.append(current_item) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) + + class TestBaseItemGeneration(SVTestBase): options = { Friendsanity.internal_name: Friendsanity.option_all_with_marriage, From 92873ca14ee97d0642d233255c88ba0e88914bdb Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 6 Dec 2023 21:23:36 -0600 Subject: [PATCH 332/482] Remove test for now. --- worlds/stardew_valley/test/mods/TestMods.py | 28 ++++++--------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index d6fc893cac33..3f85b34b327b 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -1,6 +1,7 @@ import random import sys import unittest +from itertools import chain, combinations from typing import List, Union from BaseClasses import MultiWorld @@ -11,7 +12,7 @@ from ...locations import location_table from ...mods.mod_data import all_mods from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems, Chefsanity, \ - Shipsanity, Craftsanity + Shipsanity, Craftsanity, ToolProgression from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions @@ -28,6 +29,11 @@ def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.T tester.assertTrue(location.mod_name is None or location.mod_name in chosen_mods) +def powerset(iterable): + s = list(iterable) + return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) + + class TestGenerateModsOptions(SVTestCase): def test_given_single_mods_when_generate_then_basic_checks(self): @@ -48,26 +54,6 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi # return # assume the rest will work as well -class TestBaseLocationDependencies(SVTestBase): - options = { - Mods.internal_name: all_mods - } - - def test_lance_chest_requires_quest(self): - item_list = ["Spring", "Summer", "Fall", "Winter", "Marlon's Boat Paddle"] - item_list.extend(weapon for weapon in ["Progressive Weapon"]*3) - item_list.extend(tool for tool in ["Progressive Axe", "Progressive Pickaxe"]*2) - random.shuffle(item_list) - world_items = [] - rule = self.world.logic.region.can_reach_location("Lance's Diamond Wand") - for item in item_list: - self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state)) - current_item = self.world.create_item(item) - self.multiworld.state.collect(current_item, event=False) - world_items.append(current_item) - self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) - - class TestBaseItemGeneration(SVTestBase): options = { Friendsanity.internal_name: Friendsanity.option_all_with_marriage, From 7c89c4cbf294c9edfde89b6b87ac4c32eead9d55 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 6 Dec 2023 23:05:14 -0600 Subject: [PATCH 333/482] Fixed lance chest test, put in long. --- worlds/stardew_valley/test/mods/TestMods.py | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 3f85b34b327b..389d42a24fdf 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -1,6 +1,7 @@ import random import sys import unittest +from collections import Counter from itertools import chain, combinations from typing import List, Union @@ -54,6 +55,41 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi # return # assume the rest will work as well +class TestBaseLocationDependencies(SVTestBase): + options = { + Mods.internal_name: all_mods, + ToolProgression.internal_name: ToolProgression.option_progressive, + SeasonRandomization.internal_name: SeasonRandomization.option_randomized + } + + def test_lance_chest_requires_quest_thoroughly(self): # the method can be reused for other locations that seem troublesome. + if self.skip_long_tests: + return + self.multiworld.state.prog_items = {1: Counter()} + item_list = ["Spring", "Summer", "Fall", "Winter", "Marlon's Boat Paddle"] + item_list.extend(weapon for weapon in ["Progressive Weapon"]*3) + item_list.extend(tool for tool in ["Progressive Axe", "Progressive Pickaxe"]*2) + rule = self.world.logic.region.can_reach_location("Lance's Diamond Wand") + self.assertFalse(rule(self.multiworld.state), msg="Has No Items") + power_list = powerset(item_list) + for iterable in power_list: + iterable_items = [] + missing_items = [item for item in item_list if item not in iterable] + if not iterable or not missing_items: + continue + for item in iterable: + created_item = self.world.create_item(item) + self.multiworld.state.collect(created_item, event=False) + iterable_items.append(created_item) + self.assertFalse(rule(self.multiworld.state), f"Has {iterable} but not {missing_items}") + for item in iterable_items: + self.remove(item) + for item in item_list: + stinky_item = self.world.create_item(item) + self.multiworld.state.collect(stinky_item, event=False) + self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) + + class TestBaseItemGeneration(SVTestBase): options = { Friendsanity.internal_name: Friendsanity.option_all_with_marriage, From e4b228f32fedfb2048f923546b0a2bba26243b6d Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 7 Dec 2023 01:12:20 -0600 Subject: [PATCH 334/482] Faster test, clean up rules. --- worlds/stardew_valley/rules.py | 6 ++--- worlds/stardew_valley/test/mods/TestMods.py | 29 ++++++++------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index ea8fdd7c6dab..22024c3837cc 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -903,8 +903,6 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.quest.can_complete_quest(Quest.magic_ink)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), - logic.received("Fable Reef Portal")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.aurora_warp_to_aurora, player), @@ -925,8 +923,6 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.relationship.has_hearts(ModNPC.apples, 10)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), logic.quest.can_complete_quest(ModQuest.GrandpasShed)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) @@ -946,3 +942,5 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla logic.received("Fable Reef Portal")) MultiWorldRules.set_rule(multiworld.get_location(SVELocation.diamond_wand, player), logic.quest.can_complete_quest(ModQuest.MonsterCrops) & logic.region.can_reach(SVERegion.lances_house)) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 389d42a24fdf..9a29090134f4 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -16,6 +16,7 @@ Shipsanity, Craftsanity, ToolProgression from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions +tools = ["Progressive Weapon", "Progressive Axe", "Progressive Pickaxe"] def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld): if isinstance(chosen_mods, str): @@ -63,30 +64,22 @@ class TestBaseLocationDependencies(SVTestBase): } def test_lance_chest_requires_quest_thoroughly(self): # the method can be reused for other locations that seem troublesome. - if self.skip_long_tests: - return self.multiworld.state.prog_items = {1: Counter()} item_list = ["Spring", "Summer", "Fall", "Winter", "Marlon's Boat Paddle"] item_list.extend(weapon for weapon in ["Progressive Weapon"]*3) - item_list.extend(tool for tool in ["Progressive Axe", "Progressive Pickaxe"]*2) + item_list.extend(tool for tool in ["Progressive Axe"]*2) + item_list.extend(tool for tool in ["Progressive Pickaxe"]*2) + missing_items = [] + missing_items.extend(item_list) rule = self.world.logic.region.can_reach_location("Lance's Diamond Wand") self.assertFalse(rule(self.multiworld.state), msg="Has No Items") - power_list = powerset(item_list) - for iterable in power_list: - iterable_items = [] - missing_items = [item for item in item_list if item not in iterable] - if not iterable or not missing_items: - continue - for item in iterable: - created_item = self.world.create_item(item) - self.multiworld.state.collect(created_item, event=False) - iterable_items.append(created_item) - self.assertFalse(rule(self.multiworld.state), f"Has {iterable} but not {missing_items}") - for item in iterable_items: - self.remove(item) for item in item_list: - stinky_item = self.world.create_item(item) - self.multiworld.state.collect(stinky_item, event=False) + missing_items.remove(item) + created_item = self.world.create_item(item) + self.multiworld.state.collect(created_item, event=False) + if not missing_items: + continue + self.assertFalse(rule(self.multiworld.state), f"{missing_items}") self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) From f3804523bc26378817dbd4d2f6170764ff95f727 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 7 Dec 2023 10:42:44 -0600 Subject: [PATCH 335/482] Use typical fail message. --- worlds/stardew_valley/test/mods/TestMods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 9a29090134f4..e610ec9992ef 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -79,7 +79,7 @@ def test_lance_chest_requires_quest_thoroughly(self): # the method can be reuse self.multiworld.state.collect(created_item, event=False) if not missing_items: continue - self.assertFalse(rule(self.multiworld.state), f"{missing_items}") + self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state)) self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) From bb6863c1e904f8c873155cade6113eb5718ac0d0 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 8 Dec 2023 13:27:44 -0600 Subject: [PATCH 336/482] General fixes --- worlds/stardew_valley/logic/relationship_logic.py | 5 +++-- worlds/stardew_valley/mods/logic/deepwoods_logic.py | 11 +++++++---- .../stardew_valley/strings/ap_names/mods/mod_items.py | 11 +++++++++++ worlds/stardew_valley/strings/food_names.py | 1 + worlds/stardew_valley/test/mods/TestMods.py | 7 ------- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index bea5e13ea4c5..81ca32d627e6 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -13,6 +13,7 @@ from ..data.villagers_data import all_villagers_by_name, Villager from ..options import Friendsanity from ..stardew_rule import StardewRule, True_, And, Or, Count +from ..strings.ap_names.mods.mod_items import SVEQuestItem from ..strings.crop_names import Fruit from ..strings.generic_names import Generic from ..strings.gift_names import Gift @@ -117,13 +118,13 @@ def can_meet(self, npc: str) -> StardewRule: elif npc == ModNPC.apples: rules.append(self.logic.has(Fruit.starfruit)) elif npc == ModNPC.scarlett: - scarlett_job = self.logic.received("Scarlett's Job Offer") + scarlett_job = self.logic.received(SVEQuestItem.scarlett_job_offer) scarlett_spring = self.logic.season.has(Season.spring) & self.can_meet(ModNPC.andy) scarlett_summer = self.logic.season.has(Season.summer) & self.can_meet(ModNPC.susan) scarlett_fall = self.logic.season.has(Season.fall) & self.can_meet(ModNPC.sophia) rules.append(scarlett_job & (scarlett_spring | scarlett_summer | scarlett_fall)) elif npc == ModNPC.morgan: - rules.append(self.logic.received("Morgan's Schooling")) + rules.append(self.logic.received(SVEQuestItem.morgan_schooling)) return And(*rules) diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index e9c9c7d57305..086231997f45 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -11,7 +11,9 @@ from ...options import SkillProgression, ElevatorProgression from ...stardew_rule import StardewRule, True_, And from ...strings.ap_names.transport_names import ModTransportation +from ...strings.ap_names.mods.mod_items import DeepWoodsItem, SkillItem from ...strings.craftable_names import Bomb +from ...strings.food_names import Meal from ...strings.performance_names import Performance from ...strings.skill_names import Skill from ...strings.tool_names import Tool, ToolMaterial @@ -44,7 +46,7 @@ def can_reach_woods_depth(self, depth: int) -> StardewRule: def has_woods_rune_to_depth(self, floor: int) -> StardewRule: if self.options.skill_progression == ElevatorProgression.option_vanilla: return True_() - return self.logic.received("Progressive Woods Obelisk Sigils", int(floor / 10)) + return self.logic.received(DeepWoodsItem.obelisk_sigil, int(floor / 10)) def can_chop_to_depth(self, floor: int) -> StardewRule: previous_elevator = max(floor - 10, 0) @@ -52,10 +54,11 @@ def can_chop_to_depth(self, floor: int) -> StardewRule: self.can_reach_woods_depth(previous_elevator)) def can_pull_sword(self) -> StardewRule: - rules = [self.logic.received("Pendant of Depths") & self.logic.received("Pendant of Community") & self.logic.received("Pendant of Elders"), + rules = [self.logic.received(DeepWoodsItem.pendant_depths) & self.logic.received(DeepWoodsItem.pendant_community) & + self.logic.received(DeepWoodsItem.pendant_elder), self.logic.skill.has_total_level(40)] if ModNames.luck_skill in self.options.mods: - rules.append(self.logic.received("Luck Level", 7)) + rules.append(self.logic.received(SkillItem.luck_skill, 7)) else: - rules.append(self.logic.has("Magic Rock Candy")) # You need more luck than this, but it'll push the logic down a ways; you can get the rest there. + rules.append(self.logic.has(Meal.magic_rock_candy)) # You need more luck than this, but it'll push the logic down a ways; you can get the rest there. return And(*rules) diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 1e5f39493dbe..59f9d1782780 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -1,6 +1,17 @@ from typing import List +class DeepWoodsItem: + pendant_community = "Pendant of Community" + pendant_elder = "Pendant of Elders" + pendant_depths = "Pendant of Depths" + obelisk_sigil = "Progressive Woods Obelisk Sigils" + + +class SkillItem: + luck_skill = "Luck Level" + + class SVEQuestItem: aurora_vineyard_tablet = "Aurora Vineyard Tablet" iridium_bomb = "Iridium Bomb" diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index 07dace7d7d1f..b0a187b0154d 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -77,6 +77,7 @@ class Meal: tropical_curry = "Tropical Curry" trout_soup = "Trout Soup" vegetable_medley = "Vegetable Medley" + magic_rock_candy = "Magic Rock Candy" class Beverage: diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index e610ec9992ef..6eb451cb973c 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -16,7 +16,6 @@ Shipsanity, Craftsanity, ToolProgression from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions -tools = ["Progressive Weapon", "Progressive Axe", "Progressive Pickaxe"] def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld): if isinstance(chosen_mods, str): @@ -31,11 +30,6 @@ def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.T tester.assertTrue(location.mod_name is None or location.mod_name in chosen_mods) -def powerset(iterable): - s = list(iterable) - return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) - - class TestGenerateModsOptions(SVTestCase): def test_given_single_mods_when_generate_then_basic_checks(self): @@ -64,7 +58,6 @@ class TestBaseLocationDependencies(SVTestBase): } def test_lance_chest_requires_quest_thoroughly(self): # the method can be reused for other locations that seem troublesome. - self.multiworld.state.prog_items = {1: Counter()} item_list = ["Spring", "Summer", "Fall", "Winter", "Marlon's Boat Paddle"] item_list.extend(weapon for weapon in ["Progressive Weapon"]*3) item_list.extend(tool for tool in ["Progressive Axe"]*2) From a80afbe8aa802545f97f519d4209e1369ffb129f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 18:45:23 -0500 Subject: [PATCH 337/482] - Add some early items to help the generator --- worlds/stardew_valley/__init__.py | 10 +-- worlds/stardew_valley/data/locations.csv | 28 +++--- worlds/stardew_valley/data/museum_data.py | 87 +++++++++---------- worlds/stardew_valley/early_items.py | 55 ++++++++++++ worlds/stardew_valley/logic/logic.py | 14 +-- worlds/stardew_valley/logic/museum_logic.py | 12 ++- worlds/stardew_valley/logic/time_logic.py | 2 +- worlds/stardew_valley/mods/logic/sve_logic.py | 10 ++- worlds/stardew_valley/rules.py | 3 +- 9 files changed, 142 insertions(+), 79 deletions(-) create mode 100644 worlds/stardew_valley/early_items.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index c57e2fc8858e..54be52ceff2e 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -7,6 +7,7 @@ from . import rules from .bundles.bundle_room import BundleRoom from .bundles.bundles import get_all_bundles +from .early_items import setup_early_items from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs from .locations import location_table, create_locations, LocationData, locations_by_tag from .logic.bundle_logic import BundleLogic @@ -146,7 +147,7 @@ def create_items(self): self.multiworld.itempool += created_items - self.setup_early_items() + setup_early_items(self.multiworld, self.options, self.player, self.multiworld.random) self.setup_player_events() self.setup_victory() @@ -187,13 +188,6 @@ def precollect_starting_season(self): starting_season = self.create_starting_item(self.multiworld.random.choice(season_pool)) self.multiworld.push_precollected(starting_season) - def setup_early_items(self): - if self.options.building_progression & BuildingProgression.option_progressive: - self.multiworld.early_items[self.player]["Shipping Bin"] = 1 - - if self.options.backpack_progression == BackpackProgression.option_early_progressive: - self.multiworld.early_items[self.player]["Progressive Backpack"] = 1 - def setup_player_events(self): self.setup_construction_events() self.setup_quest_events() diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index e533fda24f6d..a17db08c1573 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -302,21 +302,21 @@ id,region,name,tags,mod_name 706,Farmhouse,Spouse Stardrop,, 707,Sewer,Krobus Stardrop,MANDATORY, 801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, -802,The Mines - Floor 20,Help Wanted: Gathering 2,HELP_WANTED, -803,The Mines - Floor 35,Help Wanted: Gathering 3,HELP_WANTED, -804,The Mines - Floor 50,Help Wanted: Gathering 4,HELP_WANTED, -805,The Mines - Floor 65,Help Wanted: Gathering 5,HELP_WANTED, -806,The Mines - Floor 80,Help Wanted: Gathering 6,HELP_WANTED, -807,The Mines - Floor 95,Help Wanted: Gathering 7,HELP_WANTED, -808,The Mines - Floor 110,Help Wanted: Gathering 8,HELP_WANTED, +802,The Mines - Floor 10,Help Wanted: Gathering 2,HELP_WANTED, +803,The Mines - Floor 15,Help Wanted: Gathering 3,HELP_WANTED, +804,The Mines - Floor 20,Help Wanted: Gathering 4,HELP_WANTED, +805,The Mines - Floor 25,Help Wanted: Gathering 5,HELP_WANTED, +806,The Mines - Floor 30,Help Wanted: Gathering 6,HELP_WANTED, +807,The Mines - Floor 35,Help Wanted: Gathering 7,HELP_WANTED, +808,The Mines - Floor 40,Help Wanted: Gathering 8,HELP_WANTED, 811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,The Mines - Floor 20,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,The Mines - Floor 35,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,The Mines - Floor 50,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,The Mines - Floor 65,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,The Mines - Floor 80,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,The Mines - Floor 95,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,The Mines - Floor 110,Help Wanted: Slay Monsters 8,HELP_WANTED, +812,The Mines - Floor 15,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 25,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 35,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 45,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 55,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 65,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 75,Help Wanted: Slay Monsters 8,HELP_WANTED, 821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, 822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, 823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index 2e80d7d2ddcd..1ed1a4a7edc8 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -62,7 +62,7 @@ def create_artifact(name: str, def create_mineral(name: str, - locations: Union[str, Tuple[str, ...]], + locations: Union[str, Tuple[str, ...]] = (), geodes: Union[str, Tuple[str, ...]] = (), monsters: Union[str, Tuple[str, ...]] = (), difficulty: Optional[float] = None) -> MuseumItem: @@ -199,89 +199,86 @@ class Mineral: prismatic_shard = create_mineral("Prismatic Shard", Region.skull_cavern_100, geodes=unlikely, monsters=unlikely) - alamite = create_mineral("Alamite", Region.town, + alamite = create_mineral("Alamite", geodes=(Geode.geode, Geode.omni)) - bixite = create_mineral("Bixite", Region.town, + bixite = create_mineral("Bixite", geodes=(Geode.magma, Geode.omni), monsters=unlikely) - baryte = create_mineral("Baryte", Region.town, + baryte = create_mineral("Baryte", geodes=(Geode.magma, Geode.omni)) - aerinite = create_mineral("Aerinite", Region.town, + aerinite = create_mineral("Aerinite", geodes=(Geode.frozen, Geode.omni)) - calcite = create_mineral("Calcite", Region.town, + calcite = create_mineral("Calcite", geodes=(Geode.geode, Geode.omni)) - dolomite = create_mineral("Dolomite", Region.town, + dolomite = create_mineral("Dolomite", geodes=(Geode.magma, Geode.omni)) - esperite = create_mineral("Esperite", Region.town, + esperite = create_mineral("Esperite", geodes=(Geode.frozen, Geode.omni)) - fluorapatite = create_mineral("Fluorapatite", Region.town, + fluorapatite = create_mineral("Fluorapatite", geodes=(Geode.frozen, Geode.omni)) - geminite = create_mineral("Geminite", Region.town, + geminite = create_mineral("Geminite", geodes=(Geode.frozen, Geode.omni)) - helvite = create_mineral("Helvite", Region.town, + helvite = create_mineral("Helvite", geodes=(Geode.magma, Geode.omni)) - jamborite = create_mineral("Jamborite", Region.town, + jamborite = create_mineral("Jamborite", geodes=(Geode.geode, Geode.omni)) - jagoite = create_mineral("Jagoite", Region.town, + jagoite = create_mineral("Jagoite", geodes=(Geode.geode, Geode.omni)) - kyanite = create_mineral("Kyanite", Region.town, + kyanite = create_mineral("Kyanite", geodes=(Geode.frozen, Geode.omni)) - lunarite = create_mineral("Lunarite", Region.town, + lunarite = create_mineral("Lunarite", geodes=(Geode.frozen, Geode.omni)) - malachite = create_mineral("Malachite", Region.town, + malachite = create_mineral("Malachite", geodes=(Geode.geode, Geode.omni)) - neptunite = create_mineral("Neptunite", Region.town, + neptunite = create_mineral("Neptunite", geodes=(Geode.magma, Geode.omni)) - lemon_stone = create_mineral("Lemon Stone", Region.town, + lemon_stone = create_mineral("Lemon Stone", geodes=(Geode.magma, Geode.omni)) - nekoite = create_mineral("Nekoite", Region.town, + nekoite = create_mineral("Nekoite", geodes=(Geode.geode, Geode.omni)) - orpiment = create_mineral("Orpiment", Region.town, + orpiment = create_mineral("Orpiment", geodes=(Geode.geode, Geode.omni)) - petrified_slime = create_mineral("Petrified Slime", Region.town, + petrified_slime = create_mineral("Petrified Slime", geodes=(Geode.geode, Geode.omni)) - thunder_egg = create_mineral("Thunder Egg", Region.town, + thunder_egg = create_mineral("Thunder Egg", geodes=(Geode.geode, Geode.omni)) - pyrite = create_mineral("Pyrite", Region.town, + pyrite = create_mineral("Pyrite", geodes=(Geode.frozen, Geode.omni)) - ocean_stone = create_mineral("Ocean Stone", Region.town, + ocean_stone = create_mineral("Ocean Stone", geodes=(Geode.frozen, Geode.omni)) - ghost_crystal = create_mineral("Ghost Crystal", Region.town, + ghost_crystal = create_mineral("Ghost Crystal", geodes=(Geode.frozen, Geode.omni)) - tigerseye = create_mineral("Tigerseye", Region.town, + tigerseye = create_mineral("Tigerseye", geodes=(Geode.magma, Geode.omni)) - jasper = create_mineral("Jasper", Region.town, + jasper = create_mineral("Jasper", geodes=(Geode.magma, Geode.omni)) - opal = create_mineral("Opal", Region.town, + opal = create_mineral("Opal", geodes=(Geode.frozen, Geode.omni)) - fire_opal = create_mineral("Fire Opal", Region.town, + fire_opal = create_mineral("Fire Opal", geodes=(Geode.magma, Geode.omni)) - celestine = create_mineral("Celestine", Region.town, + celestine = create_mineral("Celestine", geodes=(Geode.geode, Geode.omni)) - marble = create_mineral("Marble", Region.town, + marble = create_mineral("Marble", geodes=(Geode.frozen, Geode.omni)) - sandstone = create_mineral("Sandstone", Region.town, + sandstone = create_mineral("Sandstone", geodes=(Geode.geode, Geode.omni)) - granite = create_mineral("Granite", Region.town, + granite = create_mineral("Granite", geodes=(Geode.geode, Geode.omni)) - basalt = create_mineral("Basalt", Region.town, + basalt = create_mineral("Basalt", geodes=(Geode.magma, Geode.omni)) - limestone = create_mineral("Limestone", Region.town, + limestone = create_mineral("Limestone", geodes=(Geode.geode, Geode.omni)) - soapstone = create_mineral("Soapstone", Region.town, + soapstone = create_mineral("Soapstone", geodes=(Geode.frozen, Geode.omni)) - hematite = create_mineral("Hematite", Region.town, + hematite = create_mineral("Hematite", geodes=(Geode.frozen, Geode.omni)) - mudstone = create_mineral("Mudstone", Region.town, + mudstone = create_mineral("Mudstone", geodes=(Geode.geode, Geode.omni)) - obsidian = create_mineral("Obsidian", Region.town, + obsidian = create_mineral("Obsidian", geodes=(Geode.magma, Geode.omni)) - slate = create_mineral("Slate", Region.town, - geodes=(Geode.geode, Geode.omni)) - fairy_stone = create_mineral("Fairy Stone", Region.town, - geodes=(Geode.frozen, Geode.omni)) - star_shards = create_mineral("Star Shards", Region.town, - geodes=(Geode.magma, Geode.omni)) + slate = create_mineral("Slate", geodes=(Geode.geode, Geode.omni)) + fairy_stone = create_mineral("Fairy Stone", geodes=(Geode.frozen, Geode.omni)) + star_shards = create_mineral("Star Shards", geodes=(Geode.magma, Geode.omni)) dwarf_scrolls = (Artifact.dwarf_scroll_i, Artifact.dwarf_scroll_ii, Artifact.dwarf_scroll_iii, Artifact.dwarf_scroll_iv) diff --git a/worlds/stardew_valley/early_items.py b/worlds/stardew_valley/early_items.py new file mode 100644 index 000000000000..d7ec48d0f97f --- /dev/null +++ b/worlds/stardew_valley/early_items.py @@ -0,0 +1,55 @@ +from random import Random + +from .options import BuildingProgression, StardewValleyOptions, BackpackProgression, ExcludeGingerIsland, SeasonRandomization, SpecialOrderLocations, \ + Monstersanity + +early_candidate_rate = 4 +always_early_candidates = ["Greenhouse", "Desert Obelisk", "Rusty Key", "Progressive Fishing Rod", "Progressive Pickaxe", "Fishing Level"] +seasons = ["Spring", "Summer", "Fall", "Winter"] + + +def setup_early_items(multiworld, options: StardewValleyOptions, player: int, random: Random): + early_forced = [] + early_candidates = [] + early_candidates.extend(always_early_candidates) + + add_seasonal_candidates(early_candidates, options) + + if options.building_progression & BuildingProgression.option_progressive: + early_forced.append("Shipping Bin") + early_candidates.append("Progressive Coop") + early_candidates.append("Progressive Barn") + + if options.backpack_progression == BackpackProgression.option_early_progressive: + early_forced.append("Progressive Backpack") + + if options.quest_locations >= 0: + early_candidates.append("Magnifying Glass") + + if options.special_order_locations != SpecialOrderLocations.option_disabled: + early_candidates.append("Special Order Board") + + if options.monstersanity == Monstersanity.option_none: + early_candidates.append("Progressive Weapon") + else: + early_candidates.append("Progressive Sword") + + if options.exclude_ginger_island == ExcludeGingerIsland.option_false: + early_candidates.append("Island Obelisk") + + early_forced.extend(random.sample(early_candidates, len(early_candidates) // early_candidate_rate)) + + for item_name in early_forced: + if item_name in multiworld.early_items[player]: + continue + multiworld.early_items[player][item_name] = 1 + + +def add_seasonal_candidates(early_candidates, options): + if options.season_randomization == SeasonRandomization.option_progressive: + early_candidates.extend(["Progressive Season"] * 3) + return + if options.season_randomization == SeasonRandomization.option_disabled: + return + + early_candidates.extend(seasons) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 66757405e8cb..11b782a4916a 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -54,11 +54,11 @@ from ..strings.ap_names.community_upgrade_names import CommunityUpgrade from ..strings.artisan_good_names import ArtisanGood from ..strings.building_names import Building -from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting +from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting, WildSeeds from ..strings.crop_names import Fruit, Vegetable from ..strings.currency_names import Currency from ..strings.decoration_names import Decoration -from ..strings.fertilizer_names import Fertilizer +from ..strings.fertilizer_names import Fertilizer, SpeedGro, RetainingSoil from ..strings.festival_check_names import FestivalCheck from ..strings.fish_names import Fish, Trash, WaterItem, WaterChest from ..strings.flower_names import Flower @@ -239,9 +239,8 @@ def __init__(self, player: int, options: StardewValleyOptions): Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600), Beverage.triple_shot_espresso: self.has("Hot Java Ring"), Decoration.rotten_plant: self.has(Lighting.jack_o_lantern) & self.season.has(Season.winter), - Fertilizer.basic: (self.has(Material.sap) & self.skill.has_farming_level(1)) | (self.time.has_lived_months(1) & self.money.can_spend_at(Region.pierre_store, 100)), - Fertilizer.deluxe: False_(), - Fertilizer.quality: (self.skill.has_farming_level(9) & self.has(Material.sap) & self.has(Fish.any)) | (self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150)), + Fertilizer.basic: self.money.can_spend_at(Region.pierre_store, 100), + Fertilizer.quality: self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150), Fertilizer.tree: self.skill.has_level(Skill.foraging, 7) & self.has(Material.fiber) & self.has(Material.stone), Fish.any: Or(*(self.fishing.can_catch_fish(fish) for fish in get_fish_for_mods(self.options.mods.value))), Fish.crab: self.skill.can_crab_pot_at(Region.beach), @@ -366,8 +365,12 @@ def __init__(self, player: int, options: StardewValleyOptions): Ore.iridium: self.mine.can_mine_in_the_skull_cavern(), Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), + RetainingSoil.basic: self.money.can_spend_at(Region.pierre_store, 100), + RetainingSoil.quality: self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150), Sapling.tea: self.relationship.has_hearts(NPC.caroline, 2) & self.has(Material.fiber) & self.has(Material.wood), Seed.mixed: self.tool.has_tool(Tool.scythe) & self.region.can_reach_all((Region.farm, Region.forest, Region.town)), + SpeedGro.basic: self.money.can_spend_at(Region.pierre_store, 100), + SpeedGro.deluxe: self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150), Trash.broken_cd: self.skill.can_crab_pot, Trash.broken_glasses: self.skill.can_crab_pot, Trash.driftwood: self.skill.can_crab_pot, @@ -388,6 +391,7 @@ def __init__(self, player: int, options: StardewValleyOptions): WaterItem.sea_urchin: self.tool.can_forage(Generic.any, Region.tide_pools), WaterItem.seaweed: self.skill.can_fish(Region.beach) | self.region.can_reach(Region.tide_pools), WaterItem.white_algae: self.skill.can_fish(Region.mines_floor_20), + WildSeeds.grass_starter: self.money.can_spend_at(Region.pierre_store, 100), }) # @formatter:on self.registry.item_rules.update(self.registry.fish_rules) diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index c4af8a95313b..29129f6cee55 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -28,14 +28,20 @@ def can_donate_museum_artifacts(self, number: int) -> StardewRule: @cache_self1 def can_find_museum_item(self, item: MuseumItem) -> StardewRule: - region_rule = self.logic.region.can_reach_all_except_one(item.locations) - geodes_rule = And(*(self.logic.action.can_open_geode(geode) for geode in item.geodes)) if item.geodes else true_ + if item.locations: + region_rule = self.logic.region.can_reach_all_except_one(item.locations) + else: + region_rule = False_() + if item.geodes: + geodes_rule = And(*(self.logic.action.can_open_geode(geode) for geode in item.geodes)) + else: + geodes_rule = False_() # monster_rule = self.can_farm_monster(item.monsters) # extra_rule = True_() pan_rule = False_() if item.item_name == "Earth Crystal" or item.item_name == "Fire Quartz" or item.item_name == "Frozen Tear": pan_rule = self.logic.action.can_pan() - return pan_rule | (region_rule & geodes_rule) # & monster_rule & extra_rule + return pan_rule | region_rule | geodes_rule # & monster_rule & extra_rule def can_find_museum_artifacts(self, number: int) -> StardewRule: rules = [] diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index a1c2134776fd..54756a94800c 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -7,7 +7,7 @@ from ..stardew_rule import StardewRule, HasProgressionPercent, True_ MAX_MONTHS = 12 -MONTH_COEFFICIENT = 100 // MAX_MONTHS +MONTH_COEFFICIENT = 50 // MAX_MONTHS class TimeLogicMixin(BaseLogicMixin): diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index 4be398b962d5..a28f78a717c5 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -13,9 +13,10 @@ from ...logic.season_logic import SeasonLogicMixin from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin -from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes +from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes, SVEQuestItem from ...strings.quest_names import ModQuest from ...stardew_rule import Or +from ...strings.quest_names import ModQuest class SVELogicMixin(BaseLogicMixin): @@ -25,7 +26,7 @@ def __init__(self, *args, **kwargs): class SVELogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, QuestLogicMixin, RegionLogicMixin, RelationshipLogicMixin, TimeLogicMixin, ToolLogicMixin, - CookingLogicMixin, MoneyLogicMixin, CombatLogicMixin, SeasonLogicMixin]]): + CookingLogicMixin, MoneyLogicMixin, CombatLogicMixin, SeasonLogicMixin, QuestLogicMixin]]): def initialize_rules(self): self.registry.sve_location_rules.update({ SVELocation.tempered_galaxy_sword: self.logic.money.can_spend_at(SVERegion.alesia_shop, 350000), @@ -36,3 +37,8 @@ def initialize_rules(self): def has_any_rune(self): rune_list = SVERunes.nexus_items return Or(*(self.logic.received(rune) for rune in rune_list)) + + def has_iridium_bomb(self): + if self.options.quest_locations < 0: + return self.logic.quest.can_complete_quest(ModQuest.RailroadBoulder) + return self.logic.received(SVEQuestItem.iridium_bomb) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 22024c3837cc..dda5e4111957 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -19,6 +19,7 @@ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And from .strings.ap_names.event_names import Event +from .strings.ap_names.mods.mod_items import SVEQuestItem from .strings.ap_names.transport_names import Transportation from .strings.ap_names.mods.mod_items import SVELocation from .strings.artisan_good_names import ArtisanGood @@ -894,7 +895,7 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_to_lost_woods, player), logic.bundle.can_complete_community_center) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), - logic.received("Iridium Bomb")) + logic.mod.sve.has_iridium_bomb()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), logic.mod.sve.has_any_rune()) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.badlands_to_cave, player), From 994dd18207f15eb9e7675ba70278051780268169 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 8 Dec 2023 19:57:40 -0500 Subject: [PATCH 338/482] - Update to early items --- worlds/stardew_valley/early_items.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/early_items.py b/worlds/stardew_valley/early_items.py index d7ec48d0f97f..c046e0ddc727 100644 --- a/worlds/stardew_valley/early_items.py +++ b/worlds/stardew_valley/early_items.py @@ -1,10 +1,10 @@ from random import Random from .options import BuildingProgression, StardewValleyOptions, BackpackProgression, ExcludeGingerIsland, SeasonRandomization, SpecialOrderLocations, \ - Monstersanity + Monstersanity, ToolProgression, SkillProgression -early_candidate_rate = 4 -always_early_candidates = ["Greenhouse", "Desert Obelisk", "Rusty Key", "Progressive Fishing Rod", "Progressive Pickaxe", "Fishing Level"] +early_candidate_rate = 2 +always_early_candidates = ["Greenhouse", "Desert Obelisk", "Rusty Key"] seasons = ["Spring", "Summer", "Fall", "Winter"] @@ -23,6 +23,13 @@ def setup_early_items(multiworld, options: StardewValleyOptions, player: int, ra if options.backpack_progression == BackpackProgression.option_early_progressive: early_forced.append("Progressive Backpack") + if options.tool_progression & ToolProgression.option_progressive: + early_forced.append("Progressive Fishing Rod") + early_forced.append("Progressive Pickaxe") + + if options.skill_progression == SkillProgression.option_progressive: + early_forced.append("Fishing Level") + if options.quest_locations >= 0: early_candidates.append("Magnifying Glass") From 43eac8c959a7f85bf499550fd147fc90a2964fa5 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 9 Dec 2023 11:12:12 -0500 Subject: [PATCH 339/482] - Fixes and improvements to money logic - renamed highlands outside --- worlds/stardew_valley/data/fish_data.py | 2 +- worlds/stardew_valley/data/villagers_data.py | 2 +- worlds/stardew_valley/logic/money_logic.py | 25 ++++++++++++++++--- .../logic/relationship_logic.py | 4 ++- .../stardew_valley/mods/logic/item_logic.py | 8 +++--- worlds/stardew_valley/mods/mod_regions.py | 6 ++--- worlds/stardew_valley/strings/region_names.py | 2 +- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 06cc7cdcb235..73238f9e9eb1 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -45,7 +45,7 @@ def __repr__(self): crimson_badlands = (SVERegion.crimson_badlands,) shearwater = (SVERegion.shearwater,) -highlands = (SVERegion.highlands,) +highlands = (SVERegion.highlands_outside,) sprite_spring = (SVERegion.sprite_spring,) fable_reef = (SVERegion.fable_reef,) vineyard = (SVERegion.blue_moon_vineyard,) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index bd83f05832dd..40959c51a032 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -45,7 +45,7 @@ def __repr__(self): # Stardew Valley Expanded Locations adventurer = (Region.adventurer_guild,) -highlands = (SVERegion.highlands,) +highlands = (SVERegion.highlands_outside,) bluemoon = (SVERegion.blue_moon_vineyard,) aurora = (SVERegion.aurora_vineyard,) museum = (Region.museum,) diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index a601aa867515..cf77ca5c0e67 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -10,6 +10,7 @@ from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, HasProgressionPercent, False_ from ..strings.currency_names import Currency +from ..strings.machine_names import Machine from ..strings.region_names import Region from ..strings.ap_names.event_names import Event @@ -27,14 +28,32 @@ class MoneyLogic(BaseLogic[Union[RegionLogicMixin, MoneyLogicMixin, TimeLogicMix @cache_self1 def can_have_earned_total(self, amount: int) -> StardewRule: - if amount < 2000: + if amount < 1000: return True_() + + pierre_rule = self.logic.region.can_reach_all((Region.pierre_store, Region.forest)) + willy_rule = self.logic.region.can_reach_all((Region.fish_shop, Region.fishing)) + clint_rule = self.logic.region.can_reach_all((Region.blacksmith, Region.mines_floor_5)) + robin_rule = self.logic.region.can_reach_all((Region.carpenter, Region.secret_woods)) shipping_rule = self.logic.received(Event.can_ship_items) + + if amount < 2000: + selling_any_rule = pierre_rule | willy_rule | clint_rule | robin_rule | shipping_rule + return selling_any_rule + + if amount < 5000: + selling_all_rule = (pierre_rule & willy_rule & clint_rule & robin_rule) | shipping_rule + return selling_all_rule + if amount < 10000: return shipping_rule - percent_progression_items_needed = min(100, amount // 10000) - return shipping_rule & HasProgressionPercent(self.player, percent_progression_items_needed) + seed_rules = self.logic.region.can_reach_any((Region.pierre_store, Region.oasis)) + if amount < 40000: + return shipping_rule & seed_rules + + percent_progression_items_needed = min(90, amount // 20000) + return shipping_rule & seed_rules & HasProgressionPercent(self.player, percent_progression_items_needed) @cache_self1 def can_spend(self, amount: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 81ca32d627e6..7f71921e5c7a 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -101,7 +101,9 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: # Should be cached def received_hearts(self, npc: str, hearts: int) -> StardewRule: - return self.logic.received(self.heart(npc), math.ceil(hearts / self.options.friendsanity_heart_size)) + heart_item = self.heart(npc) + number_required = math.ceil(hearts / self.options.friendsanity_heart_size) + return self.logic.received(heart_item, number_required) @cache_self1 def can_meet(self, npc: str) -> StardewRule: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index fb1ffa1c0afc..44dc9392773b 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -59,14 +59,14 @@ def get_sve_item_rules(self): return {SVEGift.aged_blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 28000), SVEGift.blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 3000), SVESeed.fungus_seed: self.logic.region.can_reach(SVERegion.highlands_cavern) & self.logic.combat.has_good_weapon, - ModLoot.green_mushroom: self.logic.region.can_reach(SVERegion.highlands) & self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron), + ModLoot.green_mushroom: self.logic.region.can_reach(SVERegion.highlands_outside) & self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron), SVEFruit.monster_fruit: self.logic.season.has(Season.summer) & self.logic.has(SVESeed.stalk_seed), SVEVegetable.monster_mushroom: self.logic.season.has(Season.fall) & self.logic.has(SVESeed.fungus_seed), - SVEForage.ornate_treasure_chest: self.logic.region.can_reach(SVERegion.highlands) & self.logic.combat.has_galaxy_weapon & + SVEForage.ornate_treasure_chest: self.logic.region.can_reach(SVERegion.highlands_outside) & self.logic.combat.has_galaxy_weapon & self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron), SVEFruit.slime_berry: self.logic.season.has(Season.spring) & self.logic.has(SVESeed.slime_seed), - SVESeed.slime_seed: self.logic.region.can_reach(SVERegion.highlands) & self.logic.combat.has_good_weapon, - SVESeed.stalk_seed: self.logic.region.can_reach(SVERegion.highlands) & self.logic.combat.has_good_weapon, + SVESeed.slime_seed: self.logic.region.can_reach(SVERegion.highlands_outside) & self.logic.combat.has_good_weapon, + SVESeed.stalk_seed: self.logic.region.can_reach(SVERegion.highlands_outside) & self.logic.combat.has_good_weapon, SVEForage.swirl_stone: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_great_weapon, SVEVegetable.void_root: self.logic.season.has(Season.winter) & self.logic.has(SVESeed.void_seed), SVESeed.void_seed: self.logic.region.can_reach(SVERegion.highlands_cavern) & self.logic.combat.has_good_weapon, diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index c84b55dc85fd..5b74641e839d 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -177,7 +177,7 @@ RegionData(SVERegion.first_slash_guild, [SVEEntrance.first_slash_guild_to_hallway]), RegionData(SVERegion.first_slash_hallway, [SVEEntrance.first_slash_hallway_to_room]), RegionData(SVERegion.first_slash_spare_room), - RegionData(SVERegion.highlands, [SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave]), + RegionData(SVERegion.highlands_outside, [SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave]), RegionData(SVERegion.highlands_cavern, [SVEEntrance.to_dwarf_prison]), RegionData(SVERegion.dwarf_prison), RegionData(SVERegion.lances_house, [SVEEntrance.lance_to_ladder]), @@ -216,7 +216,7 @@ ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands), + ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside), ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp), @@ -255,7 +255,7 @@ ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder), - ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 52c07975fc1e..213fef3a3818 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -241,7 +241,7 @@ class SVERegion: guild_summit = "Guild Summit" fable_reef = "Fable Reef" first_slash_guild = "First Slash Guild" - highlands = "Highlands Outside" + highlands_outside = "Highlands Outside" highlands_cavern = "Highlands Cavern" dwarf_prison = "Highlands Cavern Prison" lances_house = "Lance's House Main" From 822926e17ebae394a9202791d883d53401eae514 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 9 Dec 2023 11:58:35 -0500 Subject: [PATCH 340/482] - Add warp totem desert recipe --- worlds/stardew_valley/data/locations.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a17db08c1573..225838fcf350 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2079,6 +2079,7 @@ id,region,name,tags,mod_name 3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, 3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, 3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, +3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill From ec5bee7b6a79109040c9eef8f275e0d020bd884d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 00:46:42 -0500 Subject: [PATCH 341/482] - Added rule that Albrekka told me to add --- worlds/stardew_valley/rules.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index dda5e4111957..184f72948bf2 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -927,6 +927,8 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.railroad_to_grampleton_station, player), + logic.received(SVEQuestItem.scarlett_job_offer)) logic.mod.sve.initialize_rules() for location in logic.registry.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), From 1366cfdf854c0686252bbaf6621a9ea2b93d8afe Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 11:21:20 -0500 Subject: [PATCH 342/482] Surprise new traps! --- worlds/stardew_valley/data/items.csv | 42 +++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 89adee3ebb9b..a0fa0e0f6976 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -445,23 +445,31 @@ id,name,classification,groups,mod_name 467,Four Corners Farm,progression,FARM_TYPE, 468,Beach Farm,progression,FARM_TYPE, 469,Railroad Boulder Removed,progression,, -4001,Burnt,trap,TRAP, -4002,Darkness,trap,TRAP, -4003,Frozen,trap,TRAP, -4004,Jinxed,trap,TRAP, -4005,Nauseated,trap,TRAP, -4006,Slimed,trap,TRAP, -4007,Weakness,trap,TRAP, -4008,Taxes,trap,TRAP, -4009,Random Teleport,trap,TRAP, -4010,The Crows,trap,TRAP, -4011,Monsters,trap,TRAP, -4012,Entrance Reshuffle,trap,"TRAP,DEPRECATED", -4013,Debris,trap,TRAP, -4014,Shuffle,trap,TRAP, -4015,Temporary Winter,trap,"TRAP,DEPRECATED", -4016,Pariah,trap,TRAP, -4017,Drought,trap,TRAP, +4001,Burnt Trap,trap,TRAP, +4002,Darkness Trap,trap,TRAP, +4003,Frozen Trap,trap,TRAP, +4004,Jinxed Trap,trap,TRAP, +4005,Nauseated Trap,trap,TRAP, +4006,Slimed Trap,trap,TRAP, +4007,Weakness Trap,trap,TRAP, +4008,Taxes Trap,trap,TRAP, +4009,Random Teleport Trap,trap,TRAP, +4010,The Crows Trap,trap,TRAP, +4011,Monsters Trap,trap,TRAP, +4012,Entrance Reshuffle Trap,trap,"TRAP,DEPRECATED", +4013,Debris Trap,trap,TRAP, +4014,Shuffle Trap,trap,TRAP, +4015,Temporary Winter Trap,trap,"TRAP,DEPRECATED", +4016,Pariah Trap,trap,TRAP, +4017,Drought Trap,trap,TRAP, +4018,Time Flies Trap,trap,TRAP, +4019,Babies Trap,trap,TRAP, +4020,Meow Trap,trap,TRAP, +4020,Bark Trap,trap,TRAP, +4021,Depression Trap,trap,"TRAP,DEPRECATED", +4022,Benjamin Budton Trap,trap,TRAP, +4023,Inflation Trap,trap,TRAP, +4024,Bomb Trap,trap,TRAP, 5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", 5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", 5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", From 4535c555dc7b1eacaf180828634072f11df2cd78 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 11:32:26 -0500 Subject: [PATCH 343/482] - fixed ids --- worlds/stardew_valley/data/items.csv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index a0fa0e0f6976..6c8c466663dd 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -465,11 +465,11 @@ id,name,classification,groups,mod_name 4018,Time Flies Trap,trap,TRAP, 4019,Babies Trap,trap,TRAP, 4020,Meow Trap,trap,TRAP, -4020,Bark Trap,trap,TRAP, -4021,Depression Trap,trap,"TRAP,DEPRECATED", -4022,Benjamin Budton Trap,trap,TRAP, -4023,Inflation Trap,trap,TRAP, -4024,Bomb Trap,trap,TRAP, +4021,Bark Trap,trap,TRAP, +4022,Depression Trap,trap,"TRAP,DEPRECATED", +4023,Benjamin Budton Trap,trap,TRAP, +4024,Inflation Trap,trap,TRAP, +4025,Bomb Trap,trap,TRAP, 5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", 5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", 5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", From 284b21aba85b63e77155067ba0bad3c7f91f7050 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 12:15:11 -0500 Subject: [PATCH 344/482] - Add the farm caves as items --- worlds/stardew_valley/data/items.csv | 2 ++ worlds/stardew_valley/data/locations.csv | 1 + worlds/stardew_valley/items.py | 5 +++- worlds/stardew_valley/logic/logic.py | 24 ++++++++++++------- worlds/stardew_valley/rules.py | 2 ++ .../ap_names/community_upgrade_names.py | 2 ++ 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 6c8c466663dd..443e0a054182 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -445,6 +445,8 @@ id,name,classification,groups,mod_name 467,Four Corners Farm,progression,FARM_TYPE, 468,Beach Farm,progression,FARM_TYPE, 469,Railroad Boulder Removed,progression,, +470,Fruit Bats,progression,, +471,Mushroom Boxes,progression,, 4001,Burnt Trap,trap,TRAP, 4002,Darkness Trap,trap,TRAP, 4003,Frozen Trap,trap,TRAP, diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 225838fcf350..e9fba08e9902 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -156,6 +156,7 @@ id,region,name,tags,mod_name 235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, 236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, 237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, +250,Shipping,Demetrius's Breakthrough,MANDATORY 251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", 301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", 302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 16fd875c66d0..d8d7b4c4f5f6 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -16,6 +16,7 @@ Shipsanity, Chefsanity, Craftsanity, BundleRandomization, BundlePrice from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff +from .strings.ap_names.community_upgrade_names import CommunityUpgrade from .strings.ap_names.event_names import Event from .strings.ap_names.mods.mod_items import SVEQuestItem from .strings.villager_names import NPC, ModNPC @@ -209,7 +210,7 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items = [] items.extend(item_factory(item) for item in items_by_group[Group.COMMUNITY_REWARD]) - items.append(item_factory("Progressive Movie Theater")) # It is a community reward, but we need two of them + items.append(item_factory(CommunityUpgrade.movie_theater)) # It is a community reward, but we need two of them create_backpack_items(item_factory, options, items) create_weapons(item_factory, options, items) @@ -220,6 +221,8 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley create_wizard_buildings(item_factory, options, items) create_carpenter_buildings(item_factory, options, items) items.append(item_factory("Railroad Boulder Removed")) + items.append(item_factory(CommunityUpgrade.fruit_bats)) + items.append(item_factory(CommunityUpgrade.mushroom_boxes)) items.append(item_factory("Beach Bridge")) items.append(item_factory("Dark Talisman")) create_tv_channels(item_factory, items) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 11b782a4916a..1fdfef519349 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -254,12 +254,12 @@ def __init__(self, player: int, options: StardewValleyOptions): Fish.snail: self.skill.can_crab_pot_at(Region.town), Fishing.curiosity_lure: self.monster.can_kill(all_monsters_by_name[Monster.mummy]), Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200), - Forageable.blackberry: self.tool.can_forage(Season.fall), + Forageable.blackberry: self.tool.can_forage(Season.fall) | self.has_fruit_bats(), Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), Forageable.cave_carrot: self.tool.can_forage(Generic.any, Region.mines_floor_10, True), - Forageable.chanterelle: self.tool.can_forage(Season.fall, Region.secret_woods), + Forageable.chanterelle: self.tool.can_forage(Season.fall, Region.secret_woods) | self.has_mushroom_cave(), Forageable.coconut: self.tool.can_forage(Generic.any, Region.desert), - Forageable.common_mushroom: self.tool.can_forage(Season.fall) | (self.tool.can_forage(Season.spring, Region.secret_woods)), + Forageable.common_mushroom: self.tool.can_forage(Season.fall) | (self.tool.can_forage(Season.spring, Region.secret_woods)) | self.has_mushroom_cave(), Forageable.crocus: self.tool.can_forage(Season.winter), Forageable.crystal_fruit: self.tool.can_forage(Season.winter), Forageable.daffodil: self.tool.can_forage(Season.spring), @@ -273,18 +273,18 @@ def __init__(self, player: int, options: StardewValleyOptions): Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & self.quest.has_magnifying_glass() & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), Forageable.leek: self.tool.can_forage(Season.spring), Forageable.magma_cap: self.tool.can_forage(Generic.any, Region.volcano_floor_5), - Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods), - Forageable.purple_mushroom: self.tool.can_forage(Generic.any, Region.mines_floor_95) | self.tool.can_forage(Generic.any, Region.skull_cavern_25), + Forageable.morel: self.tool.can_forage(Season.spring, Region.secret_woods) | self.has_mushroom_cave(), + Forageable.purple_mushroom: self.tool.can_forage(Generic.any, Region.mines_floor_95) | self.tool.can_forage(Generic.any, Region.skull_cavern_25) | self.has_mushroom_cave(), Forageable.rainbow_shell: self.tool.can_forage(Season.summer, Region.beach), - Forageable.red_mushroom: self.tool.can_forage(Season.summer, Region.secret_woods) | self.tool.can_forage(Season.fall, Region.secret_woods), - Forageable.salmonberry: self.tool.can_forage(Season.spring), + Forageable.red_mushroom: self.tool.can_forage(Season.summer, Region.secret_woods) | self.tool.can_forage(Season.fall, Region.secret_woods) | self.has_mushroom_cave(), + Forageable.salmonberry: self.tool.can_forage(Season.spring) | self.has_fruit_bats(), Forageable.secret_note: self.quest.has_magnifying_glass() & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), Forageable.snow_yam: self.tool.can_forage(Season.winter, Region.beach, True), - Forageable.spice_berry: self.tool.can_forage(Season.summer), + Forageable.spice_berry: self.tool.can_forage(Season.summer) | self.has_fruit_bats(), Forageable.spring_onion: self.tool.can_forage(Season.spring), Forageable.sweet_pea: self.tool.can_forage(Season.summer), Forageable.wild_horseradish: self.tool.can_forage(Season.spring), - Forageable.wild_plum: self.tool.can_forage(Season.fall), + Forageable.wild_plum: self.tool.can_forage(Season.fall) | self.has_fruit_bats(), Forageable.winter_root: self.tool.can_forage(Season.winter, Region.forest, True), Fossil.bone_fragment: (self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe)) | self.monster.can_kill(Monster.skeleton), Fossil.fossilized_leg: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe), @@ -734,3 +734,9 @@ def has_movie_theater(self) -> StardewRule: def can_use_obelisk(self, obelisk: str) -> StardewRule: return self.region.can_reach(Region.farm) & self.received(obelisk) + + def has_fruit_bats(self) -> StardewRule: + return self.region.can_reach(Region.farm_cave) & self.received(CommunityUpgrade.fruit_bats) + + def has_mushroom_cave(self) -> StardewRule: + return self.region.can_reach(Region.farm_cave) & self.received(CommunityUpgrade.mushroom_boxes) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 184f72948bf2..6fd85735dbe0 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -90,6 +90,8 @@ def set_isolated_locations_rules(logic: StardewLogic, multiworld, player): logic.has("Prismatic Shard")) MultiWorldRules.add_rule(multiworld.get_location("Krobus Stardrop", player), logic.money.can_spend(20000)) + MultiWorldRules.add_rule(multiworld.get_location("Demetrius's Breakthrough", player), + logic.money.can_have_earned_total(25000)) def set_tool_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): diff --git a/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py b/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py index 0be4d31b5384..68dad8e75287 100644 --- a/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py +++ b/worlds/stardew_valley/strings/ap_names/community_upgrade_names.py @@ -1,2 +1,4 @@ class CommunityUpgrade: + fruit_bats = "Fruit Bats" + mushroom_boxes = "Mushroom Boxes" movie_theater = "Progressive Movie Theater" From d2dbda13095037853febc50a18faa6bc90e70143 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 17:00:55 -0500 Subject: [PATCH 345/482] - Slight changes to brewer and bartender bundle --- worlds/stardew_valley/data/bundle_data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index a7957e2081ee..3dea4e141046 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -457,7 +457,7 @@ garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose] garden_bundle = BundleTemplate(CCRoom.pantry, BundleName.garden, garden_items, 5, 4) -brewer_items = [mead, pale_ale, wine, juice, green_tea] +brewer_items = [mead, pale_ale, wine, juice, green_tea, beer] brewer_bundle = BundleTemplate(CCRoom.pantry, BundleName.brewer, brewer_items, 5, 4) orchard_items = [apple, apricot, orange, peach, pomegranate, cherry, banana, mango] @@ -651,7 +651,7 @@ chocolate_cake, pancakes, rhubarb_pie] home_cook_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.home_cook, home_cook_items, 3, 3) -bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, green_tea, cranberry_candy] +bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, cranberry_candy, beer, pale_ale] bartender_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.bartender, bartender_items, 3, 3) bulletin_board_bundles_vanilla = [chef_bundle_vanilla, dye_bundle_vanilla, field_research_bundle_vanilla, fodder_bundle_vanilla, enchanter_bundle_vanilla] From 08aeb0e21995d05e4bef9d1a3a22424c28bcf321 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 17:12:47 -0500 Subject: [PATCH 346/482] - Made the dark talisman into a quest-only item --- worlds/stardew_valley/early_items.py | 2 +- worlds/stardew_valley/items.py | 2 +- worlds/stardew_valley/logic/quest_logic.py | 5 +++++ worlds/stardew_valley/rules.py | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/early_items.py b/worlds/stardew_valley/early_items.py index c046e0ddc727..d6d493bc90f2 100644 --- a/worlds/stardew_valley/early_items.py +++ b/worlds/stardew_valley/early_items.py @@ -3,7 +3,7 @@ from .options import BuildingProgression, StardewValleyOptions, BackpackProgression, ExcludeGingerIsland, SeasonRandomization, SpecialOrderLocations, \ Monstersanity, ToolProgression, SkillProgression -early_candidate_rate = 2 +early_candidate_rate = 4 always_early_candidates = ["Greenhouse", "Desert Obelisk", "Rusty Key"] seasons = ["Spring", "Summer", "Fall", "Winter"] diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index d8d7b4c4f5f6..8203b45e1dd1 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -224,7 +224,6 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley items.append(item_factory(CommunityUpgrade.fruit_bats)) items.append(item_factory(CommunityUpgrade.mushroom_boxes)) items.append(item_factory("Beach Bridge")) - items.append(item_factory("Dark Talisman")) create_tv_channels(item_factory, items) create_special_quest_rewards(item_factory, options, items) create_stardrops(item_factory, options, items) @@ -359,6 +358,7 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, options: Star items.append(item_factory(Wallet.bears_knowledge)) items.append(item_factory(Wallet.iridium_snake_milk)) items.append(item_factory("Fairy Dust Recipe")) + items.append(item_factory("Dark Talisman")) if ModNames.sve in options.mods: create_special_quest_rewards_sve(item_factory, options, items) diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index cdc02700b6fa..4b35d59872a8 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -121,3 +121,8 @@ def has_magnifying_glass(self) -> StardewRule: if self.options.quest_locations < 0: return self.logic.quest.can_complete_quest(Quest.a_winter_mystery) return self.logic.received(Wallet.magnifying_glass) + + def has_dark_talisman(self) -> StardewRule: + if self.options.quest_locations < 0: + return self.logic.quest.can_complete_quest(Quest.dark_talisman) + return self.logic.received(Wallet.dark_talisman) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 6fd85735dbe0..73240c2bbd08 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -232,7 +232,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), logic.received("Railroad Boulder Removed")) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), - logic.received(Wallet.dark_talisman) | (logic.mod.magic.can_blink())) + logic.quest.has_dark_talisman() | (logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink())) MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), From 8525e2644b801fe03f620b620bb04500602b7451 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 18:03:26 -0500 Subject: [PATCH 347/482] - New bundle but unfinished --- worlds/stardew_valley/data/bundle_data.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 3dea4e141046..0c1c45891f72 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -593,6 +593,9 @@ demolition_items = [cherry_bomb, bomb, mega_bomb, explosive_ammo] demolition_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.demolition, demolition_items, 3, 3) +# recycling_items = [stone, coal, iron_ore, wood, torch, cloth, refined_quartz] +# recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4) + boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla] boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic] boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle, demolition_bundle] From ed2f307f05b1f2a9ff6f93dfbfd237552ac7ab03 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 10 Dec 2023 18:27:20 -0500 Subject: [PATCH 348/482] fix 4.x.x performances configs --- worlds/stardew_valley/test/__init__.py | 2 +- worlds/stardew_valley/test/performance/TestPerformance.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 61fbb385d1d1..80e563121ae3 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -135,7 +135,7 @@ def allsanity_4_x_x_options_without_mods(): ElevatorProgression.internal_name: ElevatorProgression.option_progressive, ArcadeMachineLocations.internal_name: ArcadeMachineLocations.option_full_shuffling, SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, - HelpWantedLocations.internal_name: 56, + QuestLocations.internal_name: 56, Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, Monstersanity.internal_name: Monstersanity.option_progressive_goals, diff --git a/worlds/stardew_valley/test/performance/TestPerformance.py b/worlds/stardew_valley/test/performance/TestPerformance.py index e3d823386702..e83134033da2 100644 --- a/worlds/stardew_valley/test/performance/TestPerformance.py +++ b/worlds/stardew_valley/test/performance/TestPerformance.py @@ -7,7 +7,13 @@ from BaseClasses import get_seed from Fill import distribute_items_restrictive, balance_multiworld_progression from worlds import AutoWorld -from .. import SVTestCase, minimal_locations_maximal_items, setup_multiworld, allsanity_options_without_mods, default_options +from .. import SVTestCase, minimal_locations_maximal_items, setup_multiworld, default_4_x_x_options, \ + allsanity_4_x_x_options_without_mods, default_options, allsanity_options_without_mods + +assert default_4_x_x_options +assert allsanity_4_x_x_options_without_mods +assert default_options +assert allsanity_options_without_mods default_number_generations = 25 acceptable_deviation = 4 From c447585a1be86d15677f9ab0f6517c90888c2429 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 18:46:21 -0500 Subject: [PATCH 349/482] - Add alternative source of iridium in case entrance rando locks the skull cavern behind iridium --- worlds/stardew_valley/logic/logic.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 1fdfef519349..0f431ccbe0e0 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -362,7 +362,7 @@ def __init__(self, player: int, options: StardewValleyOptions): MetalBar.radioactive: self.can_smelt(Ore.radioactive), Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), - Ore.iridium: self.mine.can_mine_in_the_skull_cavern(), + Ore.iridium: self.mine.can_mine_in_the_skull_cavern() | self.can_fish_pond(Fish.super_cucumber), Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.action.can_pan(), Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room), RetainingSoil.basic: self.money.can_spend_at(Region.pierre_store, 100), @@ -740,3 +740,6 @@ def has_fruit_bats(self) -> StardewRule: def has_mushroom_cave(self) -> StardewRule: return self.region.can_reach(Region.farm_cave) & self.received(CommunityUpgrade.mushroom_boxes) + + def can_fish_pond(self, fish: str) -> StardewRule: + return self.building.has_building(Building.fish_pond) & self.has(fish) From 7d16e7cd7d54889a763c6d8253007f42839c1a61 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 18:59:21 -0500 Subject: [PATCH 350/482] - Improve odds on a rude test --- worlds/stardew_valley/test/TestItems.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index 540418df2cbc..b37b0bad7619 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -81,7 +81,7 @@ def test_can_start_in_any_season(self): def test_can_start_on_any_farm(self): starting_farms_rolled = set() - for attempt_number in range(50): + for attempt_number in range(60): if len(starting_farms_rolled) >= 7: print(f"Already got all 7 farm types, breaking early [{attempt_number} generations]") break From eb5e5188be0edde077edf560bc12d1554e4535ee Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 19:06:29 -0500 Subject: [PATCH 351/482] - Updated check counts --- worlds/stardew_valley/test/TestGeneration.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index cfde491336e1..5ebcfc2640f8 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -354,7 +354,7 @@ def test_minimal_location_maximal_items_with_island_still_valid(self): print(f"Stardew Valley - Minimum Locations: {number_locations}, Maximum Items: {number_items} [ISLAND INCLUDED]") def test_minsanity_has_fewer_than_locations(self): - expected_locations = 122 + expected_locations = 76 minsanity_options = get_minsanity_options() multiworld = setup_solo_multiworld(minsanity_options) real_locations = get_real_locations(self, multiworld) @@ -368,7 +368,7 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tActual: {number_locations}") def test_default_settings_has_exactly_locations(self): - expected_locations = 420 + expected_locations = 421 multiworld = setup_solo_multiworld(default_options()) real_locations = get_real_locations(self, multiworld) number_locations = len(real_locations) @@ -380,7 +380,7 @@ def test_default_settings_has_exactly_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1952 + expected_locations = 1954 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -394,7 +394,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2693 + expected_locations = 2695 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) From 7761ea152b0da80db878b3a3570cb471214d02c3 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 19:36:04 -0500 Subject: [PATCH 352/482] - Don't shuffle entrance to junimo woods --- worlds/stardew_valley/mods/mod_regions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 5b74641e839d..019d4e396c1f 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -246,7 +246,7 @@ ConnectionData(SVEEntrance.forest_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.secret_woods_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.forest_to_lost_woods, SVERegion.lost_woods, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_to_lost_woods, SVERegion.lost_woods), ConnectionData(SVEEntrance.lost_woods_to_junimo_woods, SVERegion.junimo_woods), ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.NON_PROGRESSION), From aaa00931921741ccdd4ee22330c672fed13527d4 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 19:42:01 -0500 Subject: [PATCH 353/482] - Fix mod regions entrance rando being wayyy too aggressive --- worlds/stardew_valley/mods/mod_regions.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 019d4e396c1f..363dbc37daf2 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -212,7 +212,7 @@ ConnectionData(SVEEntrance.town_to_bridge, SVERegion.shearwater), ConnectionData(SVEEntrance.plot_to_bridge, SVERegion.shearwater), ConnectionData(SVEEntrance.bus_stop_to_shed, SVERegion.grandpas_shed), - ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(SVEEntrance.grandpa_shed_to_interior, SVERegion.grandpas_shed_interior, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), @@ -236,10 +236,10 @@ ConnectionData(SVEEntrance.grove_to_spring_warp, SVERegion.grove_spring_warp), ConnectionData(SVEEntrance.spring_warp_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.guild_to_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.mountain_to_guild_summit, SVERegion.guild_summit), ConnectionData(SVEEntrance.summit_to_boat, SVERegion.marlon_boat), @@ -250,18 +250,18 @@ ConnectionData(SVEEntrance.lost_woods_to_junimo_woods, SVERegion.junimo_woods), ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder), - ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop), ConnectionData(SVEEntrance.use_isaac_shop, SVERegion.isaac_shop), - ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.railroad_to_grampleton_station, SVERegion.grampleton_station), ConnectionData(SVEEntrance.grampleton_station_to_grampleton_suburbs, SVERegion.grampleton_suburbs), ConnectionData(SVEEntrance.grampleton_suburbs_to_scarlett_house, SVERegion.scarlett_house, flag=RandomizationFlag.BUILDINGS), From fb36fc1fdbb0d0578393b56e9f8a9e8ab741855f Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 10 Dec 2023 20:23:44 -0500 Subject: [PATCH 354/482] remove frozendict --- worlds/stardew_valley/requirements.txt | 1 - worlds/stardew_valley/stardew_rule.py | 28 +++++++++----------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/worlds/stardew_valley/requirements.txt b/worlds/stardew_valley/requirements.txt index 6cebc566c00b..b0922176e43b 100644 --- a/worlds/stardew_valley/requirements.txt +++ b/worlds/stardew_valley/requirements.txt @@ -1,2 +1 @@ importlib_resources; python_version <= '3.8' -frozendict diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 2b1a2c0f76ac..4df643f3da2a 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -9,8 +9,6 @@ from threading import Lock from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional -from frozendict import frozendict - from BaseClasses import CollectionState, ItemClassification from .items import item_table @@ -154,9 +152,9 @@ def value(self): def is_same_rule(self, other: CombinableStardewRule): return self.combination_key == other.combination_key - def add_into(self, rules: frozendict[Hashable, CombinableStardewRule], + def add_into(self, rules: Dict[Hashable, CombinableStardewRule], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ - -> frozendict[Hashable, CombinableStardewRule]: + -> Dict[Hashable, CombinableStardewRule]: if self.combination_key not in rules: return rules | {self.combination_key: self} @@ -239,7 +237,7 @@ class AggregatingStardewRule(StardewRule, ABC): complement: LiteralStardewRule symbol: str - combinable_rules: frozendict[Hashable, CombinableStardewRule] + combinable_rules: Dict[Hashable, CombinableStardewRule] simplification_state: _SimplificationState _last_short_circuiting_rule: Optional[StardewRule] = None @@ -264,7 +262,7 @@ def current_rules(self): return RepeatableChain(self.combinable_rules.values(), self.simplification_state.simplified_rules, self.simplification_state.rules_to_simplify) @classmethod - def split_rules(cls, rules: Union[Iterable[StardewRule]]) -> Tuple[Tuple[StardewRule, ...], frozendict[Hashable, CombinableStardewRule]]: + def split_rules(cls, rules: Union[Iterable[StardewRule]]) -> Tuple[Tuple[StardewRule, ...], Dict[Hashable, CombinableStardewRule]]: other_rules = [] reduced_rules = {} for rule in rules: @@ -279,22 +277,16 @@ def split_rules(cls, rules: Union[Iterable[StardewRule]]) -> Tuple[Tuple[Stardew if type(rule) is cls: other_rules.extend(rule.simplification_state.original_simplifiable_rules) # noqa - reduced_rules = cls.merge_mutable(reduced_rules, rule.combinable_rules) # noqa + reduced_rules = cls.merge(reduced_rules, rule.combinable_rules) # noqa continue other_rules.append(rule) - return tuple(other_rules), frozendict(reduced_rules) + return tuple(other_rules), reduced_rules @classmethod - def merge(cls, left: frozendict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ - -> frozendict[Hashable, CombinableStardewRule]: - return frozendict(cls.merge_mutable(dict(left), right)) - - @classmethod - def merge_mutable(cls, left: Dict[Hashable, CombinableStardewRule], right: frozendict[Hashable, CombinableStardewRule]) \ - -> Dict[Hashable, CombinableStardewRule]: - reduced_rules = left + def merge(cls, left: Dict[Hashable, CombinableStardewRule], right: Dict[Hashable, CombinableStardewRule]) -> Dict[Hashable, CombinableStardewRule]: + reduced_rules = dict(left) for key, rule in right.items(): if key not in reduced_rules: reduced_rules[key] = rule @@ -311,7 +303,7 @@ def combine(left: CombinableStardewRule, right: CombinableStardewRule) -> Combin def short_circuit_simplification(self): self.simplification_state.short_circuit(self.complement) - self.combinable_rules = frozendict() + self.combinable_rules = {} return self.complement, self.complement.value def short_circuit_evaluation(self, rule): @@ -409,7 +401,7 @@ def __eq__(self, other): self.simplification_state.original_simplifiable_rules == self.simplification_state.original_simplifiable_rules) def __hash__(self): - return hash((self.combinable_rules, self.simplification_state.original_simplifiable_rules)) + return hash((id(self.combinable_rules), self.simplification_state.original_simplifiable_rules)) def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: return StardewRuleExplanation(self, state, expected, self.original_rules) From bd15db90a7819b1eef5422a1e063369fbc0625c4 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 20:52:48 -0500 Subject: [PATCH 355/482] - Improve the shipping bin rules to consider that you don't need to build it --- worlds/stardew_valley/logic/building_logic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 5faac888c70c..e88e6531c2b7 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -53,6 +53,12 @@ def update_rules(self, new_rules: Dict[str, StardewRule]): @cache_self1 def has_building(self, building: str) -> StardewRule: + # Shipping bin is special. The mod auto-builds it when received, no need to go to Robin. + if building is Building.shipping_bin: + if not self.options.building_progression & BuildingProgression.option_progressive: + return True_() + return self.logic.received(f"{building}") + carpenter_rule = self.logic.received(Event.can_construct_buildings) if not self.options.building_progression & BuildingProgression.option_progressive: return Has(building, self.registry.building_rules) & carpenter_rule From 2f2cc670e6975de3e71f9122109aab0365202d6b Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sun, 10 Dec 2023 21:16:15 -0500 Subject: [PATCH 356/482] fix 3.8 --- worlds/stardew_valley/stardew_rule.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule.py index 4df643f3da2a..fd5bd2e6b857 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule.py @@ -152,14 +152,16 @@ def value(self): def is_same_rule(self, other: CombinableStardewRule): return self.combination_key == other.combination_key - def add_into(self, rules: Dict[Hashable, CombinableStardewRule], - reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ + def add_into(self, rules: Dict[Hashable, CombinableStardewRule], reducer: Callable[[CombinableStardewRule, CombinableStardewRule], CombinableStardewRule]) \ -> Dict[Hashable, CombinableStardewRule]: - if self.combination_key not in rules: - return rules | {self.combination_key: self} + rules = dict(rules) - other = rules[self.combination_key] - return rules | {self.combination_key: reducer(self, other)} + if self.combination_key in rules: + rules[self.combination_key] = reducer(self, rules[self.combination_key]) + else: + rules[self.combination_key] = self + + return rules def __and__(self, other): if isinstance(other, CombinableStardewRule) and self.is_same_rule(other): From d1b89f33371d95c59ccb88634f00ab336c2e464c Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 10 Dec 2023 22:28:35 -0500 Subject: [PATCH 357/482] - Fixes --- worlds/stardew_valley/__init__.py | 7 ++- worlds/stardew_valley/data/locations.csv | 50 +++++++++---------- worlds/stardew_valley/early_items.py | 5 +- worlds/stardew_valley/logic/cooking_logic.py | 3 +- worlds/stardew_valley/logic/crafting_logic.py | 3 +- worlds/stardew_valley/logic/monster_logic.py | 6 ++- worlds/stardew_valley/logic/time_logic.py | 2 +- worlds/stardew_valley/mods/mod_regions.py | 2 +- worlds/stardew_valley/rules.py | 4 +- 9 files changed, 45 insertions(+), 37 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 54be52ceff2e..259c3fe61c63 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -158,9 +158,12 @@ def precollect_farm_type(self): chosen_farm_types = [] for item in self.multiworld.precollected_items[self.player]: if item.name in all_farm_type_names: - chosen_farm_types.append(item.name) - self.multiworld.precollected_items[self.player].remove(item) + chosen_farm_types.append(item) + for item in chosen_farm_types: + self.multiworld.precollected_items[self.player].remove(item) + + chosen_farm_types = [item.name for item in chosen_farm_types] if not chosen_farm_types: chosen_farm_types = all_farm_type_names diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index e9fba08e9902..ca6244f33b25 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -236,38 +236,38 @@ id,region,name,tags,mod_name 508,The Mines - Floor 5,Forging Ahead,"STORY_QUEST", 509,The Mines - Floor 10,Smelting,"STORY_QUEST", 510,The Mines - Floor 15,Initiation,"STORY_QUEST", -511,Forest,Robin's Lost Axe,"STORY_QUEST", -512,Sam's House,Jodi's Request,"STORY_QUEST", -513,Marnie's Ranch,"Mayor's ""Shorts""","STORY_QUEST", -514,Tunnel Entrance,Blackberry Basket,"STORY_QUEST", +511,Mountain,Robin's Lost Axe,"STORY_QUEST", +512,Town,Jodi's Request,"STORY_QUEST", +513,Town,"Mayor's ""Shorts""","STORY_QUEST", +514,Mountain,Blackberry Basket,"STORY_QUEST", 515,Marnie's Ranch,Marnie's Request,"STORY_QUEST", -516,Trailer,Pam Is Thirsty,"STORY_QUEST", +516,Town,Pam Is Thirsty,"STORY_QUEST", 517,Wizard Tower,A Dark Reagent,"STORY_QUEST", -518,Marnie's Ranch,Cow's Delight,"STORY_QUEST", +518,Forest,Cow's Delight,"STORY_QUEST", 519,Skull Cavern Entrance,The Skull Key,"STORY_QUEST", -520,Carpenter Shop,Crop Research,"STORY_QUEST", +520,Mountain,Crop Research,"STORY_QUEST", 521,Alex's House,Knee Therapy,"STORY_QUEST", -522,Carpenter Shop,Robin's Request,"STORY_QUEST", +522,Mountain,Robin's Request,"STORY_QUEST", 523,Skull Cavern Floor 25,Qi's Challenge,"STORY_QUEST", 524,Desert,The Mysterious Qi,"STORY_QUEST", -525,Pierre's General Store,Carving Pumpkins,"STORY_QUEST", +525,Town,Carving Pumpkins,"STORY_QUEST", 526,Town,A Winter Mystery,"STORY_QUEST", 527,Secret Woods,Strange Note,"STORY_QUEST", 528,Skull Cavern Floor 100,Cryptic Note,"STORY_QUEST", -529,Haley's House,Fresh Fruit,"STORY_QUEST", -530,Carpenter Shop,Aquatic Research,"STORY_QUEST", -531,Sam's House,A Soldier's Star,"STORY_QUEST", -532,Mayor's Manor,Mayor's Need,"STORY_QUEST", +529,Town,Fresh Fruit,"STORY_QUEST", +530,Mountain,Aquatic Research,"STORY_QUEST", +531,Town,A Soldier's Star,"STORY_QUEST", +532,Town,Mayor's Need,"STORY_QUEST", 533,Saloon,Wanted: Lobster,"STORY_QUEST", -534,Trailer,Pam Needs Juice,"STORY_QUEST", +534,Town,Pam Needs Juice,"STORY_QUEST", 535,Sam's House,Fish Casserole,"STORY_QUEST", -536,Fishing,Catch A Squid,"STORY_QUEST", +536,Beach,Catch A Squid,"STORY_QUEST", 537,Saloon,Fish Stew,"STORY_QUEST", 538,Pierre's General Store,Pierre's Notice,"STORY_QUEST", 539,Clint's Blacksmith,Clint's Attempt,"STORY_QUEST", -540,Haley's House,A Favor For Clint,"STORY_QUEST", +540,Town,A Favor For Clint,"STORY_QUEST", 541,Wizard Tower,Staff Of Power,"STORY_QUEST", -542,Alex's House,Granny's Gift,"STORY_QUEST", +542,Town,Granny's Gift,"STORY_QUEST", 543,Desert,Exotic Spirits,"STORY_QUEST", 544,Fishing,Catch a Lingcod,"STORY_QUEST", 545,Island West,The Pirate's Wife,"GINGER_ISLAND,STORY_QUEST", @@ -302,14 +302,14 @@ id,region,name,tags,mod_name 705,Farmhouse,Have Another Baby,BABY, 706,Farmhouse,Spouse Stardrop,, 707,Sewer,Krobus Stardrop,MANDATORY, -801,The Mines - Floor 5,Help Wanted: Gathering 1,HELP_WANTED, -802,The Mines - Floor 10,Help Wanted: Gathering 2,HELP_WANTED, -803,The Mines - Floor 15,Help Wanted: Gathering 3,HELP_WANTED, -804,The Mines - Floor 20,Help Wanted: Gathering 4,HELP_WANTED, -805,The Mines - Floor 25,Help Wanted: Gathering 5,HELP_WANTED, -806,The Mines - Floor 30,Help Wanted: Gathering 6,HELP_WANTED, -807,The Mines - Floor 35,Help Wanted: Gathering 7,HELP_WANTED, -808,The Mines - Floor 40,Help Wanted: Gathering 8,HELP_WANTED, +801,Forest,Help Wanted: Gathering 1,HELP_WANTED, +802,Forest,Help Wanted: Gathering 2,HELP_WANTED, +803,Forest,Help Wanted: Gathering 3,HELP_WANTED, +804,Forest,Help Wanted: Gathering 4,HELP_WANTED, +805,Forest,Help Wanted: Gathering 5,HELP_WANTED, +806,Forest,Help Wanted: Gathering 6,HELP_WANTED, +807,Forest,Help Wanted: Gathering 7,HELP_WANTED, +808,Forest,Help Wanted: Gathering 8,HELP_WANTED, 811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, 812,The Mines - Floor 15,Help Wanted: Slay Monsters 2,HELP_WANTED, 813,The Mines - Floor 25,Help Wanted: Slay Monsters 3,HELP_WANTED, diff --git a/worlds/stardew_valley/early_items.py b/worlds/stardew_valley/early_items.py index d6d493bc90f2..78170f29fee7 100644 --- a/worlds/stardew_valley/early_items.py +++ b/worlds/stardew_valley/early_items.py @@ -1,7 +1,7 @@ from random import Random from .options import BuildingProgression, StardewValleyOptions, BackpackProgression, ExcludeGingerIsland, SeasonRandomization, SpecialOrderLocations, \ - Monstersanity, ToolProgression, SkillProgression + Monstersanity, ToolProgression, SkillProgression, Cooksanity, Chefsanity early_candidate_rate = 4 always_early_candidates = ["Greenhouse", "Desert Obelisk", "Rusty Key"] @@ -36,6 +36,9 @@ def setup_early_items(multiworld, options: StardewValleyOptions, player: int, ra if options.special_order_locations != SpecialOrderLocations.option_disabled: early_candidates.append("Special Order Board") + if options.cooksanity != Cooksanity.option_none | options.chefsanity & Chefsanity.option_queen_of_sauce: + early_candidates.append("The Queen of Sauce") + if options.monstersanity == Monstersanity.option_none: early_candidates.append("Progressive Weapon") else: diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 380f64c70b07..20e86fea5de1 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -12,7 +12,6 @@ from .relationship_logic import RelationshipLogicMixin from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogicMixin -from .time_logic import TimeLogicMixin from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \ QueenOfSauceSource, CookingRecipe, ShopFriendshipSource, \ all_cooking_recipes_by_name @@ -32,7 +31,7 @@ def __init__(self, *args, **kwargs): self.cooking = CookingLogic(*args, **kwargs) -class CookingLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, MoneyLogicMixin, ActionLogicMixin, +class CookingLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, BuildingLogicMixin, RelationshipLogicMixin, SkillLogicMixin, CookingLogicMixin]]): @cached_property def can_cook_in_kitchen(self) -> StardewRule: diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index b0b161bec298..c32a52fce94e 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -11,7 +11,6 @@ from .relationship_logic import RelationshipLogicMixin from .skill_logic import SkillLogicMixin from .special_order_logic import SpecialOrderLogicMixin -from .time_logic import TimeLogicMixin from .. import options from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name from ..data.recipe_data import StarterSource, ShopSource, SkillSource, FriendshipSource @@ -29,7 +28,7 @@ def __init__(self, *args, **kwargs): self.crafting = CraftingLogic(*args, **kwargs) -class CraftingLogic(BaseLogic[Union[TimeLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, RelationshipLogicMixin, +class CraftingLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, MoneyLogicMixin, RelationshipLogicMixin, SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin, QuestLogicMixin]]): @cache_self1 def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index a00a855854a1..7ba431561186 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -23,9 +23,13 @@ def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> combat_rule = self.logic.combat.can_fight_at_level(monster.difficulty) if amount_tier <= 0: amount_tier = 0 - time_rule = self.logic.time.has_lived_months(amount_tier * 2) + time_rule = self.logic.time.has_lived_months(amount_tier) return region_rule & combat_rule & time_rule + @cache_self1 + def can_kill_many(self, monster: StardewMonster) -> StardewRule: + return self.logic.monster.can_kill(monster, MAX_MONTHS / 3) + @cache_self1 def can_kill_max(self, monster: StardewMonster) -> StardewRule: return self.logic.monster.can_kill(monster, MAX_MONTHS) diff --git a/worlds/stardew_valley/logic/time_logic.py b/worlds/stardew_valley/logic/time_logic.py index 54756a94800c..9dcebfe82a4f 100644 --- a/worlds/stardew_valley/logic/time_logic.py +++ b/worlds/stardew_valley/logic/time_logic.py @@ -7,7 +7,7 @@ from ..stardew_rule import StardewRule, HasProgressionPercent, True_ MAX_MONTHS = 12 -MONTH_COEFFICIENT = 50 // MAX_MONTHS +MONTH_COEFFICIENT = 24 // MAX_MONTHS class TimeLogicMixin(BaseLogicMixin): diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 363dbc37daf2..154e16482ed1 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -249,7 +249,7 @@ ConnectionData(SVEEntrance.forest_to_lost_woods, SVERegion.lost_woods), ConnectionData(SVEEntrance.lost_woods_to_junimo_woods, SVERegion.junimo_woods), ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 73240c2bbd08..586008207c1d 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -641,7 +641,7 @@ def set_monstersanity_monster_rules(all_location_names: List[str], logic: Starde continue location = multiworld.get_location(location_name, player) if monstersanity_option == Monstersanity.option_split_goals: - rule = logic.monster.can_kill_max(all_monsters_by_name[monster_name]) + rule = logic.monster.can_kill_many(all_monsters_by_name[monster_name]) else: rule = logic.monster.can_kill(all_monsters_by_name[monster_name]) MultiWorldRules.set_rule(location, rule) @@ -691,7 +691,7 @@ def set_monstersanity_category_rules(all_location_names: List[str], logic: Stard if monstersanity_option == Monstersanity.option_one_per_category: rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category]) else: - rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], 8) + rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], 4) MultiWorldRules.set_rule(location, rule) From c8f317dbf845a08feadca3bd6e045ea7e50ad2dd Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 11 Dec 2023 08:27:18 -0500 Subject: [PATCH 358/482] - Fixed Exotic foraging bundle item count --- worlds/stardew_valley/data/bundle_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 0c1c45891f72..e1cbd61147a2 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -376,7 +376,7 @@ exotic_foraging_items_vanilla = [coconut, cactus_fruit, cave_carrot, red_mushroom, purple_mushroom, maple_syrup, oak_resin, pine_tar, morel] exotic_foraging_items_thematic = [*exotic_foraging_items_vanilla, coral, sea_urchin, clam, cockle, mussel, oyster, seaweed] -exotic_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.exotic_foraging, exotic_foraging_items_vanilla, 4, 4) +exotic_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.exotic_foraging, exotic_foraging_items_vanilla, 9, 5) exotic_foraging_bundle_thematic = BundleTemplate.extend_from(exotic_foraging_bundle_vanilla, exotic_foraging_items_thematic) beach_foraging_items = [nautilus_shell, coral, sea_urchin, rainbow_shell, clam, cockle, mussel, oyster, seaweed] From 8c3ba02ae82cb2917ff043192f4f831ff7b0889e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 11 Dec 2023 20:36:55 -0500 Subject: [PATCH 359/482] - Fixes left and right --- worlds/stardew_valley/data/items.csv | 2 -- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/mods/mod_regions.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 443e0a054182..1f6895c22ce2 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -314,9 +314,7 @@ id,name,classification,groups,mod_name 329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", 330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", 331,Jack-O-Lantern Recipe,progression,FESTIVAL, -332,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, 333,Tub o' Flowers Recipe,progression,FESTIVAL, -334,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, 335,Moonlight Jellies Banner,filler,FESTIVAL, 336,Starport Decal,filler,FESTIVAL, 337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index ca6244f33b25..aecb4252784a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2568,7 +2568,7 @@ id,region,name,tags,mod_name 7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded 7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 154e16482ed1..ad5e0fb11244 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -251,7 +251,7 @@ ConnectionData(SVEEntrance.forest_to_marnie_shed, SVERegion.marnies_shed, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.forest_west_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.NON_PROGRESSION), + ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder), From 921bf8adbb8b874bbbf285bde9a7f8ed63e1b831 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 12 Dec 2023 12:48:33 -0500 Subject: [PATCH 360/482] - Fixed request for Quality ginger --- worlds/stardew_valley/data/bundle_data.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index e1cbd61147a2..b43ad583f6a4 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -388,7 +388,8 @@ desert_foraging_items = [cactus_fruit.as_quality(ForageQuality.gold), cactus_fruit.as_amount(5), coconut.as_quality(ForageQuality.gold), coconut.as_amount(5)] desert_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.desert_foraging, desert_foraging_items, 2, 2) -island_foraging_items = [ginger.as_amount(5), magma_cap.as_quality(ForageQuality.gold), magma_cap.as_amount(5)] +island_foraging_items = [ginger.as_amount(5), magma_cap.as_quality(ForageQuality.gold), magma_cap.as_amount(5), + fiddlehead_fern.as_quality(ForageQuality.gold), fiddlehead_fern.as_amount(5)] island_foraging_bundle = IslandBundleTemplate(CCRoom.crafts_room, BundleName.island_foraging, island_foraging_items, 2, 2) sticky_items = [sap.as_amount(500), sap.as_amount(500)] @@ -400,7 +401,7 @@ quality_foraging_items = list({item.as_quality(ForageQuality.gold).as_amount(1) for item in [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, - *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, *island_foraging_items]}) + *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap]}) quality_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.quality_foraging, quality_foraging_items, 4, 3) crafts_room_bundles_vanilla = [spring_foraging_bundle_vanilla, summer_foraging_bundle_vanilla, fall_foraging_bundle_vanilla, @@ -454,7 +455,7 @@ fish_farmer_items = [roe.as_amount(15), aged_roe.as_amount(15), squid_ink] fish_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.fish_farmer, fish_farmer_items, 3, 2) -garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose] +garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose, poppy, crocus, sweet_pea] garden_bundle = BundleTemplate(CCRoom.pantry, BundleName.garden, garden_items, 5, 4) brewer_items = [mead, pale_ale, wine, juice, green_tea, beer] From 357a94e81686096368f8e9309a0d9f98c2096b2f Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 12 Dec 2023 23:37:26 -0500 Subject: [PATCH 361/482] - add some missing archaeology recipe checks --- worlds/stardew_valley/data/locations.csv | 8 ++++++++ worlds/stardew_valley/test/checks/option_checks.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index aecb4252784a..5233213a9e64 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2518,6 +2518,14 @@ id,region,name,tags,mod_name 7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded 7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded 7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7407,Farm,Craft Glass Path,CRAFTSANITY,Archaeology +7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology +7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology +7410,Farm,Craft Bone Path,CRAFTSANITY,Archaeology +7411,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology +7412,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology +7413,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology +7414,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology 7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/test/checks/option_checks.py b/worlds/stardew_valley/test/checks/option_checks.py index 5caa1c9fa150..42ae2f496113 100644 --- a/worlds/stardew_valley/test/checks/option_checks.py +++ b/worlds/stardew_valley/test/checks/option_checks.py @@ -94,7 +94,7 @@ def assert_festivals_give_access_to_deluxe_scarecrow(tester: SVTestCase, multiwo def assert_has_festival_recipes(tester: SVTestCase, multiworld: MultiWorld): stardew_options = get_stardew_options(multiworld) has_festivals = stardew_options.festival_locations.value != options.FestivalLocations.option_disabled - festival_items = ["Tub o' Flowers Recipe", "Jack-O-Lantern Recipe", "Moonlight Jellies Banner", "Starport Decal"] + festival_items = ["Tub o' Flowers Recipe", "Jack-O-Lantern Recipe"] for festival_item in festival_items: if has_festivals: assert_has_item(tester, multiworld, festival_item) From 0a371133a2246a605a451a85d0a986273db639ea Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 17 Dec 2023 20:40:29 -0500 Subject: [PATCH 362/482] - slight logic fix --- worlds/stardew_valley/logic/logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 0f431ccbe0e0..57b6eed283ce 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -389,7 +389,7 @@ def __init__(self, player: int, options: StardewValleyOptions): WaterItem.green_algae: self.fishing.can_fish_in_freshwater(), WaterItem.nautilus_shell: self.tool.can_forage(Season.winter, Region.beach), WaterItem.sea_urchin: self.tool.can_forage(Generic.any, Region.tide_pools), - WaterItem.seaweed: self.skill.can_fish(Region.beach) | self.region.can_reach(Region.tide_pools), + WaterItem.seaweed: self.skill.can_fish(Region.tide_pools), WaterItem.white_algae: self.skill.can_fish(Region.mines_floor_20), WildSeeds.grass_starter: self.money.can_spend_at(Region.pierre_store, 100), }) From 8bb83e46aa59e6e93472e89d61018e9ee4368955 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 18 Dec 2023 16:04:42 -0500 Subject: [PATCH 363/482] - Removed butterfish dish from shipsanity fish --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 5233213a9e64..efdd691ffa60 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2652,7 +2652,7 @@ id,region,name,tags,mod_name 8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded 8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded 8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY",Stardew Valley Expanded 8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded 8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded 8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded From 3f6566edec91f7e4f85c47479e5eb000369c6a74 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 19 Dec 2023 00:18:22 -0500 Subject: [PATCH 364/482] - Add ginger island tag to island totems so they don't generate as resource pack when the island is excluded --- worlds/stardew_valley/data/items.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 1f6895c22ce2..a624b071089f 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -516,12 +516,12 @@ id,name,classification,groups,mod_name 5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", 5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", 5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM", -5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", 5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", 5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", 5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", From b04bd68cc75b732d38bff212959e6943ac524045 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 28 Dec 2023 01:11:09 -0500 Subject: [PATCH 365/482] WIP paleontoglosit and archaeologist bundle --- worlds/stardew_valley/data/bundle_data.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index b43ad583f6a4..be54d28c9735 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -594,6 +594,14 @@ demolition_items = [cherry_bomb, bomb, mega_bomb, explosive_ammo] demolition_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.demolition, demolition_items, 3, 3) +# archaeologist_items = [golden_mask, golden_relic, ancient_drum, dwarf_gadget, dwarvish_helm, prehistoric_handaxe, bone_flute, anchor, prehistoric_tool, +# chicken_statue, rusty_cog, rusty_spur, rusty_spoon, ancient_sword, ornamental_fan, elvish_jewelry, ancient_doll, chipped_amphora] +# archaeologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.archaeologist, archaeologist_items, 4, 2) +# +# paleontologist_items = [prehistoric_scapula, prehistoric_tibia, prehistoric_skull, skeletal_hand, prehistoric_rib, prehistoric_vertebra, skeletal_tail, +# nautilius_fossil, amphibian_fossil, palm_fossil, trilobite] +# paleontologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.paleontologist, paleontologist_items, 4, 2) + # recycling_items = [stone, coal, iron_ore, wood, torch, cloth, refined_quartz] # recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4) From 45c6b10d46f50b01b9e8300aeff14414bd2581fd Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 28 Dec 2023 23:46:54 -0500 Subject: [PATCH 366/482] add stability test and fix stability --- worlds/stardew_valley/__init__.py | 16 ++++--- worlds/stardew_valley/bundles/bundle.py | 9 +--- worlds/stardew_valley/bundles/bundle_item.py | 37 ++-------------- worlds/stardew_valley/bundles/bundle_room.py | 6 +-- worlds/stardew_valley/data/bundle_data.py | 26 ++++++----- worlds/stardew_valley/items.py | 5 ++- .../test/stability/StabilityOutputScript.py | 29 +++++++++++++ .../test/stability/TestStability.py | 43 +++++++++++++++++++ .../stardew_valley/test/stability/__init__.py | 0 9 files changed, 104 insertions(+), 67 deletions(-) create mode 100644 worlds/stardew_valley/test/stability/StabilityOutputScript.py create mode 100644 worlds/stardew_valley/test/stability/TestStability.py create mode 100644 worlds/stardew_valley/test/stability/__init__.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 259c3fe61c63..69d8ff16ccca 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -65,13 +65,15 @@ class StardewValleyWorld(World): item_name_to_id = {name: data.code for name, data in item_table.items()} location_name_to_id = {name: data.code for name, data in location_table.items()} - item_name_groups = {group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() - in item_table else ""): - [item.name for item in items] for group, items in items_by_group.items()} - location_name_groups = {group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() - in locations_by_tag else ""): - [location.name for location in locations] for group, locations in locations_by_tag.items()} - + item_name_groups = { + group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() in item_table else ""): + [item.name for item in items] for group, items in items_by_group.items() + } + location_name_groups = { + group.name.replace("_", " ").title() + (" Group" if group.name.replace("_", " ").title() in locations_by_tag else ""): + [location.name for location in locations] for group, locations in locations_by_tag.items() + } + data_version = 3 required_client_version = (0, 4, 0) diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index 68b1c397340a..6fdc79521402 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -1,3 +1,4 @@ +from dataclasses import dataclass from random import Random from typing import List @@ -6,18 +7,13 @@ from ..strings.currency_names import Currency +@dataclass class Bundle: room: str name: str items: List[BundleItem] number_required: int - def __init__(self, room: str, name: str, items: List[BundleItem], number_required): - self.room = room - self.name = name - self.items = items - self.number_required = number_required - def __repr__(self): return f"{self.name} -> {self.number_required} from {repr(self.items)}" @@ -157,4 +153,3 @@ def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_ chosen_items.append(random.choice(filtered_items)) return Bundle(self.room, self.name, chosen_items, number_required) - diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index 168dffc41ecd..3250554d5323 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -5,11 +5,12 @@ from ..strings.quality_names import CropQuality, FishQuality, ForageQuality -@dataclass(frozen=True) +@dataclass(frozen=True, order=True) class BundleItem: item_name: str amount: int = 1 quality: str = CropQuality.basic + requires_island: bool = False @staticmethod def money_bundle(amount: int): @@ -38,36 +39,6 @@ def __repr__(self): quality = "" if self.quality == CropQuality.basic else self.quality return f"{self.amount} {quality} {self.item_name}" - @property - def requires_island(self) -> bool: - return False - -class IslandBundleItem(BundleItem): - - def as_amount(self, amount: int): - return IslandBundleItem(self.item_name, amount, self.quality) - - def as_quality(self, quality: str): - return IslandBundleItem(self.item_name, self.amount, quality) - - def as_quality_crop(self): - amount = 5 - difficult_crops = [Fruit.sweet_gem_berry, Fruit.ancient_fruit] - if self.item_name in difficult_crops: - amount = 1 - return self.as_quality(CropQuality.gold).as_amount(amount) - - def as_quality_fish(self): - return self.as_quality(FishQuality.gold) - - def as_quality_forage(self): - return self.as_quality(ForageQuality.gold) - - def __repr__(self): - quality = "" if self.quality == CropQuality.basic else self.quality - return f"{self.amount} {quality} {self.item_name} [ISLAND]" - - @property - def requires_island(self) -> bool: - return True +def IslandBundleItem(*args, **kwargs): + return BundleItem(*args, requires_island=True, **kwargs) diff --git a/worlds/stardew_valley/bundles/bundle_room.py b/worlds/stardew_valley/bundles/bundle_room.py index 688e8ed5ba36..53ee2252587e 100644 --- a/worlds/stardew_valley/bundles/bundle_room.py +++ b/worlds/stardew_valley/bundles/bundle_room.py @@ -1,3 +1,4 @@ +from dataclasses import dataclass from random import Random from typing import List @@ -5,14 +6,11 @@ from ..options import BundlePrice +@dataclass class BundleRoom: name: str bundles: List[Bundle] - def __init__(self, name: str, bundles: List[Bundle]): - self.name = name - self.bundles = bundles - class BundleRoomTemplate: name: str diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index be54d28c9735..5d2af0b3ea2e 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -347,7 +347,6 @@ sugar = BundleItem(Ingredient.sugar) vinegar = BundleItem(Ingredient.vinegar) - # Crafts Room spring_foraging_items_vanilla = [wild_horseradish, daffodil, leek, dandelion] spring_foraging_items_thematic = [*spring_foraging_items_vanilla, spring_onion, salmonberry, morel] @@ -398,10 +397,10 @@ wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3) -quality_foraging_items = list({item.as_quality(ForageQuality.gold).as_amount(1) - for item in - [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, - *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap]}) +quality_foraging_items = sorted({item.as_quality(ForageQuality.gold).as_amount(1) + for item in + [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, + *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap]}) quality_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.quality_foraging, quality_foraging_items, 4, 3) crafts_room_bundles_vanilla = [spring_foraging_bundle_vanilla, summer_foraging_bundle_vanilla, fall_foraging_bundle_vanilla, @@ -414,7 +413,6 @@ crafts_room_thematic = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_thematic, 6) crafts_room_remixed = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_remixed, 6) - # Pantry spring_crops_items_vanilla = [parsnip, green_bean, cauliflower, potato] spring_crops_items_thematic = [*spring_crops_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice] @@ -431,7 +429,7 @@ fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4) fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic) -all_crops_items = list({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) +all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]] quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items] @@ -482,7 +480,6 @@ pantry_thematic = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_thematic, 6) pantry_remixed = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_remixed, 6) - # Fish Tank river_fish_items_vanilla = [sunfish, catfish, shad, tiger_trout] river_fish_items_thematic = [*river_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, pike, bream, salmon, smallmouth_bass, dorado] @@ -536,7 +533,7 @@ rain_fish_items = [red_snapper, shad, catfish, eel, walleye] rain_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.rain_fish, rain_fish_items, 3, 3) -quality_fish_items = list({item.as_quality(FishQuality.gold) for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]}) +quality_fish_items = sorted({item.as_quality(FishQuality.gold) for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]}) quality_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.quality_fish, quality_fish_items, 4, 4) master_fisher_items = [lava_eel, scorpion_carp, octopus, blobfish, lingcod, ice_pip, super_cucumber, stingray, void_salmon, pufferfish] @@ -567,7 +564,6 @@ fish_tank_thematic = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_thematic, 6) fish_tank_remixed = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_remixed, 6) - # Boiler Room blacksmith_items_vanilla = [copper_bar, iron_Bar, gold_bar] blacksmith_items_thematic = [*blacksmith_items_vanilla, iridium_bar, refined_quartz.as_amount(3), wilted_bouquet] @@ -675,10 +671,13 @@ missing_bundle_items_vanilla = [wine.as_quality(ArtisanQuality.silver), dinosaur_mayo, prismatic_shard, caviar, ancient_fruit.as_quality_crop(), void_salmon.as_quality(FishQuality.gold)] -missing_bundle_items_thematic = [*missing_bundle_items_vanilla, pale_ale.as_quality(ArtisanQuality.silver), beer.as_quality(ArtisanQuality.silver), mead.as_quality(ArtisanQuality.silver), - cheese.as_quality(ArtisanQuality.silver), goat_cheese.as_quality(ArtisanQuality.silver), void_mayo, cloth, green_tea, truffle_oil, diamond, +missing_bundle_items_thematic = [*missing_bundle_items_vanilla, pale_ale.as_quality(ArtisanQuality.silver), beer.as_quality(ArtisanQuality.silver), + mead.as_quality(ArtisanQuality.silver), + cheese.as_quality(ArtisanQuality.silver), goat_cheese.as_quality(ArtisanQuality.silver), void_mayo, cloth, green_tea, + truffle_oil, diamond, sweet_gem_berry.as_quality_crop(), starfruit.as_quality_crop(), - tea_leaves.as_amount(5), lava_eel.as_quality(FishQuality.gold), scorpion_carp.as_quality(FishQuality.gold), blobfish.as_quality(FishQuality.gold)] + tea_leaves.as_amount(5), lava_eel.as_quality(FishQuality.gold), scorpion_carp.as_quality(FishQuality.gold), + blobfish.as_quality(FishQuality.gold)] missing_bundle_vanilla = BundleTemplate(CCRoom.abandoned_joja_mart, BundleName.missing_bundle, missing_bundle_items_vanilla, 6, 5) missing_bundle_thematic = BundleTemplate.extend_from(missing_bundle_vanilla, missing_bundle_items_thematic) @@ -718,7 +717,6 @@ vault_thematic = BundleRoomTemplate(CCRoom.vault, vault_bundles_thematic, 4) vault_remixed = BundleRoomTemplate(CCRoom.vault, vault_bundles_remixed, 4) - all_bundle_items_except_money = [] all_remixed_bundles = [*crafts_room_bundles_remixed, *pantry_bundles_remixed, *fish_tank_bundles_remixed, *boiler_room_bundles_remixed, *bulletin_board_bundles_remixed, missing_bundle_thematic] diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 8203b45e1dd1..d7f0a1db8b6a 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -13,7 +13,7 @@ from .options import StardewValleyOptions, TrapItems, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Cropsanity, \ Friendsanity, Museumsanity, \ Fishsanity, BuildingProgression, SkillProgression, ToolProgression, ElevatorProgression, BackpackProgression, ArcadeMachineLocations, Monstersanity, Goal, \ - Shipsanity, Chefsanity, Craftsanity, BundleRandomization, BundlePrice + Chefsanity, Craftsanity, BundleRandomization from .strings.ap_names.ap_weapon_names import APWeapon from .strings.ap_names.buff_names import Buff from .strings.ap_names.community_upgrade_names import CommunityUpgrade @@ -85,6 +85,7 @@ class Group(enum.Enum): MAGIC_SPELL = enum.auto() MOD_WARP = enum.auto() + @dataclass(frozen=True) class ItemData: code_without_offset: Optional[int] @@ -514,7 +515,7 @@ def create_special_order_board_rewards(item_factory: StardewItemFactory, options if options.special_order_locations == SpecialOrderLocations.option_disabled: return - special_order_board_items = {item for item in items_by_group[Group.SPECIAL_ORDER_BOARD]} + special_order_board_items = [item for item in items_by_group[Group.SPECIAL_ORDER_BOARD]] items.extend([item_factory(item) for item in special_order_board_items]) diff --git a/worlds/stardew_valley/test/stability/StabilityOutputScript.py b/worlds/stardew_valley/test/stability/StabilityOutputScript.py new file mode 100644 index 000000000000..59b43f8d9fea --- /dev/null +++ b/worlds/stardew_valley/test/stability/StabilityOutputScript.py @@ -0,0 +1,29 @@ +import argparse +import json + +from ...test import setup_solo_multiworld + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--seed', help='Define seed number to generate.', type=int, required=True) + + args = parser.parse_args() + seed = args.seed + + multi_world = setup_solo_multiworld(seed=seed) + + output = { + "bundles": { + bundle_room.name: { + bundle.name: str(bundle.items) + for bundle in bundle_room.bundles + } + for bundle_room in multi_world.worlds[1].modified_bundles + }, + "items": [item.name for item in multi_world.get_items()], + "location_rules": {location.name: repr(location.access_rule) for location in multi_world.get_locations(1)} + } + + print(json.dumps(output)) +else: + raise RuntimeError("Do not import this file, execute it in different python session so the PYTHONHASHSEED is different..") diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py new file mode 100644 index 000000000000..4a695520662b --- /dev/null +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -0,0 +1,43 @@ +import json +import re +import subprocess +import unittest + +from BaseClasses import get_seed + +# at 0x102ca98a0> +lambda_regex = re.compile(r" at (.*)>") + + +class TestGenerationIsStable(unittest.TestCase): + """Let it be known that I hate this tests, and if someone has a better idea than starting subprocesses, please fix this. + """ + + def test_all_locations_and_items_are_the_same_between_two_generations(self): + seed = get_seed(234) + + output_a = subprocess.check_output(['python3', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) + output_b = subprocess.check_output(['python3', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) + + result_a = json.loads(output_a) + result_b = json.loads(output_b) + + for i, ((room_a, bundles_a), (room_b, bundles_b)) in enumerate(zip(result_a["bundles"].items(), result_b["bundles"].items())): + self.assertEqual(room_a, room_b, f"Bundle rooms at index {i} is different between both executions. Seed={seed}") + for j, ((bundle_a, items_a), (bundle_b, items_b)) in enumerate(zip(bundles_a.items(), bundles_b.items())): + self.assertEqual(bundle_a, bundle_b, f"Bundle in room {room_a} at index {j} is different between both executions. Seed={seed}") + self.assertEqual(items_a, items_b, f"Items in bundle {bundle_a} are different between both executions. Seed={seed}") + + for i, (item_a, item_b) in enumerate(zip(result_a["items"], result_b["items"])): + self.assertEqual(item_a, item_b, f"Item at index {i} is different between both executions. Seed={seed}") + + for i, ((location_a, rule_a), (location_b, rule_b)) in enumerate(zip(result_a["location_rules"].items(), result_b["location_rules"].items())): + self.assertEqual(location_a, location_a, f"Location at index {i} is different between both executions. Seed={seed}") + + match = lambda_regex.match(rule_a) + if match: + self.assertTrue(bool(lambda_regex.match(rule_b)), + f"Location rule of {location_a} at index {i} is different between both executions. Seed={seed}") + continue + + self.assertEqual(rule_a, rule_b, f"Location rule of {location_a} at index {i} is different between both executions. Seed={seed}") diff --git a/worlds/stardew_valley/test/stability/__init__.py b/worlds/stardew_valley/test/stability/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 From 3ab5c15bf6f494cd051d706a770f3052daa7a618 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Thu, 28 Dec 2023 23:50:33 -0500 Subject: [PATCH 367/482] remove hardcoded seed --- worlds/stardew_valley/test/stability/TestStability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py index 4a695520662b..a13ebaa92322 100644 --- a/worlds/stardew_valley/test/stability/TestStability.py +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -14,7 +14,7 @@ class TestGenerationIsStable(unittest.TestCase): """ def test_all_locations_and_items_are_the_same_between_two_generations(self): - seed = get_seed(234) + seed = get_seed() output_a = subprocess.check_output(['python3', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) output_b = subprocess.check_output(['python3', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) From 9141fed738908577d5b718278ae35aa8a87f6e05 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 29 Dec 2023 12:29:13 -0500 Subject: [PATCH 368/482] fix ginger island exclusion --- worlds/stardew_valley/bundles/bundle.py | 1 + worlds/stardew_valley/bundles/bundle_item.py | 4 ++-- worlds/stardew_valley/bundles/bundle_room.py | 6 +----- worlds/stardew_valley/test/TestOptions.py | 6 +++--- worlds/stardew_valley/test/checks/world_checks.py | 4 ++-- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index 6fdc79521402..653ce54c991b 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -18,6 +18,7 @@ def __repr__(self): return f"{self.name} -> {self.number_required} from {repr(self.items)}" +@dataclass class BundleTemplate: room: str name: str diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index 3250554d5323..4993b5cfb3a2 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -17,10 +17,10 @@ def money_bundle(amount: int): return BundleItem(Currency.money, amount) def as_amount(self, amount: int): - return BundleItem(self.item_name, amount, self.quality) + return BundleItem(self.item_name, amount, self.quality, requires_island=self.requires_island) def as_quality(self, quality: str): - return BundleItem(self.item_name, self.amount, quality) + return BundleItem(self.item_name, self.amount, quality, requires_island=self.requires_island) def as_quality_crop(self): amount = 5 diff --git a/worlds/stardew_valley/bundles/bundle_room.py b/worlds/stardew_valley/bundles/bundle_room.py index 53ee2252587e..5c43da985b13 100644 --- a/worlds/stardew_valley/bundles/bundle_room.py +++ b/worlds/stardew_valley/bundles/bundle_room.py @@ -12,16 +12,12 @@ class BundleRoom: bundles: List[Bundle] +@dataclass class BundleRoomTemplate: name: str bundles: List[BundleTemplate] number_bundles: int - def __init__(self, name: str, bundles: List[BundleTemplate], number_bundles: int): - self.name = name - self.bundles = bundles - self.number_bundles = number_bundles - def create_bundle_room(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool): filtered_bundles = [bundle for bundle in self.bundles if allow_island_items or not bundle.requires_island] chosen_bundles = random.sample(filtered_bundles, self.number_bundles) diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index e812380a8c3f..0599ab974eba 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -3,11 +3,11 @@ from random import random from typing import Dict -from BaseClasses import ItemClassification, MultiWorld +from BaseClasses import MultiWorld from Options import NamedRange from . import setup_solo_multiworld, SVTestCase, allsanity_options_without_mods, allsanity_options_with_mods from .checks.world_checks import basic_checks -from .. import StardewItem, items_by_group, Group, StardewValleyWorld +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 from ..strings.goal_names import Goal as GoalName @@ -154,7 +154,7 @@ def test_given_choice_when_generate_exclude_ginger_island(self): if not option.options or option_name == ExcludeGingerIsland.internal_name: continue for value in option.options: - seed = int(random() * pow(10, 18) - 1) + seed = 345093477266400704 # int(random() * pow(10, 18) - 1) with self.subTest(f"{option_name}: {value} [Seed: {seed}]"): # print(seed) multiworld = setup_solo_multiworld( diff --git a/worlds/stardew_valley/test/checks/world_checks.py b/worlds/stardew_valley/test/checks/world_checks.py index 2d8bdd7f631c..2e9d6a88c1b0 100644 --- a/worlds/stardew_valley/test/checks/world_checks.py +++ b/worlds/stardew_valley/test/checks/world_checks.py @@ -22,7 +22,7 @@ def collect_all_then_assert_can_win(tester: unittest.TestCase, multiworld: Multi multiworld.state.collect(item) victory = multiworld.find_item("Victory", 1) can_win = victory.can_reach(multiworld.state) - tester.assertTrue(can_win) + tester.assertTrue(can_win, victory.access_rule.explain(multiworld.state)) def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): @@ -37,4 +37,4 @@ def assert_same_number_items_locations(tester: unittest.TestCase, multiworld: Mu def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): assert_can_win(tester, multiworld) - assert_same_number_items_locations(tester, multiworld) \ No newline at end of file + assert_same_number_items_locations(tester, multiworld) From 8c304beee54ddaf6add4bf5f4fb700c6a2586397 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 29 Dec 2023 12:29:56 -0500 Subject: [PATCH 369/482] remove hardcoded seed --- worlds/stardew_valley/test/TestOptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 0599ab974eba..ab35765f2dd9 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -154,7 +154,7 @@ def test_given_choice_when_generate_exclude_ginger_island(self): if not option.options or option_name == ExcludeGingerIsland.internal_name: continue for value in option.options: - seed = 345093477266400704 # int(random() * pow(10, 18) - 1) + seed =qg int(random() * pow(10, 18) - 1) with self.subTest(f"{option_name}: {value} [Seed: {seed}]"): # print(seed) multiworld = setup_solo_multiworld( From b7f391cdaf9e3a22160081d61740340f00cfe9b9 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 29 Dec 2023 12:31:35 -0500 Subject: [PATCH 370/482] remove hardcoded seed --- worlds/stardew_valley/test/TestOptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index ab35765f2dd9..61f49ed67c2e 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -154,7 +154,7 @@ def test_given_choice_when_generate_exclude_ginger_island(self): if not option.options or option_name == ExcludeGingerIsland.internal_name: continue for value in option.options: - seed =qg int(random() * pow(10, 18) - 1) + seed = int(random() * pow(10, 18) - 1) with self.subTest(f"{option_name}: {value} [Seed: {seed}]"): # print(seed) multiworld = setup_solo_multiworld( From 4970997c7cf0242da7add451f4ad770c68c1000c Mon Sep 17 00:00:00 2001 From: Jouramie Date: Fri, 29 Dec 2023 23:08:57 -0500 Subject: [PATCH 371/482] split rules in multiple files --- .../stardew_valley/stardew_rule/__init__.py | 4 + .../{stardew_rule.py => stardew_rule/base.py} | 288 +----------------- .../stardew_rule/explanation.py | 55 ++++ worlds/stardew_valley/stardew_rule/literal.py | 62 ++++ .../stardew_valley/stardew_rule/protocol.py | 31 ++ worlds/stardew_valley/stardew_rule/state.py | 165 ++++++++++ 6 files changed, 332 insertions(+), 273 deletions(-) create mode 100644 worlds/stardew_valley/stardew_rule/__init__.py rename worlds/stardew_valley/{stardew_rule.py => stardew_rule/base.py} (67%) create mode 100644 worlds/stardew_valley/stardew_rule/explanation.py create mode 100644 worlds/stardew_valley/stardew_rule/literal.py create mode 100644 worlds/stardew_valley/stardew_rule/protocol.py create mode 100644 worlds/stardew_valley/stardew_rule/state.py diff --git a/worlds/stardew_valley/stardew_rule/__init__.py b/worlds/stardew_valley/stardew_rule/__init__.py new file mode 100644 index 000000000000..73b2d1b66747 --- /dev/null +++ b/worlds/stardew_valley/stardew_rule/__init__.py @@ -0,0 +1,4 @@ +from .base import * +from .literal import * +from .protocol import * +from .state import * diff --git a/worlds/stardew_valley/stardew_rule.py b/worlds/stardew_valley/stardew_rule/base.py similarity index 67% rename from worlds/stardew_valley/stardew_rule.py rename to worlds/stardew_valley/stardew_rule/base.py index fd5bd2e6b857..d195d7c06113 100644 --- a/worlds/stardew_valley/stardew_rule.py +++ b/worlds/stardew_valley/stardew_rule/base.py @@ -3,62 +3,20 @@ import logging from abc import ABC, abstractmethod from collections import deque -from dataclasses import dataclass, field -from functools import cached_property from itertools import chain from threading import Lock from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional -from BaseClasses import CollectionState, ItemClassification -from .items import item_table +from BaseClasses import CollectionState +from .explanation import RuleExplanation +from .literal import true_, false_, LiteralStardewRule +from .protocol import StardewRule MISSING_ITEM = "THIS ITEM IS MISSING" logger = logging.getLogger(__name__) -@dataclass -class StardewRuleExplanation: - rule: StardewRule - state: CollectionState - expected: bool - sub_rules: Iterable[StardewRule] = field(default_factory=set) - - def summary(self, depth=0): - return " " * depth + f"{str(self.rule)} -> {self.result}" - - def __str__(self, depth=0): - if not self.sub_rules: - return self.summary(depth) - - return self.summary(depth) + "\n" + "\n".join(StardewRuleExplanation.__str__(i, depth + 1) - if i.result is not self.expected else i.summary(depth + 1) - for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) - - def __repr__(self, depth=0): - if not self.sub_rules: - return self.summary(depth) - - return self.summary(depth) + "\n" + "\n".join(StardewRuleExplanation.__repr__(i, depth + 1) - for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) - - @cached_property - def result(self): - return self.rule(self.state) - - @cached_property - def explained_sub_rules(self): - return [i.explain(self.state) for i in self.sub_rules] - - -class StardewRule(ABC): - - @abstractmethod - def __call__(self, state: CollectionState) -> bool: - raise NotImplementedError - - @abstractmethod - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - raise NotImplementedError +class BaseStardewRule(StardewRule, ABC): def __or__(self, other) -> StardewRule: if other is true_ or other is false_ or type(other) is Or: @@ -72,72 +30,8 @@ def __and__(self, other) -> StardewRule: return And(self, other) - @abstractmethod - def get_difficulty(self): - raise NotImplementedError - - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, expected) - - -class LiteralStardewRule(StardewRule, ABC): - value: bool - - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self, self.value - - def __call__(self, state: CollectionState) -> bool: - return self.value - - def __repr__(self): - return str(self.value) - -class True_(LiteralStardewRule): # noqa - value = True - - def __new__(cls, _cache=[]): # noqa - # Only one single instance will be ever created. - if not _cache: - _cache.append(super(True_, cls).__new__(cls)) - return _cache[0] - - def __or__(self, other) -> StardewRule: - return self - - def __and__(self, other) -> StardewRule: - return other - - def get_difficulty(self): - return 0 - - -class False_(LiteralStardewRule): # noqa - value = False - - def __new__(cls, _cache=[]): # noqa - # Only one single instance will be ever created. - if not _cache: - _cache.append(super(False_, cls).__new__(cls)) - return _cache[0] - - def __or__(self, other) -> StardewRule: - return other - - def __and__(self, other) -> StardewRule: - return self - - def get_difficulty(self): - return 999999999 - - -false_ = False_() -true_ = True_() -assert false_ is False_() -assert true_ is True_() - - -class CombinableStardewRule(StardewRule, ABC): +class CombinableStardewRule(BaseStardewRule, ABC): @property @abstractmethod @@ -231,7 +125,7 @@ def release(self): self.locked = False -class AggregatingStardewRule(StardewRule, ABC): +class AggregatingStardewRule(BaseStardewRule, ABC): """ Logic for both "And" and "Or" rules. """ @@ -405,8 +299,8 @@ def __eq__(self, other): def __hash__(self): return hash((id(self.combinable_rules), self.simplification_state.original_simplifiable_rules)) - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, expected, self.original_rules) + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: + return RuleExplanation(self, state, expected, self.original_rules) class Or(AggregatingStardewRule): @@ -467,7 +361,7 @@ def get_difficulty(self): return max(rule.get_difficulty() for rule in self.original_rules) -class Count(StardewRule): +class Count(BaseStardewRule): count: int rules: List[StardewRule] rules_count: int @@ -509,8 +403,8 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul def __call__(self, state: CollectionState) -> bool: return self.evaluate_while_simplifying(state)[1] - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, expected, self.rules) + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: + return RuleExplanation(self, state, expected, self.rules) def get_difficulty(self): self.rules = sorted(self.rules, key=lambda x: x.get_difficulty()) @@ -522,120 +416,7 @@ def __repr__(self): return f"Received {self.count} {repr(self.rules)}" -class TotalReceived(StardewRule): - count: int - items: Iterable[str] - player: int - - def __init__(self, count: int, items: Union[str, Iterable[str]], player: int): - items_list: List[str] - - if isinstance(items, Iterable): - items_list = [*items] - else: - items_list = [items] - - assert items_list, "Can't create a Total Received conditions without items" - for item in items_list: - assert item_table[item].classification & ItemClassification.progression, \ - f"Item [{item_table[item].name}] has to be progression to be used in logic" - - self.player = player - self.items = items_list - self.count = count - - def __call__(self, state: CollectionState) -> bool: - c = 0 - for item in self.items: - c += state.count(item, self.player) - if c >= self.count: - return True - return False - - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self, self(state) - - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, expected, [Received(i, self.player, 1) for i in self.items]) - - def get_difficulty(self): - return self.count - - def __repr__(self): - return f"Received {self.count} {self.items}" - - -@dataclass(frozen=True) -class Received(CombinableStardewRule): - item: str - player: int - count: int - - def __post_init__(self): - assert item_table[self.item].classification & ItemClassification.progression, \ - f"Item [{item_table[self.item].name}] has to be progression to be used in logic" - - @property - def combination_key(self) -> Hashable: - return self.item - - @property - def value(self): - return self.count - - def __call__(self, state: CollectionState) -> bool: - return state.has(self.item, self.player, self.count) - - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self, self(state) - - def __repr__(self): - if self.count == 1: - return f"Received {self.item}" - return f"Received {self.count} {self.item}" - - def get_difficulty(self): - return self.count - - -@dataclass(frozen=True) -class Reach(StardewRule): - spot: str - resolution_hint: str - player: int - - def __call__(self, state: CollectionState) -> bool: - return state.can_reach(self.spot, self.resolution_hint, self.player) - - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self, self(state) - - def __repr__(self): - return f"Reach {self.resolution_hint} {self.spot}" - - def get_difficulty(self): - return 1 - - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - if self.resolution_hint == 'Location': - spot = state.multiworld.get_location(self.spot, self.player) - access_rule = spot.access_rule - if isinstance(access_rule, StardewRule): - access_rule = And(access_rule, Reach(spot.parent_region.name, "Region", self.player)) - elif self.resolution_hint == 'Entrance': - spot = state.multiworld.get_entrance(self.spot, self.player) - access_rule = spot.access_rule - else: - spot = state.multiworld.get_region(self.spot, self.player) - access_rule = Or(*(Reach(e.name, "Entrance", self.player) for e in spot.entrances)) - - if not isinstance(access_rule, StardewRule): - return StardewRuleExplanation(self, state, expected) - - return StardewRuleExplanation(self, state, expected, [access_rule]) - - -class Has(StardewRule): +class Has(BaseStardewRule): item: str # For sure there is a better way than just passing all the rules everytime other_rules: Dict[str, StardewRule] @@ -650,8 +431,8 @@ def __call__(self, state: CollectionState) -> bool: def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self.other_rules[self.item].evaluate_while_simplifying(state) - def explain(self, state: CollectionState, expected=True) -> StardewRuleExplanation: - return StardewRuleExplanation(self, state, expected, [self.other_rules[self.item]]) + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: + return RuleExplanation(self, state, expected, [self.other_rules[self.item]]) def get_difficulty(self): return self.other_rules[self.item].get_difficulty() + 1 @@ -670,45 +451,6 @@ def __hash__(self): return hash(self.item) -@dataclass(frozen=True) -class HasProgressionPercent(CombinableStardewRule): - player: int - percent: int - - def __post_init__(self): - assert self.percent > 0, "HasProgressionPercent rule must be above 0%" - assert self.percent <= 100, "HasProgressionPercent rule can't require more than 100% of items" - - @property - def combination_key(self) -> Hashable: - return HasProgressionPercent.__name__ - - @property - def value(self): - return self.percent - - def __call__(self, state: CollectionState) -> bool: - stardew_world = state.multiworld.worlds[self.player] - total_count = stardew_world.total_progression_items - needed_count = (total_count * self.percent) // 100 - total_count = 0 - for item in state.prog_items[self.player]: - item_count = state.prog_items[self.player][item] - total_count += item_count - if total_count >= needed_count: - return True - return False - - def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: - return self, self(state) - - def __repr__(self): - return f"HasProgressionPercent {self.percent}" - - def get_difficulty(self): - return self.percent - - class RepeatableChain(Iterable, Sized): """ Essentially a copy of what's in the core, with proper type hinting diff --git a/worlds/stardew_valley/stardew_rule/explanation.py b/worlds/stardew_valley/stardew_rule/explanation.py new file mode 100644 index 000000000000..f6eacafca127 --- /dev/null +++ b/worlds/stardew_valley/stardew_rule/explanation.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +from abc import abstractmethod +from dataclasses import dataclass, field +from functools import cached_property +from typing import Iterable, Protocol, runtime_checkable + +from BaseClasses import CollectionState + +max_explanation_depth = 10 + + +@runtime_checkable +class ExplainableRule(Protocol): + + @abstractmethod + def __call__(self, state: CollectionState) -> bool: + ... + + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: + return RuleExplanation(self, state, expected) + + +@dataclass +class RuleExplanation: + rule: ExplainableRule + state: CollectionState + expected: bool + sub_rules: Iterable[ExplainableRule] = field(default_factory=list) + + def summary(self, depth=0): + return " " * depth + f"{str(self.rule)} -> {self.result}" + + def __str__(self, depth=0): + if not self.sub_rules or depth >= max_explanation_depth: + return self.summary(depth) + + return self.summary(depth) + "\n" + "\n".join(RuleExplanation.__str__(i, depth + 1) + if i.result is not self.expected else i.summary(depth + 1) + for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) + + def __repr__(self, depth=0): + if not self.sub_rules or depth >= max_explanation_depth: + return self.summary(depth) + + return self.summary(depth) + "\n" + "\n".join(RuleExplanation.__repr__(i, depth + 1) + for i in sorted(self.explained_sub_rules, key=lambda x: x.result)) + + @cached_property + def result(self): + return self.rule(self.state) + + @cached_property + def explained_sub_rules(self): + return [i.explain(self.state) for i in self.sub_rules] diff --git a/worlds/stardew_valley/stardew_rule/literal.py b/worlds/stardew_valley/stardew_rule/literal.py new file mode 100644 index 000000000000..58f7bae047fa --- /dev/null +++ b/worlds/stardew_valley/stardew_rule/literal.py @@ -0,0 +1,62 @@ +from abc import ABC +from typing import Tuple + +from BaseClasses import CollectionState +from .protocol import StardewRule + + +class LiteralStardewRule(StardewRule, ABC): + value: bool + + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self.value + + def __call__(self, state: CollectionState) -> bool: + return self.value + + def __repr__(self): + return str(self.value) + + +class True_(LiteralStardewRule): # noqa + value = True + + def __new__(cls, _cache=[]): # noqa + # Only one single instance will be ever created. + if not _cache: + _cache.append(super(True_, cls).__new__(cls)) + return _cache[0] + + def __or__(self, other) -> StardewRule: + return self + + def __and__(self, other) -> StardewRule: + return other + + def get_difficulty(self): + return 0 + + +class False_(LiteralStardewRule): # noqa + value = False + + def __new__(cls, _cache=[]): # noqa + # Only one single instance will be ever created. + if not _cache: + _cache.append(super(False_, cls).__new__(cls)) + return _cache[0] + + def __or__(self, other) -> StardewRule: + return other + + def __and__(self, other) -> StardewRule: + return self + + def get_difficulty(self): + return 999999999 + + +false_ = False_() +true_ = True_() +assert false_ +assert true_ diff --git a/worlds/stardew_valley/stardew_rule/protocol.py b/worlds/stardew_valley/stardew_rule/protocol.py new file mode 100644 index 000000000000..4f17d816e048 --- /dev/null +++ b/worlds/stardew_valley/stardew_rule/protocol.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from abc import abstractmethod +from typing import Protocol, Tuple, runtime_checkable + +from BaseClasses import CollectionState +from .explanation import ExplainableRule + + +@runtime_checkable +class StardewRule(ExplainableRule, Protocol): + + @abstractmethod + def __call__(self, state: CollectionState) -> bool: + ... + + @abstractmethod + def __and__(self, other: StardewRule): + ... + + @abstractmethod + def __or__(self, other: StardewRule): + ... + + @abstractmethod + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + ... + + @abstractmethod + def get_difficulty(self): + ... diff --git a/worlds/stardew_valley/stardew_rule/state.py b/worlds/stardew_valley/stardew_rule/state.py new file mode 100644 index 000000000000..34b519bb89b9 --- /dev/null +++ b/worlds/stardew_valley/stardew_rule/state.py @@ -0,0 +1,165 @@ +from dataclasses import dataclass +from typing import Iterable, Union, List, Tuple, Hashable + +from BaseClasses import ItemClassification, CollectionState +from .base import BaseStardewRule, CombinableStardewRule +from .explanation import RuleExplanation, ExplainableRule +from .protocol import StardewRule +from ..items import item_table + + +class TotalReceived(BaseStardewRule): + count: int + items: Iterable[str] + player: int + + def __init__(self, count: int, items: Union[str, Iterable[str]], player: int): + items_list: List[str] + + if isinstance(items, Iterable): + items_list = [*items] + else: + items_list = [items] + + assert items_list, "Can't create a Total Received conditions without items" + for item in items_list: + assert item_table[item].classification & ItemClassification.progression, \ + f"Item [{item_table[item].name}] has to be progression to be used in logic" + + self.player = player + self.items = items_list + self.count = count + + def __call__(self, state: CollectionState) -> bool: + c = 0 + for item in self.items: + c += state.count(item, self.player) + if c >= self.count: + return True + return False + + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + + def get_difficulty(self): + return self.count + + def __repr__(self): + return f"Received {self.count} {self.items}" + + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: + return RuleExplanation(self, state, expected, [Received(i, self.player, 1) for i in self.items]) + + +@dataclass(frozen=True) +class Received(CombinableStardewRule): + item: str + player: int + count: int + + def __post_init__(self): + assert item_table[self.item].classification & ItemClassification.progression, \ + f"Item [{item_table[self.item].name}] has to be progression to be used in logic" + + @property + def combination_key(self) -> Hashable: + return self.item + + @property + def value(self): + return self.count + + def __call__(self, state: CollectionState) -> bool: + return state.has(self.item, self.player, self.count) + + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + + def __repr__(self): + if self.count == 1: + return f"Received {self.item}" + return f"Received {self.count} {self.item}" + + def get_difficulty(self): + return self.count + + +@dataclass(frozen=True) +class Reach(BaseStardewRule): + spot: str + resolution_hint: str + player: int + + def __call__(self, state: CollectionState) -> bool: + return state.can_reach(self.spot, self.resolution_hint, self.player) + + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + + def __repr__(self): + return f"Reach {self.resolution_hint} {self.spot}" + + def get_difficulty(self): + return 1 + + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: + access_rules = None + if self.resolution_hint == 'Location': + spot = state.multiworld.get_location(self.spot, self.player) + + if isinstance(spot.access_rule, ExplainableRule): + access_rules = [spot.access_rule, Reach(spot.parent_region.name, "Region", self.player)] + + elif self.resolution_hint == 'Entrance': + spot = state.multiworld.get_entrance(self.spot, self.player) + + if isinstance(spot.access_rule, ExplainableRule): + access_rules = [spot.access_rule, Reach(spot.parent_region.name, "Region", self.player)] + + else: + spot = state.multiworld.get_region(self.spot, self.player) + access_rules = [*(Reach(e.name, "Entrance", self.player) for e in spot.entrances)] + + if not access_rules: + return RuleExplanation(self, state, expected) + + return RuleExplanation(self, state, expected, access_rules) + + +@dataclass(frozen=True) +class HasProgressionPercent(CombinableStardewRule): + player: int + percent: int + + def __post_init__(self): + assert self.percent > 0, "HasProgressionPercent rule must be above 0%" + assert self.percent <= 100, "HasProgressionPercent rule can't require more than 100% of items" + + @property + def combination_key(self) -> Hashable: + return HasProgressionPercent.__name__ + + @property + def value(self): + return self.percent + + def __call__(self, state: CollectionState) -> bool: + stardew_world = state.multiworld.worlds[self.player] + total_count = stardew_world.total_progression_items + needed_count = (total_count * self.percent) // 100 + total_count = 0 + for item in state.prog_items[self.player]: + item_count = state.prog_items[self.player][item] + total_count += item_count + if total_count >= needed_count: + return True + return False + + def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: + return self, self(state) + + def __repr__(self): + return f"HasProgressionPercent {self.percent}" + + def get_difficulty(self): + return self.percent From a69b65d6c1ec932ad5dec9e129578357f8a2a645 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 25 Dec 2023 15:06:05 -0500 Subject: [PATCH 372/482] - Added Slime Farmer Bundle - Added Trash and recycling bundles --- worlds/stardew_valley/data/bundle_data.py | 29 ++++++++++++++----- worlds/stardew_valley/data/locations.csv | 4 ++- worlds/stardew_valley/data/museum_data.py | 3 +- worlds/stardew_valley/strings/bundle_names.py | 2 ++ worlds/stardew_valley/strings/metal_names.py | 1 + .../strings/monster_drop_names.py | 5 ++++ 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 5d2af0b3ea2e..8129d337956f 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -228,6 +228,9 @@ refined_quartz = BundleItem(MetalBar.quartz) coal = BundleItem(Material.coal, 5) iridium_ore = BundleItem(Ore.iridium) +gold_ore = BundleItem(Ore.gold) +iron_ore = BundleItem(Ore.iron) +copper_ore = BundleItem(Ore.copper) battery_pack = BundleItem(ArtisanGood.battery_pack) quartz = BundleItem(Mineral.quartz) @@ -247,6 +250,13 @@ solar_essence = BundleItem(Loot.solar_essence) void_essence = BundleItem(Loot.void_essence) +petrified_slime = BundleItem(Mineral.petrified_slime) +blue_slime_egg = BundleItem(Loot.blue_slime_egg) +red_slime_egg = BundleItem(Loot.red_slime_egg) +purple_slime_egg = BundleItem(Loot.purple_slime_egg) +green_slime_egg = BundleItem(Loot.green_slime_egg) +tiger_slime_egg = IslandBundleItem(Loot.tiger_slime_egg) + cherry_bomb = BundleItem(Bomb.cherry_bomb, 5) bomb = BundleItem(Bomb.bomb, 2) mega_bomb = BundleItem(Bomb.mega_bomb) @@ -470,12 +480,16 @@ speed_gro, deluxe_speed_gro, hyper_speed_gro, tree_fertilizer] agronomist_bundle = BundleTemplate(CCRoom.pantry, BundleName.agronomist, agronomist_items, 4, 3) +slime_farmer_items = [slime.as_amount(99), petrified_slime.as_amount(10), blue_slime_egg, red_slime_egg, + purple_slime_egg, green_slime_egg, tiger_slime_egg] +slime_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.slime_farmer, slime_farmer_items, 4, 3) + pantry_bundles_vanilla = [spring_crops_bundle_vanilla, summer_crops_bundle_vanilla, fall_crops_bundle_vanilla, quality_crops_bundle_vanilla, animal_bundle_vanilla, artisan_bundle_vanilla] pantry_bundles_thematic = [spring_crops_bundle_thematic, summer_crops_bundle_thematic, fall_crops_bundle_thematic, quality_crops_bundle_thematic, animal_bundle_thematic, artisan_bundle_thematic] pantry_bundles_remixed = [*pantry_bundles_thematic, rare_crops_bundle, fish_farmer_bundle, garden_bundle, - brewer_bundle, orchard_bundle, island_crops_bundle, agronomist_bundle] + brewer_bundle, orchard_bundle, island_crops_bundle, agronomist_bundle, slime_farmer_bundle] pantry_vanilla = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_vanilla, 6) pantry_thematic = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_thematic, 6) pantry_remixed = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_remixed, 6) @@ -507,7 +521,7 @@ crab_pot_items_thematic = [*crab_pot_items_vanilla, *crab_pot_trash_items] crab_pot_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.crab_pot, crab_pot_items_vanilla, 10, 5) crab_pot_bundle_thematic = BundleTemplate.extend_from(crab_pot_bundle_vanilla, crab_pot_items_thematic) -recycling_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.recycling, crab_pot_trash_items, 4, 4) +trash_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.trash, crab_pot_trash_items, 4, 4) specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip] specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip, @@ -555,8 +569,9 @@ night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla] fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic, night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic] -fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, winter_fish_bundle, recycling_bundle, +fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, winter_fish_bundle, trash_bundle, rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle, tackle_bundle, bait_bundle] + # In Remixed, the trash items are in the recycling bundle, so we don't use the thematic version of the crab pot bundle that added trash items to it fish_tank_bundles_remixed.remove(crab_pot_bundle_thematic) fish_tank_bundles_remixed.append(crab_pot_bundle_vanilla) @@ -590,6 +605,8 @@ demolition_items = [cherry_bomb, bomb, mega_bomb, explosive_ammo] demolition_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.demolition, demolition_items, 3, 3) +recycling_items = [stone, coal, iron_ore, wood, cloth, refined_quartz] +recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4) # archaeologist_items = [golden_mask, golden_relic, ancient_drum, dwarf_gadget, dwarvish_helm, prehistoric_handaxe, bone_flute, anchor, prehistoric_tool, # chicken_statue, rusty_cog, rusty_spur, rusty_spoon, ancient_sword, ornamental_fan, elvish_jewelry, ancient_doll, chipped_amphora] # archaeologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.archaeologist, archaeologist_items, 4, 2) @@ -598,12 +615,10 @@ # nautilius_fossil, amphibian_fossil, palm_fossil, trilobite] # paleontologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.paleontologist, paleontologist_items, 4, 2) -# recycling_items = [stone, coal, iron_ore, wood, torch, cloth, refined_quartz] -# recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4) - boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla] boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic] -boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle, demolition_bundle] +boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle, + demolition_bundle, recycling_bundle] boiler_room_vanilla = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_vanilla, 3) boiler_room_thematic = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_thematic, 3) boiler_room_remixed = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_remixed, 3) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index efdd691ffa60..fcffd8f99b2a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -43,6 +43,7 @@ id,region,name,tags,mod_name 44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", 45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", 46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +49,Pantry,Slime Farmer Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", @@ -51,7 +52,7 @@ id,region,name,tags,mod_name 55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -58,Fish Tank,Recycling Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +58,Fish Tank,Trash Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", @@ -62,6 +63,7 @@ id,region,name,tags,mod_name 66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +69,Boiler Room,Recycling Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", 72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index 1ed1a4a7edc8..895fce76b09b 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -238,8 +238,7 @@ class Mineral: geodes=(Geode.geode, Geode.omni)) orpiment = create_mineral("Orpiment", geodes=(Geode.geode, Geode.omni)) - petrified_slime = create_mineral("Petrified Slime", - geodes=(Geode.geode, Geode.omni)) + petrified_slime = create_mineral(Mineral.petrified_slime, Region.slime_hutch) thunder_egg = create_mineral("Thunder Egg", geodes=(Geode.geode, Geode.omni)) pyrite = create_mineral("Pyrite", diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 4406bfcf610e..12fb3c944542 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -35,11 +35,13 @@ class BundleName: orchard = "Orchard Bundle" island_crops = "Island Crops Bundle" agronomist = "Agronomist's Bundle" + slime_farmer = "Slime Farmer Bundle" river_fish = "River Fish Bundle" lake_fish = "Lake Fish Bundle" ocean_fish = "Ocean Fish Bundle" night_fish = "Night Fishing Bundle" crab_pot = "Crab Pot Bundle" + trash = "Trash Bundle" recycling = "Recycling Bundle" specialty_fish = "Specialty Fish Bundle" spring_fish = "Spring Fishing Bundle" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 2cd519aa3f4c..3828b7c28e2d 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -30,6 +30,7 @@ class MetalBar: class Mineral: + petrified_slime = "Petrified Slime" quartz = "Quartz" earth_crystal = "Earth Crystal" fire_quartz = "Fire Quartz" diff --git a/worlds/stardew_valley/strings/monster_drop_names.py b/worlds/stardew_valley/strings/monster_drop_names.py index 5f1830d595a0..c42e7ad5ede0 100644 --- a/worlds/stardew_valley/strings/monster_drop_names.py +++ b/worlds/stardew_valley/strings/monster_drop_names.py @@ -1,4 +1,9 @@ class Loot: + blue_slime_egg = "Blue Slime Egg" + red_slime_egg = "Red Slime Egg" + purple_slime_egg = "Purple Slime Egg" + green_slime_egg = "Green Slime Egg" + tiger_slime_egg = "Tiger Slime Egg" slime = "Slime" bug_meat = "Bug Meat" bat_wing = "Bat Wing" From ebb62bb68e3920103147afdec0ed6fe7e02318d1 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sat, 30 Dec 2023 00:13:43 -0500 Subject: [PATCH 373/482] - Movie ticket isn't ginger island! --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index fcffd8f99b2a..9b5e3faf7996 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1673,7 +1673,7 @@ id,region,name,tags,mod_name 2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", 2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", 2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Shipping,Shipsanity: Movie Ticket,"GINGER_ISLAND,SHIPSANITY", +2966,Shipping,Shipsanity: Movie Ticket,"SHIPSANITY", 2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", 2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", 2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", From 157e858b87a7e830669a9026cb815aa4da3b4358 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 30 Dec 2023 11:04:55 -0500 Subject: [PATCH 374/482] add count method with has --- worlds/stardew_valley/logic/has_logic.py | 15 +++--- worlds/stardew_valley/logic/logic.py | 53 ++++++++++--------- worlds/stardew_valley/logic/museum_logic.py | 8 +-- worlds/stardew_valley/logic/received_logic.py | 6 --- worlds/stardew_valley/logic/region_logic.py | 9 ++-- .../logic/relationship_logic.py | 4 +- .../stardew_valley/mods/logic/magic_logic.py | 9 ++-- .../stardew_valley/mods/logic/skills_logic.py | 6 +-- worlds/stardew_valley/stardew_rule/base.py | 26 +++------ 9 files changed, 61 insertions(+), 75 deletions(-) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index ae2293f1df77..ca91c084bc8a 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -5,12 +5,6 @@ class HasLogicMixin(BaseLogic[None]): - def __call__(self, *args, **kwargs) -> StardewRule: - count = None - if len(args) >= 2: - count = args[1] - return self.has(args[0], count) - # Should be cached def has(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = None) -> StardewRule: if isinstance(items, str): @@ -25,4 +19,11 @@ def has(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = None) - if count == 1: return Or(*(self.has(item) for item in items)) - return Count(count, (self.has(item) for item in items)) + return self.count(count, *(self.has(item) for item in items)) + + @staticmethod + def count(count: int, *rules: StardewRule) -> StardewRule: + assert rules, "Can't create a Count conditions without rules" + assert len(rules) >= count, "Count need at least as many rules at the count" + + return Count(list(rules), count) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 57b6eed283ce..89e2798e9681 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -46,7 +46,7 @@ from ..mods.logic.mod_logic import ModLogicMixin from ..mods.mod_data import ModNames from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity, StardewValleyOptions -from ..stardew_rule import False_, Or, True_, Count, And, StardewRule +from ..stardew_rule import False_, Or, True_, And, StardewRule from ..strings.animal_names import Animal, coop_animals, barn_animals from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.ap_weapon_names import APWeapon @@ -508,29 +508,30 @@ def can_complete_field_office(self) -> StardewRule: def can_finish_grandpa_evaluation(self) -> StardewRule: # https://stardewvalleywiki.com/Grandpa - rules_worth_a_point = [self.money.can_have_earned_total(50000), # 50 000g - self.money.can_have_earned_total(100000), # 100 000g - self.money.can_have_earned_total(200000), # 200 000g - self.money.can_have_earned_total(300000), # 300 000g - self.money.can_have_earned_total(500000), # 500 000g - self.money.can_have_earned_total(1000000), # 1 000 000g first point - self.money.can_have_earned_total(1000000), # 1 000 000g second point - self.skill.has_total_level(30), # Total Skills: 30 - self.skill.has_total_level(50), # Total Skills: 50 - self.museum.can_complete_museum(), # Completing the museum for a point - # Catching every fish not expected - # Shipping every item not expected - self.relationship.can_get_married() & self.building.has_house(2), - self.relationship.has_hearts("5", 8), # 5 Friends - self.relationship.has_hearts("10", 8), # 10 friends - self.pet.has_hearts(5), # Max Pet - self.bundle.can_complete_community_center, # Community Center Completion - self.bundle.can_complete_community_center, # CC Ceremony first point - self.bundle.can_complete_community_center, # CC Ceremony second point - self.received(Wallet.skull_key), # Skull Key obtained - self.wallet.has_rusty_key(), # Rusty key obtained - ] - return Count(12, rules_worth_a_point) + rules_worth_a_point = [ + self.money.can_have_earned_total(50000), # 50 000g + self.money.can_have_earned_total(100000), # 100 000g + self.money.can_have_earned_total(200000), # 200 000g + self.money.can_have_earned_total(300000), # 300 000g + self.money.can_have_earned_total(500000), # 500 000g + self.money.can_have_earned_total(1000000), # 1 000 000g first point + self.money.can_have_earned_total(1000000), # 1 000 000g second point + self.skill.has_total_level(30), # Total Skills: 30 + self.skill.has_total_level(50), # Total Skills: 50 + self.museum.can_complete_museum(), # Completing the museum for a point + # Catching every fish not expected + # Shipping every item not expected + self.relationship.can_get_married() & self.building.has_house(2), + self.relationship.has_hearts("5", 8), # 5 Friends + self.relationship.has_hearts("10", 8), # 10 friends + self.pet.has_hearts(5), # Max Pet + self.bundle.can_complete_community_center, # Community Center Completion + self.bundle.can_complete_community_center, # CC Ceremony first point + self.bundle.can_complete_community_center, # CC Ceremony second point + self.received(Wallet.skull_key), # Skull Key obtained + self.wallet.has_rusty_key(), # Rusty key obtained + ] + return self.count(12, *rules_worth_a_point) def can_complete_all_monster_slaying_goals(self) -> StardewRule: rules = [self.time.has_lived_max_months] @@ -672,9 +673,9 @@ def has_walnut(self, number: int) -> StardewRule: if number <= 5: return Or(reach_south, reach_north, reach_west, reach_volcano) if number <= 10: - return Count(2, reach_walnut_regions) + return self.count(2, *reach_walnut_regions) if number <= 15: - return Count(3, reach_walnut_regions) + return self.count(3, *reach_walnut_regions) if number <= 20: return And(*reach_walnut_regions) if number <= 50: diff --git a/worlds/stardew_valley/logic/museum_logic.py b/worlds/stardew_valley/logic/museum_logic.py index 29129f6cee55..285916bb41c9 100644 --- a/worlds/stardew_valley/logic/museum_logic.py +++ b/worlds/stardew_valley/logic/museum_logic.py @@ -8,7 +8,7 @@ from .region_logic import RegionLogicMixin from .. import options from ..data.museum_data import MuseumItem, all_museum_items, all_museum_artifacts, all_museum_minerals -from ..stardew_rule import StardewRule, And, False_, Count, true_ +from ..stardew_rule import StardewRule, And, False_ from ..strings.region_names import Region @@ -48,21 +48,21 @@ def can_find_museum_artifacts(self, number: int) -> StardewRule: for artifact in all_museum_artifacts: rules.append(self.logic.museum.can_find_museum_item(artifact)) - return Count(number, rules) + return self.logic.count(number, *rules) def can_find_museum_minerals(self, number: int) -> StardewRule: rules = [] for mineral in all_museum_minerals: rules.append(self.logic.museum.can_find_museum_item(mineral)) - return Count(number, rules) + return self.logic.count(number, *rules) def can_find_museum_items(self, number: int) -> StardewRule: rules = [] for donation in all_museum_items: rules.append(self.logic.museum.can_find_museum_item(donation)) - return Count(number, rules) + return self.logic.count(number, *rules) def can_complete_museum(self) -> StardewRule: rules = [self.logic.region.can_reach(Region.museum)] diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 2b35e4e21cbe..5f11785c0a34 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -5,12 +5,6 @@ class ReceivedLogicMixin(BaseLogic[None], BaseLogicMixin): - def __call__(self, *args, **kwargs) -> StardewRule: - count = 1 - if len(args) >= 2: - count = args[1] - return self.received(args[0], count) - # Should be cached def received(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = 1) -> StardewRule: if count <= 0 or not items: diff --git a/worlds/stardew_valley/logic/region_logic.py b/worlds/stardew_valley/logic/region_logic.py index 12697e760bd0..a7e718a23c18 100644 --- a/worlds/stardew_valley/logic/region_logic.py +++ b/worlds/stardew_valley/logic/region_logic.py @@ -1,9 +1,10 @@ -from typing import Tuple +from typing import Tuple, Union from Utils import cache_self1 from .base_logic import BaseLogic, BaseLogicMixin +from .has_logic import HasLogicMixin from ..options import EntranceRandomization -from ..stardew_rule import StardewRule, And, Or, Reach, Count, True_ +from ..stardew_rule import StardewRule, And, Or, Reach, True_ from ..strings.region_names import Region main_outside_area = {Region.menu, Region.stardew_valley, Region.farm_house, Region.farm, Region.town, Region.beach, Region.mountain, Region.forest, @@ -27,7 +28,7 @@ def __init__(self, *args, **kwargs): self.region = RegionLogic(*args, **kwargs) -class RegionLogic(BaseLogic[RegionLogicMixin]): +class RegionLogic(BaseLogic[Union[RegionLogicMixin, HasLogicMixin]]): @cache_self1 def can_reach(self, region_name: str) -> StardewRule: @@ -50,7 +51,7 @@ def can_reach_all_except_one(self, region_names: Tuple[str, ...]) -> StardewRule num_required = len(region_names) - 1 if num_required <= 0: num_required = len(region_names) - return Count(num_required, [self.logic.region.can_reach(spot) for spot in region_names]) + return self.logic.count(num_required, *(self.logic.region.can_reach(spot) for spot in region_names)) @cache_self1 def can_reach_location(self, location_name: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 7f71921e5c7a..1e06019feb49 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -12,7 +12,7 @@ from .time_logic import TimeLogicMixin from ..data.villagers_data import all_villagers_by_name, Villager from ..options import Friendsanity -from ..stardew_rule import StardewRule, True_, And, Or, Count +from ..stardew_rule import StardewRule, True_, And, Or from ..strings.ap_names.mods.mod_items import SVEQuestItem from ..strings.crop_names import Fruit from ..strings.generic_names import Generic @@ -84,7 +84,7 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: if not self.npc_is_in_current_slot(name): continue possible_friends.append(self.logic.relationship.has_hearts(name, hearts)) - return Count(int(npc), possible_friends) + return self.logic.count(int(npc), *possible_friends) return self.can_earn_relationship(npc, hearts) if not self.npc_is_in_current_slot(npc): diff --git a/worlds/stardew_valley/mods/logic/magic_logic.py b/worlds/stardew_valley/mods/logic/magic_logic.py index 164780f63194..99482b063056 100644 --- a/worlds/stardew_valley/mods/logic/magic_logic.py +++ b/worlds/stardew_valley/mods/logic/magic_logic.py @@ -1,10 +1,11 @@ from typing import Union from ...logic.base_logic import BaseLogicMixin, BaseLogic +from ...logic.has_logic import HasLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...mods.mod_data import ModNames -from ...stardew_rule import Count, StardewRule, False_ +from ...stardew_rule import StardewRule, False_ from ...strings.ap_names.skill_level_names import ModSkillLevel from ...strings.region_names import MagicRegion from ...strings.spells import MagicSpell @@ -17,7 +18,7 @@ def __init__(self, *args, **kwargs): # TODO add logic.mods.magic for altar -class MagicLogic(BaseLogic[Union[RegionLogicMixin, ReceivedLogicMixin]]): +class MagicLogic(BaseLogic[Union[RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): def can_use_clear_debris_instead_of_tool_level(self, level: int) -> StardewRule: if ModNames.magic not in self.options.mods: return False_() @@ -36,13 +37,13 @@ def has_any_spell(self) -> StardewRule: def has_attack_spell_count(self, count: int) -> StardewRule: attack_spell_rule = [self.logic.received(MagicSpell.fireball), self.logic.received(MagicSpell.frostbite), self.logic.received(MagicSpell.shockwave), self.logic.received(MagicSpell.spirit), self.logic.received(MagicSpell.meteor)] - return Count(count, attack_spell_rule) + return self.logic.count(count, *attack_spell_rule) def has_support_spell_count(self, count: int) -> StardewRule: support_spell_rule = [self.can_use_altar(), self.logic.received(ModSkillLevel.magic_level, 2), self.logic.received(MagicSpell.descend), self.logic.received(MagicSpell.heal), self.logic.received(MagicSpell.tendrils)] - return Count(count, support_spell_rule) + return self.logic.count(count, *support_spell_rule) def has_decent_spells(self) -> StardewRule: if ModNames.magic not in self.options.mods: diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 13c3f8633c32..a32fecd8ff0c 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -14,7 +14,7 @@ from ...logic.tool_logic import ToolLogicMixin from ...mods.mod_data import ModNames from ...options import SkillProgression -from ...stardew_rule import Count, StardewRule, False_, True_ +from ...stardew_rule import StardewRule, False_, True_ from ...strings.building_names import Building from ...strings.geode_names import Geode from ...strings.machine_names import Machine @@ -70,14 +70,14 @@ def can_earn_magic_skill_level(self, level: int) -> StardewRule: self.logic.received(MagicSpell.shockwave), self.logic.received(MagicSpell.meteor), self.logic.received(MagicSpell.spirit)] - return Count(level, spell_count) + return self.logic.count(level, *spell_count) def can_earn_socializing_skill_level(self, level: int) -> StardewRule: villager_count = [] for villager in all_villagers: if villager.mod_name in self.options.mods or villager.mod_name is None: villager_count.append(self.logic.relationship.can_earn_relationship(villager.name, level)) - return Count(level * 2, villager_count) + return self.logic.count(level * 2, *villager_count) def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: if level >= 6: diff --git a/worlds/stardew_valley/stardew_rule/base.py b/worlds/stardew_valley/stardew_rule/base.py index d195d7c06113..06097f1118a6 100644 --- a/worlds/stardew_valley/stardew_rule/base.py +++ b/worlds/stardew_valley/stardew_rule/base.py @@ -3,6 +3,7 @@ import logging from abc import ABC, abstractmethod from collections import deque +from functools import cached_property from itertools import chain from threading import Lock from typing import Iterable, Dict, List, Union, Sized, Hashable, Callable, Tuple, Set, Optional @@ -364,27 +365,10 @@ def get_difficulty(self): class Count(BaseStardewRule): count: int rules: List[StardewRule] - rules_count: int - _simplified: bool - def __init__(self, count: int, rule: Union[StardewRule, Iterable[StardewRule]], *rules: StardewRule): - rules_list: List[StardewRule] - - if isinstance(rule, Iterable): - rules_list = [*rule] - else: - rules_list = [rule] - - if rules is not None: - rules_list.extend(rules) - - assert rules_list, "Can't create a Count conditions without rules" - assert len(rules_list) >= count, "Count need at least as many rules at the count" - - self.rules = rules_list + def __init__(self, rules: List[StardewRule], count: int): + self.rules = rules self.count = count - self.rules_count = len(rules_list) - self._simplified = False def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: c = 0 @@ -403,6 +387,10 @@ def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRul def __call__(self, state: CollectionState) -> bool: return self.evaluate_while_simplifying(state)[1] + @cached_property + def rules_count(self): + return len(self.rules) + def explain(self, state: CollectionState, expected=True) -> RuleExplanation: return RuleExplanation(self, state, expected, self.rules) From 51302fe0f6fd7e25883f2802c36d7af5021645f2 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 30 Dec 2023 14:42:57 -0500 Subject: [PATCH 375/482] split logic.received for clarity --- worlds/stardew_valley/logic/arcade_logic.py | 2 +- worlds/stardew_valley/logic/building_logic.py | 5 ++-- worlds/stardew_valley/logic/combat_logic.py | 2 +- worlds/stardew_valley/logic/crafting_logic.py | 4 +-- worlds/stardew_valley/logic/money_logic.py | 9 +++--- worlds/stardew_valley/logic/received_logic.py | 28 +++++++++++-------- .../logic/relationship_logic.py | 16 ++++++----- worlds/stardew_valley/logic/skill_logic.py | 6 ++-- worlds/stardew_valley/logic/tool_logic.py | 4 +-- .../logic/traveling_merchant_logic.py | 2 +- 10 files changed, 42 insertions(+), 36 deletions(-) diff --git a/worlds/stardew_valley/logic/arcade_logic.py b/worlds/stardew_valley/logic/arcade_logic.py index a5d839a2a25c..5e6a02a18435 100644 --- a/worlds/stardew_valley/logic/arcade_logic.py +++ b/worlds/stardew_valley/logic/arcade_logic.py @@ -20,7 +20,7 @@ def has_jotpk_power_level(self, power_level: int) -> StardewRule: if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: return True_() jotpk_buffs = ("JotPK: Progressive Boots", "JotPK: Progressive Gun", "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate") - return self.logic.received(jotpk_buffs, power_level) + return self.logic.received_n(*jotpk_buffs, count=power_level) def has_junimo_kart_power_level(self, power_level: int) -> StardewRule: if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling: diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index e88e6531c2b7..80ea099152b3 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -14,7 +14,6 @@ from ..strings.fish_names import WaterItem from ..strings.material_names import Material from ..strings.metal_names import MetalBar -from ..strings.region_names import Region class BuildingLogicMixin(BaseLogicMixin): @@ -57,7 +56,7 @@ def has_building(self, building: str) -> StardewRule: if building is Building.shipping_bin: if not self.options.building_progression & BuildingProgression.option_progressive: return True_() - return self.logic.received(f"{building}") + return self.logic.received(building) carpenter_rule = self.logic.received(Event.can_construct_buildings) if not self.options.building_progression & BuildingProgression.option_progressive: @@ -72,7 +71,7 @@ def has_building(self, building: str) -> StardewRule: elif building.startswith("Deluxe"): count = 3 building = " ".join(["Progressive", *building.split(" ")[1:]]) - return self.logic.received(f"{building}", count) & carpenter_rule + return self.logic.received(building, count) & carpenter_rule @cache_self1 def has_house(self, upgrade_level: int) -> StardewRule: diff --git a/worlds/stardew_valley/logic/combat_logic.py b/worlds/stardew_valley/logic/combat_logic.py index 11599b433833..ba825192a99e 100644 --- a/worlds/stardew_valley/logic/combat_logic.py +++ b/worlds/stardew_valley/logic/combat_logic.py @@ -38,7 +38,7 @@ def can_fight_at_level(self, level: str) -> StardewRule: @cached_property def has_any_weapon(self) -> StardewRule: - return self.logic.received(valid_weapons, 1) + return self.logic.received_any(*valid_weapons) @cached_property def has_decent_weapon(self) -> StardewRule: diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index c32a52fce94e..9d815f756ba6 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -42,7 +42,7 @@ def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: @cache_self1 def knows_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, ArchipelagoSource): - return self.logic.received(recipe.source.ap_item, len(recipe.source.ap_item)) + return self.logic.received_all(*recipe.source.ap_item) if isinstance(recipe.source, FestivalShopSource): if self.options.festival_locations == options.FestivalLocations.option_disabled: return self.logic.crafting.can_learn_recipe(recipe) @@ -67,7 +67,7 @@ def can_learn_recipe(self, recipe: CraftingRecipe) -> StardewRule: if isinstance(recipe.source, StarterSource): return True_() if isinstance(recipe.source, ArchipelagoSource): - return self.logic.received(recipe.source.ap_item, len(recipe.source.ap_item)) + return self.logic.received_all(*recipe.source.ap_item) if isinstance(recipe.source, ShopTradeSource): return self.logic.money.can_trade_at(recipe.source.region, recipe.source.currency, recipe.source.price) if isinstance(recipe.source, ShopSource): diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index cf77ca5c0e67..7325374002fa 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -9,10 +9,9 @@ from .time_logic import TimeLogicMixin from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, HasProgressionPercent, False_ +from ..strings.ap_names.event_names import Event from ..strings.currency_names import Currency -from ..strings.machine_names import Machine from ..strings.region_names import Region -from ..strings.ap_names.event_names import Event qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems", "20 Qi Gems", "15 Qi Gems", "10 Qi Gems") @@ -78,10 +77,10 @@ def can_trade(self, currency: str, amount: int) -> StardewRule: if currency == Currency.qi_gem: if self.options.special_order_locations == SpecialOrderLocations.option_board_qi: number_rewards = min(len(qi_gem_rewards), max(1, (amount // 10))) - return self.logic.received(qi_gem_rewards, number_rewards) + return self.logic.received_n(*qi_gem_rewards, count=number_rewards) number_rewards = 2 - return self.logic.received(qi_gem_rewards, number_rewards) & self.logic.region.can_reach(Region.qi_walnut_room) & \ - self.logic.region.can_reach(Region.saloon) & self.can_have_earned_total(5000) + return self.logic.received_n(*qi_gem_rewards, count=number_rewards) & self.logic.region.can_reach(Region.qi_walnut_room) & \ + self.logic.region.can_reach(Region.saloon) & self.can_have_earned_total(5000) if currency == Currency.golden_walnut: return self.can_spend_walnut(amount) diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 5f11785c0a34..71e6dd65c304 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,22 +1,28 @@ -from typing import Union, Optional, Tuple +from typing import Optional from .base_logic import BaseLogic, BaseLogicMixin -from ..stardew_rule import StardewRule, True_, Received, And, Or, TotalReceived +from ..stardew_rule import StardewRule, Received, And, Or, TotalReceived class ReceivedLogicMixin(BaseLogic[None], BaseLogicMixin): # Should be cached - def received(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = 1) -> StardewRule: - if count <= 0 or not items: - return True_() + def received(self, item: str, count: Optional[int] = 1) -> StardewRule: + assert count >= 0, "Can't receive a negative amount of item." - if isinstance(items, str): - return Received(items, self.player, count) + return Received(item, self.player, count) - if count is None: - return And(*(self.received(item) for item in items)) + def received_all(self, *items: str): + assert items, "Can't receive all of no items." - if count == 1: - return Or(*(self.received(item) for item in items)) + return And(*(self.received(item) for item in items)) + + def received_any(self, *items: str): + assert items, "Can't receive any of no items." + + return Or(*(self.received(item) for item in items)) + + def received_n(self, *items: str, count: int): + assert items, "Can't receive n of no items." + assert count >= 0, "Can't receive a negative amount of item." return TotalReceived(count, items, self.player) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 1e06019feb49..5baf6bf58458 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -24,6 +24,13 @@ possible_kids = ("Cute Baby", "Ugly Baby") +def heart_item_name(npc: Union[str, Villager]) -> str: + if isinstance(npc, Villager): + npc = npc.name + + return f"{npc} <3" + + class RelationshipLogicMixin(BaseLogicMixin): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -47,7 +54,7 @@ def has_children(self, number_children: int) -> StardewRule: return True_() if self.options.friendsanity == Friendsanity.option_none: return self.logic.relationship.can_reproduce(number_children) - return self.logic.received(possible_kids, number_children) & self.logic.building.has_house(2) + return self.logic.received_n(*possible_kids, count=number_children) & self.logic.building.has_house(2) def can_reproduce(self, number_children: int = 1) -> StardewRule: if number_children <= 0: @@ -101,7 +108,7 @@ def has_hearts(self, npc: str, hearts: int = 1) -> StardewRule: # Should be cached def received_hearts(self, npc: str, hearts: int) -> StardewRule: - heart_item = self.heart(npc) + heart_item = heart_item_name(npc) number_required = math.ceil(hearts / self.options.friendsanity_heart_size) return self.logic.received(heart_item, number_required) @@ -168,8 +175,3 @@ def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] mod = npc.mod_name return mod is None or mod in self.options.mods - - def heart(self, npc: Union[str, Villager]) -> str: - if isinstance(npc, str): - return f"{npc} <3" - return self.heart(npc.name) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index b7cd051ac0ab..77a1ec72225f 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -2,7 +2,6 @@ from typing import Union, Tuple from Utils import cache_self1 -from ..strings.craftable_names import Fishing from .base_logic import BaseLogicMixin, BaseLogic from .combat_logic import CombatLogicMixin from .crop_logic import CropLogicMixin @@ -17,6 +16,7 @@ from ..mods.logic.magic_logic import MagicLogicMixin from ..mods.logic.mod_skills_levels import get_mod_skill_levels from ..stardew_rule import StardewRule, True_, Or, False_ +from ..strings.craftable_names import Fishing from ..strings.machine_names import Machine from ..strings.performance_names import Performance from ..strings.quality_names import ForageQuality @@ -34,7 +34,7 @@ def __init__(self, *args, **kwargs): class SkillLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, ToolLogicMixin, SkillLogicMixin, - CombatLogicMixin, CropLogicMixin, MagicLogicMixin]]): +CombatLogicMixin, CropLogicMixin, MagicLogicMixin]]): # Should be cached def can_earn_level(self, skill: str, level: int) -> StardewRule: if level <= 0: @@ -89,7 +89,7 @@ def has_total_level(self, level: int, allow_modded_skills: bool = False) -> Star skills_items = ("Farming Level", "Mining Level", "Foraging Level", "Fishing Level", "Combat Level") if allow_modded_skills: skills_items += get_mod_skill_levels(self.options.mods) - return self.logic.received(skills_items, level) + return self.logic.received_n(*skills_items, count=level) months_with_4_skills = max(1, (level // 4) - 1) months_with_5_skills = max(1, (level // 5) - 1) diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index dfa15a5bb07c..92d85c10f392 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -10,8 +10,8 @@ from ..mods.logic.magic_logic import MagicLogicMixin from ..options import ToolProgression from ..stardew_rule import StardewRule, True_ +from ..strings.ap_names.skill_level_names import ModSkillLevel from ..strings.region_names import Region -from ..strings.skill_names import ModSkill from ..strings.spells import MagicSpell from ..strings.tool_names import ToolMaterial, Tool @@ -69,5 +69,5 @@ def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = @cache_self1 def can_water(self, level: int) -> StardewRule: tool_rule = self.logic.tool.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) - spell_rule = self.logic.received(MagicSpell.water) & self.logic.magic.can_use_altar() & self.logic.received(f"{ModSkill.magic} Level", level) + spell_rule = self.logic.received(MagicSpell.water) & self.logic.magic.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, level) return tool_rule | spell_rule diff --git a/worlds/stardew_valley/logic/traveling_merchant_logic.py b/worlds/stardew_valley/logic/traveling_merchant_logic.py index 7467c79718fc..ee1c24203e4f 100644 --- a/worlds/stardew_valley/logic/traveling_merchant_logic.py +++ b/worlds/stardew_valley/logic/traveling_merchant_logic.py @@ -19,4 +19,4 @@ def has_days(self, number_days: int = 1): return True_() tier = min(7, max(1, number_days)) traveling_merchant_days = tuple(f"Traveling Merchant: {day}" for day in Weekday.all_days) - return self.logic.received(traveling_merchant_days, tier) + return self.logic.received_n(*traveling_merchant_days, count=tier) From f679f483f2326a69e6d4b578b2d064326412094d Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 30 Dec 2023 19:58:51 -0500 Subject: [PATCH 376/482] split has --- worlds/stardew_valley/logic/artisan_logic.py | 8 ++--- worlds/stardew_valley/logic/building_logic.py | 24 +++++++------- worlds/stardew_valley/logic/bundle_logic.py | 2 +- worlds/stardew_valley/logic/cooking_logic.py | 2 +- worlds/stardew_valley/logic/crafting_logic.py | 2 +- worlds/stardew_valley/logic/gift_logic.py | 2 +- worlds/stardew_valley/logic/has_logic.py | 31 +++++++++++-------- worlds/stardew_valley/logic/logic.py | 22 ++++++------- worlds/stardew_valley/logic/quest_logic.py | 16 +++++----- worlds/stardew_valley/logic/received_logic.py | 9 +++++- worlds/stardew_valley/logic/shipping_logic.py | 6 ++-- .../logic/special_order_logic.py | 14 ++++----- .../mods/logic/buildings_logic.py | 4 +-- .../stardew_valley/mods/logic/quests_logic.py | 17 +++++----- worlds/stardew_valley/rules.py | 10 +++--- 15 files changed, 89 insertions(+), 80 deletions(-) diff --git a/worlds/stardew_valley/logic/artisan_logic.py b/worlds/stardew_valley/logic/artisan_logic.py index 6ac8a2d88677..cdc2186d807a 100644 --- a/worlds/stardew_valley/logic/artisan_logic.py +++ b/worlds/stardew_valley/logic/artisan_logic.py @@ -28,9 +28,9 @@ def can_preserves_jar(self, item: str) -> StardewRule: if item == Generic.any: return machine_rule if item == Fruit.any: - return machine_rule & self.logic.has(all_fruits, 1) + return machine_rule & self.logic.has_any(*all_fruits) if item == Vegetable.any: - return machine_rule & self.logic.has(all_vegetables, 1) + return machine_rule & self.logic.has_any(*all_vegetables) return machine_rule & self.logic.has(item) def has_wine(self) -> StardewRule: @@ -44,9 +44,9 @@ def can_keg(self, item: str) -> StardewRule: if item == Generic.any: return machine_rule if item == Fruit.any: - return machine_rule & self.logic.has(all_fruits, 1) + return machine_rule & self.logic.has_any(*all_fruits) if item == Vegetable.any: - return machine_rule & self.logic.has(all_vegetables, 1) + return machine_rule & self.logic.has_any(*all_vegetables) return machine_rule & self.logic.has(item) def can_mayonnaise(self, item: str) -> StardewRule: diff --git a/worlds/stardew_valley/logic/building_logic.py b/worlds/stardew_valley/logic/building_logic.py index 80ea099152b3..7be3d19ec33b 100644 --- a/worlds/stardew_valley/logic/building_logic.py +++ b/worlds/stardew_valley/logic/building_logic.py @@ -26,19 +26,19 @@ class BuildingLogic(BaseLogic[Union[BuildingLogicMixin, MoneyLogicMixin, RegionL def initialize_rules(self): self.registry.building_rules.update({ # @formatter:off - Building.barn: self.logic.money.can_spend(6000) & self.logic.has((Material.wood, Material.stone)), - Building.big_barn: self.logic.money.can_spend(12000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.barn), - Building.deluxe_barn: self.logic.money.can_spend(25000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.big_barn), - Building.coop: self.logic.money.can_spend(4000) & self.logic.has((Material.wood, Material.stone)), - Building.big_coop: self.logic.money.can_spend(10000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.coop), - Building.deluxe_coop: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.big_coop), - Building.fish_pond: self.logic.money.can_spend(5000) & self.logic.has((Material.stone, WaterItem.seaweed, WaterItem.green_algae)), - Building.mill: self.logic.money.can_spend(2500) & self.logic.has((Material.stone, Material.wood, ArtisanGood.cloth)), + Building.barn: self.logic.money.can_spend(6000) & self.logic.has_all(Material.wood, Material.stone), + Building.big_barn: self.logic.money.can_spend(12000) & self.logic.has_all(Material.wood, Material.stone) & self.logic.building.has_building(Building.barn), + Building.deluxe_barn: self.logic.money.can_spend(25000) & self.logic.has_all(Material.wood, Material.stone) & self.logic.building.has_building(Building.big_barn), + Building.coop: self.logic.money.can_spend(4000) & self.logic.has_all(Material.wood, Material.stone), + Building.big_coop: self.logic.money.can_spend(10000) & self.logic.has_all(Material.wood, Material.stone) & self.logic.building.has_building(Building.coop), + Building.deluxe_coop: self.logic.money.can_spend(20000) & self.logic.has_all(Material.wood, Material.stone) & self.logic.building.has_building(Building.big_coop), + Building.fish_pond: self.logic.money.can_spend(5000) & self.logic.has_all(Material.stone, WaterItem.seaweed, WaterItem.green_algae), + Building.mill: self.logic.money.can_spend(2500) & self.logic.has_all(Material.stone, Material.wood, ArtisanGood.cloth), Building.shed: self.logic.money.can_spend(15000) & self.logic.has(Material.wood), - Building.big_shed: self.logic.money.can_spend(20000) & self.logic.has((Material.wood, Material.stone)) & self.logic.building.has_building(Building.shed), - Building.silo: self.logic.money.can_spend(100) & self.logic.has((Material.stone, Material.clay, MetalBar.copper)), - Building.slime_hutch: self.logic.money.can_spend(10000) & self.logic.has((Material.stone, MetalBar.quartz, MetalBar.iridium)), - Building.stable: self.logic.money.can_spend(10000) & self.logic.has((Material.hardwood, MetalBar.iron)), + Building.big_shed: self.logic.money.can_spend(20000) & self.logic.has_all(Material.wood, Material.stone) & self.logic.building.has_building(Building.shed), + Building.silo: self.logic.money.can_spend(100) & self.logic.has_all(Material.stone, Material.clay, MetalBar.copper), + Building.slime_hutch: self.logic.money.can_spend(10000) & self.logic.has_all(Material.stone, MetalBar.quartz, MetalBar.iridium), + Building.stable: self.logic.money.can_spend(10000) & self.logic.has_all(Material.hardwood, MetalBar.iron), Building.well: self.logic.money.can_spend(1000) & self.logic.has(Material.stone), Building.shipping_bin: self.logic.money.can_spend(250) & self.logic.has(Material.wood), Building.kitchen: self.logic.money.can_spend(10000) & self.logic.has(Material.wood) & self.logic.building.has_house(0), diff --git a/worlds/stardew_valley/logic/bundle_logic.py b/worlds/stardew_valley/logic/bundle_logic.py index 4ff83eeb2c56..1ae07cf2ed82 100644 --- a/worlds/stardew_valley/logic/bundle_logic.py +++ b/worlds/stardew_valley/logic/bundle_logic.py @@ -35,7 +35,7 @@ def can_complete_bundle(self, bundle: Bundle) -> StardewRule: item_rules.append(bundle_item.item_name) qualities.append(bundle_item.quality) quality_rules = self.get_quality_rules(qualities) - item_rules = self.logic.has(tuple(item_rules), bundle.number_required) + item_rules = self.logic.has_n(*item_rules, count=bundle.number_required) return can_speak_junimo & item_rules & quality_rules def get_quality_rules(self, qualities: List[str]) -> StardewRule: diff --git a/worlds/stardew_valley/logic/cooking_logic.py b/worlds/stardew_valley/logic/cooking_logic.py index 20e86fea5de1..55027c36fa8d 100644 --- a/worlds/stardew_valley/logic/cooking_logic.py +++ b/worlds/stardew_valley/logic/cooking_logic.py @@ -44,7 +44,7 @@ def can_cook(self, recipe: CookingRecipe = None) -> StardewRule: return cook_rule recipe_rule = self.logic.cooking.knows_recipe(recipe.source, recipe.meal) - ingredients_rule = And(*(self.logic.has(ingredient) for ingredient in recipe.ingredients)) + ingredients_rule = self.logic.has_all(*recipe.ingredients) return cook_rule & recipe_rule & ingredients_rule # Should be cached diff --git a/worlds/stardew_valley/logic/crafting_logic.py b/worlds/stardew_valley/logic/crafting_logic.py index 9d815f756ba6..8c267b7d1090 100644 --- a/worlds/stardew_valley/logic/crafting_logic.py +++ b/worlds/stardew_valley/logic/crafting_logic.py @@ -36,7 +36,7 @@ def can_craft(self, recipe: CraftingRecipe = None) -> StardewRule: return True_() learn_rule = self.logic.crafting.knows_recipe(recipe) - ingredients_rule = And(*(self.logic.has(ingredient) for ingredient in recipe.ingredients)) + ingredients_rule = self.logic.has_all(*recipe.ingredients) return learn_rule & ingredients_rule @cache_self1 diff --git a/worlds/stardew_valley/logic/gift_logic.py b/worlds/stardew_valley/logic/gift_logic.py index 29be419a6d2b..527da6876411 100644 --- a/worlds/stardew_valley/logic/gift_logic.py +++ b/worlds/stardew_valley/logic/gift_logic.py @@ -17,4 +17,4 @@ class GiftLogic(BaseLogic[HasLogicMixin]): @cached_property def has_any_universal_love(self) -> StardewRule: - return self.logic.has(Gift.golden_pumpkin) | self.logic.has(Gift.pearl) | self.logic.has("Prismatic Shard") | self.logic.has(AnimalProduct.rabbit_foot) + return self.logic.has_any(Gift.golden_pumpkin, Gift.pearl, "Prismatic Shard", AnimalProduct.rabbit_foot) diff --git a/worlds/stardew_valley/logic/has_logic.py b/worlds/stardew_valley/logic/has_logic.py index ca91c084bc8a..d92d4224d7d2 100644 --- a/worlds/stardew_valley/logic/has_logic.py +++ b/worlds/stardew_valley/logic/has_logic.py @@ -1,29 +1,34 @@ -from typing import Union, Optional, Tuple - from .base_logic import BaseLogic -from ..stardew_rule import StardewRule, True_, And, Or, Has, Count +from ..stardew_rule import StardewRule, And, Or, Has, Count class HasLogicMixin(BaseLogic[None]): # Should be cached - def has(self, items: Union[str, Tuple[str, ...]], count: Optional[int] = None) -> StardewRule: - if isinstance(items, str): - return Has(items, self.registry.item_rules) + def has(self, item: str) -> StardewRule: + return Has(item, self.registry.item_rules) - if len(items) == 0: - return True_() + def has_all(self, *items: str): + assert items, "Can't have all of no items." - if count is None or count == len(items): - return And(*(self.has(item) for item in items)) + return And(*(self.has(item) for item in items)) - if count == 1: - return Or(*(self.has(item) for item in items)) + def has_any(self, *items: str): + assert items, "Can't have any of no items." + + return Or(*(self.has(item) for item in items)) + def has_n(self, *items: str, count: int): return self.count(count, *(self.has(item) for item in items)) @staticmethod def count(count: int, *rules: StardewRule) -> StardewRule: assert rules, "Can't create a Count conditions without rules" - assert len(rules) >= count, "Count need at least as many rules at the count" + assert len(rules) >= count, "Count need at least as many rules as the count" + + if count == 1: + return Or(*rules) + + if count == len(rules): + return And(*rules) return Count(list(rules), count) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 89e2798e9681..f03b123ee400 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -185,10 +185,10 @@ def __init__(self, player: int, options: StardewValleyOptions): Animal.pig: self.can_buy_animal(Animal.pig), Animal.rabbit: self.can_buy_animal(Animal.rabbit), Animal.sheep: self.can_buy_animal(Animal.sheep), - AnimalProduct.any_egg: self.has(AnimalProduct.chicken_egg) | self.has(AnimalProduct.duck_egg), + AnimalProduct.any_egg: self.has_any(AnimalProduct.chicken_egg, AnimalProduct.duck_egg), AnimalProduct.brown_egg: self.has_animal(Animal.chicken), - AnimalProduct.chicken_egg: self.has((AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg), 1), - AnimalProduct.cow_milk: self.has(AnimalProduct.milk) | self.has(AnimalProduct.large_milk), + AnimalProduct.chicken_egg: self.has_any(AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg), + AnimalProduct.cow_milk: self.has_any(AnimalProduct.milk, AnimalProduct.large_milk), AnimalProduct.duck_egg: self.has_animal(Animal.duck), AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), AnimalProduct.egg: self.has_animal(Animal.chicken), @@ -497,8 +497,8 @@ def can_complete_field_office(self) -> StardewRule: field_office = self.region.can_reach(Region.field_office) professor_snail = self.received("Open Professor Snail Cave") tools = self.tool.has_tool(Tool.pickaxe) & self.tool.has_tool(Tool.hoe) & self.tool.has_tool(Tool.scythe) - leg_and_snake_skull = self.has(Fossil.fossilized_leg) & self.has(Fossil.snake_skull) - ribs_and_spine = self.has(Fossil.fossilized_ribs) & self.has(Fossil.fossilized_spine) + leg_and_snake_skull = self.has_all(Fossil.fossilized_leg, Fossil.snake_skull) + ribs_and_spine = self.has_all(Fossil.fossilized_ribs, Fossil.fossilized_spine) skull = self.has(Fossil.fossilized_skull) tail = self.has(Fossil.fossilized_tail) frog = self.has(Fossil.mummified_frog) @@ -555,15 +555,15 @@ def can_succeed_luau_soup(self) -> StardewRule: return True_() eligible_fish = [Fish.blobfish, Fish.crimsonfish, "Ice Pip", Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish, Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, "Super Cucumber"] - fish_rule = [self.has(fish) for fish in eligible_fish] + fish_rule = self.has_any(*eligible_fish) eligible_kegables = [Fruit.ancient_fruit, Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.melon, Fruit.orange, Fruit.peach, Fruit.pineapple, Fruit.pomegranate, Fruit.rhubarb, Fruit.starfruit, Fruit.strawberry, Forageable.cactus_fruit, Fruit.cherry, Fruit.cranberries, Fruit.grape, Forageable.spice_berry, Forageable.wild_plum, Vegetable.hops, Vegetable.wheat] keg_rules = [self.artisan.can_keg(kegable) for kegable in eligible_kegables] aged_rule = self.has(Machine.cask) & Or(*keg_rules) - # There are a few other valid items but I don't feel like coding them all - return Or(*fish_rule) | aged_rule + # There are a few other valid items, but I don't feel like coding them all + return fish_rule | aged_rule def can_succeed_grange_display(self) -> StardewRule: if self.options.festival_locations != FestivalLocations.option_hard: @@ -576,10 +576,10 @@ def can_succeed_grange_display(self) -> StardewRule: mineral_rule = self.action.can_open_geode(Generic.any) # More than half the minerals are good enough good_fruits = [Fruit.apple, Fruit.banana, Forageable.coconut, Forageable.crystal_fruit, Fruit.mango, Fruit.orange, Fruit.peach, Fruit.pomegranate, Fruit.strawberry, Fruit.melon, Fruit.rhubarb, Fruit.pineapple, Fruit.ancient_fruit, Fruit.starfruit, ] - fruit_rule = Or(*(self.has(fruit) for fruit in good_fruits)) + fruit_rule = self.has_any(*good_fruits) good_vegetables = [Vegetable.amaranth, Vegetable.artichoke, Vegetable.beet, Vegetable.cauliflower, Forageable.fiddlehead_fern, Vegetable.kale, Vegetable.radish, Vegetable.taro_root, Vegetable.yam, Vegetable.red_cabbage, Vegetable.pumpkin] - vegetable_rule = Or(*(self.has(vegetable) for vegetable in good_vegetables)) + vegetable_rule = self.has_any(*good_vegetables) return animal_rule & artisan_rule & cooking_rule & fish_rule & \ forage_rule & fruit_rule & mineral_rule & vegetable_rule @@ -681,7 +681,7 @@ def has_walnut(self, number: int) -> StardewRule: if number <= 50: return reach_entire_island gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz) - return reach_entire_island & self.has(Fruit.banana) & self.has(gems) & self.ability.can_mine_perfectly() & \ + return reach_entire_island & self.has(Fruit.banana) & self.has_all(*gems) & self.ability.can_mine_perfectly() & \ self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) & \ self.can_complete_field_office() diff --git a/worlds/stardew_valley/logic/quest_logic.py b/worlds/stardew_valley/logic/quest_logic.py index 4b35d59872a8..bc1f731429c6 100644 --- a/worlds/stardew_valley/logic/quest_logic.py +++ b/worlds/stardew_valley/logic/quest_logic.py @@ -73,20 +73,19 @@ def initialize_rules(self): Quest.knee_therapy: self.logic.season.has(Season.summer) & self.logic.has(Fruit.hot_pepper) & self.logic.relationship.can_meet(NPC.george), Quest.robins_request: self.logic.season.has(Season.winter) & self.logic.has(Material.hardwood) & self.logic.relationship.can_meet(NPC.robin), Quest.qis_challenge: True_(), # The skull cavern floor 25 already has rules - Quest.the_mysterious_qi: self.logic.region.can_reach_all((Region.bus_tunnel, Region.railroad, Region.mayor_house)) & - self.logic.has(ArtisanGood.battery_pack) & self.logic.has(Forageable.rainbow_shell) & - self.logic.has(Vegetable.beet) & self.logic.has(Loot.solar_essence), + Quest.the_mysterious_qi: (self.logic.region.can_reach_all((Region.bus_tunnel, Region.railroad, Region.mayor_house)) & + self.logic.has_all(ArtisanGood.battery_pack, Forageable.rainbow_shell, Vegetable.beet, Loot.solar_essence)), Quest.carving_pumpkins: self.logic.season.has(Season.fall) & self.logic.has(Vegetable.pumpkin) & self.logic.relationship.can_meet(NPC.caroline), Quest.a_winter_mystery: self.logic.season.has(Season.winter), Quest.strange_note: self.logic.has(Forageable.secret_note) & self.logic.has(ArtisanGood.maple_syrup), Quest.cryptic_note: self.logic.has(Forageable.secret_note), Quest.fresh_fruit: self.logic.season.has(Season.spring) & self.logic.has(Fruit.apricot) & self.logic.relationship.can_meet(NPC.emily), Quest.aquatic_research: self.logic.season.has(Season.summer) & self.logic.has(Fish.pufferfish) & self.logic.relationship.can_meet(NPC.demetrius), - Quest.a_soldiers_star: self.logic.season.has(Season.summer) & self.logic.time.has_year_two & self.logic.has(Fruit.starfruit) & - self.logic.relationship.can_meet(NPC.kent), + Quest.a_soldiers_star: (self.logic.season.has(Season.summer) & self.logic.time.has_year_two & self.logic.has(Fruit.starfruit) & + self.logic.relationship.can_meet(NPC.kent)), Quest.mayors_need: self.logic.season.has(Season.summer) & self.logic.has(ArtisanGood.truffle_oil) & self.logic.relationship.can_meet(NPC.lewis), - Quest.wanted_lobster: self.logic.season.has(Season.fall) & self.logic.season.has(Season.fall) & self.logic.has(Fish.lobster) & - self.logic.relationship.can_meet(NPC.gus), + Quest.wanted_lobster: (self.logic.season.has(Season.fall) & self.logic.season.has(Season.fall) & self.logic.has(Fish.lobster) & + self.logic.relationship.can_meet(NPC.gus)), Quest.pam_needs_juice: self.logic.season.has(Season.fall) & self.logic.has(ArtisanGood.battery_pack) & self.logic.relationship.can_meet(NPC.pam), Quest.fish_casserole: self.logic.relationship.has_hearts(NPC.jodi, 4) & self.logic.has(Fish.largemouth_bass), Quest.catch_a_squid: self.logic.season.has(Season.winter) & self.logic.has(Fish.squid) & self.logic.relationship.can_meet(NPC.willy), @@ -98,7 +97,8 @@ def initialize_rules(self): Quest.grannys_gift: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek) & self.logic.relationship.can_meet(NPC.evelyn), Quest.exotic_spirits: self.logic.season.has(Season.winter) & self.logic.has(Forageable.coconut) & self.logic.relationship.can_meet(NPC.gus), Quest.catch_a_lingcod: self.logic.season.has(Season.winter) & self.logic.has(Fish.lingcod) & self.logic.relationship.can_meet(NPC.willy), - Quest.dark_talisman: self.logic.region.can_reach(Region.railroad) & self.logic.wallet.has_rusty_key() & self.logic.relationship.can_meet(NPC.krobus), + Quest.dark_talisman: self.logic.region.can_reach(Region.railroad) & self.logic.wallet.has_rusty_key() & self.logic.relationship.can_meet( + NPC.krobus), Quest.goblin_problem: self.logic.region.can_reach(Region.witch_swamp), Quest.magic_ink: self.logic.relationship.can_meet(NPC.wizard), Quest.the_pirates_wife: self.logic.relationship.can_meet(NPC.kent) & self.logic.relationship.can_meet(NPC.gus) & diff --git a/worlds/stardew_valley/logic/received_logic.py b/worlds/stardew_valley/logic/received_logic.py index 71e6dd65c304..66dc078ad46f 100644 --- a/worlds/stardew_valley/logic/received_logic.py +++ b/worlds/stardew_valley/logic/received_logic.py @@ -1,10 +1,11 @@ from typing import Optional from .base_logic import BaseLogic, BaseLogicMixin +from .has_logic import HasLogicMixin from ..stardew_rule import StardewRule, Received, And, Or, TotalReceived -class ReceivedLogicMixin(BaseLogic[None], BaseLogicMixin): +class ReceivedLogicMixin(BaseLogic[HasLogicMixin], BaseLogicMixin): # Should be cached def received(self, item: str, count: Optional[int] = 1) -> StardewRule: assert count >= 0, "Can't receive a negative amount of item." @@ -21,6 +22,12 @@ def received_any(self, *items: str): return Or(*(self.received(item) for item in items)) + def received_once(self, *items: str, count: int): + assert items, "Can't receive once of no items." + assert count >= 0, "Can't receive a negative amount of item." + + return self.logic.count(count, *(self.received(item) for item in items)) + def received_n(self, *items: str, count: int): assert items, "Can't receive n of no items." assert count >= 0, "Can't receive a negative amount of item." diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index b589388802a0..b004d48006e0 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -10,9 +10,9 @@ from ..locations import LocationTags, locations_by_tag from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations -from ..stardew_rule import StardewRule, And -from ..strings.building_names import Building +from ..stardew_rule import StardewRule from ..strings.ap_names.event_names import Event +from ..strings.building_names import Building class ShippingLogicMixin(BaseLogicMixin): @@ -45,4 +45,4 @@ def can_ship_everything(self) -> StardewRule: if location.mod_name and location.mod_name not in mod_list: continue all_items_to_ship.append(location.name[len(shipsanity_prefix):]) - return self.logic.building.has_building(Building.shipping_bin) & And(*(self.logic.has(item) for item in all_items_to_ship)) + return self.logic.building.has_building(Building.shipping_bin) & self.logic.has_all(*all_items_to_ship) diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 7d2e2f6a7d1d..4f6ef4d4bc0b 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -20,8 +20,8 @@ from .tool_logic import ToolLogicMixin from ..stardew_rule import StardewRule, Has from ..strings.animal_product_names import AnimalProduct -from ..strings.ap_names.transport_names import Transportation from ..strings.ap_names.event_names import Event +from ..strings.ap_names.transport_names import Transportation from ..strings.artisan_good_names import ArtisanGood from ..strings.crop_names import Vegetable, Fruit from ..strings.fertilizer_names import Fertilizer @@ -46,9 +46,9 @@ def __init__(self, *args, **kwargs): class SpecialOrderLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, TimeLogicMixin, MoneyLogicMixin, - ShippingLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, RelationshipLogicMixin, ToolLogicMixin, SkillLogicMixin, - MineLogicMixin, CookingLogicMixin, BuffLogicMixin, - AbilityLogicMixin, SpecialOrderLogicMixin, MonsterLogicMixin]]): +ShippingLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, RelationshipLogicMixin, ToolLogicMixin, SkillLogicMixin, +MineLogicMixin, CookingLogicMixin, BuffLogicMixin, +AbilityLogicMixin, SpecialOrderLogicMixin, MonsterLogicMixin]]): def initialize_rules(self): self.update_rules({ @@ -58,9 +58,9 @@ def initialize_rules(self): SpecialOrder.cave_patrol: self.logic.relationship.can_meet(NPC.clint), SpecialOrder.aquatic_overpopulation: self.logic.relationship.can_meet(NPC.demetrius) & self.logic.ability.can_fish_perfectly(), SpecialOrder.biome_balance: self.logic.relationship.can_meet(NPC.demetrius) & self.logic.ability.can_fish_perfectly(), - SpecialOrder.rock_rejuivenation: self.logic.relationship.has_hearts(NPC.emily, 4) & self.logic.has(Mineral.ruby) & self.logic.has(Mineral.topaz) & - self.logic.has(Mineral.emerald) & self.logic.has(Mineral.jade) & self.logic.has(Mineral.amethyst) & - self.logic.has(ArtisanGood.cloth), + SpecialOrder.rock_rejuivenation: (self.logic.relationship.has_hearts(NPC.emily, 4) & + self.logic.has_all(Mineral.ruby, Mineral.topaz, Mineral.emerald, Mineral.jade, Mineral.amethyst, + ArtisanGood.cloth)), SpecialOrder.gifts_for_george: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek), SpecialOrder.fragments_of_the_past: self.logic.region.can_reach(Region.dig_site) & self.logic.tool.has_tool(Tool.pickaxe) & self.logic.monster.can_kill(Monster.skeleton), diff --git a/worlds/stardew_valley/mods/logic/buildings_logic.py b/worlds/stardew_valley/mods/logic/buildings_logic.py index d95a90230e84..388204a47614 100644 --- a/worlds/stardew_valley/mods/logic/buildings_logic.py +++ b/worlds/stardew_valley/mods/logic/buildings_logic.py @@ -22,7 +22,7 @@ class ModBuildingLogic(BaseLogic[Union[MoneyLogicMixin, HasLogicMixin]]): def get_modded_building_rules(self) -> Dict[str, StardewRule]: buildings = dict() if ModNames.tractor in self.options.mods: - tractor_rule = (self.logic.money.can_spend_at(Region.carpenter, 150000) & self.logic.has(MetalBar.iron) & - self.logic.has(MetalBar.iridium) & self.logic.has(ArtisanGood.battery_pack)) + tractor_rule = (self.logic.money.can_spend_at(Region.carpenter, 150000) & + self.logic.has_all(MetalBar.iron, MetalBar.iridium, ArtisanGood.battery_pack)) buildings.update({ModBuilding.tractor_garage: tractor_rule}) return buildings diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 16d90e2cfa9e..245c79a256a4 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -72,14 +72,14 @@ def _get_sve_quest_rules(self): return {} return { - ModQuest.RailroadBoulder: self.logic.received(Wallet.skull_key) & self.logic.has((Ore.iridium, Material.coal)) & - self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad), - ModQuest.GrandpasShed: self.logic.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & - self.logic.region.can_reach(SVERegion.grandpas_shed), - ModQuest.MarlonsBoat: self.logic.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & - self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), + ModQuest.RailroadBoulder: (self.logic.received(Wallet.skull_key) & self.logic.has_all(Ore.iridium, Material.coal) & + self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad)), + ModQuest.GrandpasShed: (self.logic.has_all(Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone) & + self.logic.region.can_reach(SVERegion.grandpas_shed)), + ModQuest.MarlonsBoat: (self.logic.has_all(Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat) & + self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit)), ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), + ModQuest.MonsterCrops: self.logic.has_all(SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root), ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul), } @@ -87,7 +87,7 @@ def _get_distant_lands_quest_rules(self): if ModNames.distant_lands not in self.options.mods: return {} - return{ + return { ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.has(Fertilizer.deluxe), ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.deluxe), ModQuest.ANewPot: self.logic.region.can_reach(Region.saloon) & @@ -97,4 +97,3 @@ def _get_distant_lands_quest_rules(self): self.logic.has(ArtisanGood.cloth) } - diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 586008207c1d..64a9bcb51aa4 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -19,9 +19,9 @@ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And from .strings.ap_names.event_names import Event +from .strings.ap_names.mods.mod_items import SVELocation from .strings.ap_names.mods.mod_items import SVEQuestItem from .strings.ap_names.transport_names import Transportation -from .strings.ap_names.mods.mod_items import SVELocation from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building from .strings.bundle_names import CCRoom @@ -853,8 +853,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze: Heal", player), logic.has("Life Elixir")) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Life School Locations", player), - (logic.has("Coffee") & logic.has("Life Elixir") - & logic.ability.can_mine_perfectly())) + logic.has_all("Coffee", "Life Elixir") & logic.ability.can_mine_perfectly()) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Descend", player), logic.region.can_reach(Region.mines)) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), @@ -883,9 +882,8 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze Every Magic School Location", player), (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & - logic.has("Coffee") & logic.has("Life Elixir") - & logic.ability.can_mine_perfectly() & logic.has("Earth Crystal") & - logic.has("Fire Quartz") & logic.skill.can_fish(difficulty=85) & + logic.has_all("Coffee", "Life Elixir", "Earth Crystal", "Fire Quartz") & + logic.ability.can_mine_perfectly() & logic.skill.can_fish(difficulty=85) & logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12))) From aec723407a07ed92abff42189857cfc030067085 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 30 Dec 2023 20:29:05 -0500 Subject: [PATCH 377/482] move rules in their respective files --- worlds/stardew_valley/__init__.py | 4 +-- worlds/stardew_valley/logic/fishing_logic.py | 17 ++++++++++-- worlds/stardew_valley/logic/logic.py | 29 ++------------------ worlds/stardew_valley/logic/monster_logic.py | 28 ++++++++++++++----- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 69d8ff16ccca..d6f97c88f6e5 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -229,7 +229,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_master_angler: self.create_event_location(location_table[GoalName.master_angler], - self.logic.can_catch_every_fish(), + self.logic.fishing.can_catch_every_fish(), Event.victory) elif self.options.goal == Goal.option_complete_collection: self.create_event_location(location_table[GoalName.complete_museum], @@ -245,7 +245,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_protector_of_the_valley: self.create_event_location(location_table[GoalName.protector_of_the_valley], - self.logic.can_complete_all_monster_slaying_goals(), + self.logic.monster.can_complete_all_monster_slaying_goals(), Event.victory) elif self.options.goal == Goal.option_full_shipment: self.create_event_location(location_table[GoalName.full_shipment], diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index d8ab54a1b80c..31046eb49d1a 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -7,8 +7,7 @@ from .season_logic import SeasonLogicMixin from .skill_logic import SkillLogicMixin from .tool_logic import ToolLogicMixin -from ..data import FishItem -from ..data.fish_data import legendary_fish +from ..data import FishItem, fish_data from ..options import ExcludeGingerIsland from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, False_, And @@ -61,7 +60,7 @@ def can_start_extended_family_quest(self) -> StardewRule: return False_() if self.options.special_order_locations != SpecialOrderLocations.option_board_qi: return False_() - return self.logic.region.can_reach(Region.qi_walnut_room) & And(*(self.logic.fishing.can_catch_fish(fish) for fish in legendary_fish)) + return self.logic.region.can_reach(Region.qi_walnut_room) & And(*(self.logic.fishing.can_catch_fish(fish) for fish in fish_data.legendary_fish)) def can_catch_quality_fish(self, fish_quality: str) -> StardewRule: if fish_quality == FishQuality.basic: @@ -74,3 +73,15 @@ def can_catch_quality_fish(self, fish_quality: str) -> StardewRule: if fish_quality == FishQuality.iridium: return rod_rule & self.logic.skill.has_level(Skill.fishing, 10) return False_() + + def can_catch_every_fish(self) -> StardewRule: + rules = [self.logic.skill.has_level(Skill.fishing, 10), self.logic.tool.has_fishing_rod(4)] + exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true + exclude_extended_family = self.options.special_order_locations != SpecialOrderLocations.option_board_qi + for fish in fish_data.get_fish_for_mods(self.options.mods.value): + if exclude_island and fish in fish_data.island_fish: + continue + if exclude_extended_family and fish in fish_data.extended_family: + continue + rules.append(self.logic.fishing.can_catch_fish(fish)) + return And(*rules) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index f03b123ee400..47ec0cd558b2 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -38,8 +38,8 @@ from ..data import all_purchasable_seeds, all_crops from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name -from ..data.fish_data import island_fish, extended_family, get_fish_for_mods -from ..data.monster_data import all_monsters_by_category, all_monsters_by_name +from ..data.fish_data import get_fish_for_mods +from ..data.monster_data import all_monsters_by_name from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..mods.logic.magic_logic import MagicLogicMixin @@ -478,18 +478,6 @@ def can_buy_sapling(self, fruit: str) -> StardewRule: return allowed_buy_sapling & can_buy_sapling - def can_catch_every_fish(self) -> StardewRule: - rules = [self.skill.has_level(Skill.fishing, 10), self.tool.has_fishing_rod(4)] - exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true - exclude_extended_family = self.options.special_order_locations != SpecialOrderLocations.option_board_qi - for fish in get_fish_for_mods(self.options.mods.value): - if exclude_island and fish in island_fish: - continue - if exclude_extended_family and fish in extended_family: - continue - rules.append(self.fishing.can_catch_fish(fish)) - return And(*rules) - def can_smelt(self, item: str) -> StardewRule: return self.has(Machine.furnace) & self.has(item) @@ -533,17 +521,6 @@ def can_finish_grandpa_evaluation(self) -> StardewRule: ] return self.count(12, *rules_worth_a_point) - def can_complete_all_monster_slaying_goals(self) -> StardewRule: - rules = [self.time.has_lived_max_months] - exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true - island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern] - for category in all_monsters_by_category: - if exclude_island and all(all(location in island_regions for location in monster.locations) for monster in all_monsters_by_category[category]): - continue - rules.append(self.monster.can_kill_any(all_monsters_by_category[category])) - - return And(*rules) - def can_win_egg_hunt(self) -> StardewRule: number_of_movement_buffs = self.options.movement_buff_number if self.options.festival_locations == FestivalLocations.option_hard or number_of_movement_buffs < 2: @@ -694,7 +671,7 @@ def has_all_stardrops(self) -> StardewRule: number_of_stardrops_to_receive += 1 # Krobus Stardrop if self.options.fishsanity == Fishsanity.option_none: # Master Angler Stardrop - other_rules.append(self.can_catch_every_fish()) + other_rules.append(self.fishing.can_catch_every_fish()) else: number_of_stardrops_to_receive += 1 diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 7ba431561186..0e84475c0af9 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -5,8 +5,10 @@ from .combat_logic import CombatLogicMixin from .region_logic import RegionLogicMixin from .time_logic import TimeLogicMixin, MAX_MONTHS -from ..data.monster_data import StardewMonster, all_monsters_by_name +from .. import options +from ..data import monster_data from ..stardew_rule import StardewRule, Or, And +from ..strings.region_names import Region class MonsterLogicMixin(BaseLogicMixin): @@ -16,9 +18,9 @@ def __init__(self, *args, **kwargs): class MonsterLogic(BaseLogic[Union[MonsterLogicMixin, RegionLogicMixin, CombatLogicMixin, TimeLogicMixin]]): - def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> StardewRule: + def can_kill(self, monster: Union[str, monster_data.StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): - monster = all_monsters_by_name[monster] + monster = monster_data.all_monsters_by_name[monster] region_rule = self.logic.region.can_reach_any(monster.locations) combat_rule = self.logic.combat.can_fight_at_level(monster.difficulty) if amount_tier <= 0: @@ -27,19 +29,31 @@ def can_kill(self, monster: Union[str, StardewMonster], amount_tier: int = 0) -> return region_rule & combat_rule & time_rule @cache_self1 - def can_kill_many(self, monster: StardewMonster) -> StardewRule: + def can_kill_many(self, monster: monster_data.StardewMonster) -> StardewRule: return self.logic.monster.can_kill(monster, MAX_MONTHS / 3) @cache_self1 - def can_kill_max(self, monster: StardewMonster) -> StardewRule: + def can_kill_max(self, monster: monster_data.StardewMonster) -> StardewRule: return self.logic.monster.can_kill(monster, MAX_MONTHS) # Should be cached - def can_kill_any(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: + def can_kill_any(self, monsters: (Iterable[monster_data.StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.logic.monster.can_kill(monster, amount_tier) for monster in monsters] return Or(*rules) # Should be cached - def can_kill_all(self, monsters: (Iterable[StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: + def can_kill_all(self, monsters: (Iterable[monster_data.StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule: rules = [self.logic.monster.can_kill(monster, amount_tier) for monster in monsters] return And(*rules) + + def can_complete_all_monster_slaying_goals(self) -> StardewRule: + rules = [self.logic.time.has_lived_max_months] + exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true + island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern] + for category in monster_data.all_monsters_by_category: + if exclude_island and all(all(location in island_regions for location in monster.locations) + for monster in monster_data.all_monsters_by_category[category]): + continue + rules.append(self.logic.monster.can_kill_any(monster_data.all_monsters_by_category[category])) + + return And(*rules) From 122d6d88294e67e3c466174d0ada9f382848afe4 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 31 Dec 2023 11:18:56 -0500 Subject: [PATCH 378/482] - Added paleontologist and slime farmer bundle --- worlds/stardew_valley/data/bundle_data.py | 45 +++++++++++++++---- worlds/stardew_valley/data/locations.csv | 2 + worlds/stardew_valley/data/museum_data.py | 6 +-- worlds/stardew_valley/strings/bundle_names.py | 2 + worlds/stardew_valley/strings/metal_names.py | 16 ++++--- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 8129d337956f..add85c885a6a 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -316,6 +316,34 @@ dried_starfish = BundleItem(Fossil.dried_starfish) bone_fragment = BundleItem(Fossil.bone_fragment) +golden_mask = BundleItem(Artifact.golden_mask) +golden_relic = BundleItem(Artifact.golden_relic) +dwarf_gadget = BundleItem(Artifact.dwarf_gadget) +dwarvish_helm = BundleItem(Artifact.dwarvish_helm) +prehistoric_handaxe = BundleItem(Artifact.prehistoric_handaxe) +bone_flute = BundleItem(Artifact.bone_flute) +anchor = BundleItem(Artifact.anchor) +prehistoric_tool = BundleItem(Artifact.prehistoric_tool) +chicken_statue = BundleItem(Artifact.chicken_statue) +rusty_cog = BundleItem(Artifact.rusty_cog) +rusty_spur = BundleItem(Artifact.rusty_spur) +rusty_spoon = BundleItem(Artifact.rusty_spoon) +ancient_sword = BundleItem(Artifact.ancient_sword) +ornamental_fan = BundleItem(Artifact.ornamental_fan) +chipped_amphora = BundleItem(Artifact.chipped_amphora) + +prehistoric_scapula = BundleItem(Fossil.prehistoric_scapula) +prehistoric_tibia = BundleItem(Fossil.prehistoric_tibia) +prehistoric_skull = BundleItem(Fossil.prehistoric_skull) +skeletal_hand = BundleItem(Fossil.skeletal_hand) +prehistoric_rib = BundleItem(Fossil.prehistoric_rib) +prehistoric_vertebra = BundleItem(Fossil.prehistoric_vertebra) +skeletal_tail = BundleItem(Fossil.skeletal_tail) +nautilus_fossil = BundleItem(Fossil.nautilus_fossil) +amphibian_fossil = BundleItem(Fossil.amphibian_fossil) +palm_fossil = BundleItem(Fossil.palm_fossil) +trilobite = BundleItem(Fossil.trilobite) + dinosaur_mayo = BundleItem(ArtisanGood.dinosaur_mayonnaise) void_mayo = BundleItem(ArtisanGood.void_mayonnaise) prismatic_shard = BundleItem(Mineral.prismatic_shard) @@ -607,18 +635,19 @@ recycling_items = [stone, coal, iron_ore, wood, cloth, refined_quartz] recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4) -# archaeologist_items = [golden_mask, golden_relic, ancient_drum, dwarf_gadget, dwarvish_helm, prehistoric_handaxe, bone_flute, anchor, prehistoric_tool, -# chicken_statue, rusty_cog, rusty_spur, rusty_spoon, ancient_sword, ornamental_fan, elvish_jewelry, ancient_doll, chipped_amphora] -# archaeologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.archaeologist, archaeologist_items, 4, 2) -# -# paleontologist_items = [prehistoric_scapula, prehistoric_tibia, prehistoric_skull, skeletal_hand, prehistoric_rib, prehistoric_vertebra, skeletal_tail, -# nautilius_fossil, amphibian_fossil, palm_fossil, trilobite] -# paleontologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.paleontologist, paleontologist_items, 4, 2) + +archaeologist_items = [golden_mask, golden_relic, ancient_drum, dwarf_gadget, dwarvish_helm, prehistoric_handaxe, bone_flute, anchor, prehistoric_tool, + chicken_statue, rusty_cog, rusty_spur, rusty_spoon, ancient_sword, ornamental_fan, elvish_jewelry, ancient_doll, chipped_amphora] +archaeologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.archaeologist, archaeologist_items, 4, 2) + +paleontologist_items = [prehistoric_scapula, prehistoric_tibia, prehistoric_skull, skeletal_hand, prehistoric_rib, prehistoric_vertebra, skeletal_tail, + nautilus_fossil, amphibian_fossil, palm_fossil, trilobite] +paleontologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.paleontologist, paleontologist_items, 4, 2) boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla] boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic] boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle, - demolition_bundle, recycling_bundle] + demolition_bundle, recycling_bundle, archaeologist_bundle, paleontologist_bundle] boiler_room_vanilla = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_vanilla, 3) boiler_room_thematic = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_thematic, 3) boiler_room_remixed = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_remixed, 3) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 9b5e3faf7996..71643a29ae7d 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -43,6 +43,8 @@ id,region,name,tags,mod_name 44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", 45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", 46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +47,Boiler Room,Paleontologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", +48,Boiler Room,Archaeologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", 49,Pantry,Slime Farmer Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", 51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", diff --git a/worlds/stardew_valley/data/museum_data.py b/worlds/stardew_valley/data/museum_data.py index 895fce76b09b..544bb92e6e55 100644 --- a/worlds/stardew_valley/data/museum_data.py +++ b/worlds/stardew_valley/data/museum_data.py @@ -6,7 +6,7 @@ from ..strings.monster_names import Monster from ..strings.fish_names import WaterChest from ..strings.forageable_names import Forageable -from ..strings.metal_names import Mineral +from ..strings.metal_names import Mineral, Artifact, Fossil from ..strings.region_names import Region from ..strings.geode_names import Geode @@ -131,7 +131,7 @@ class Artifact: geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) bone_flute = create_artifact("Bone Flute", 6.3, (Region.mountain, Region.forest, Region.town), geodes=(Geode.artifact_trove, WaterChest.fishing_chest)) - prehistoric_handaxe = create_artifact("Prehistoric Handaxe", 13.7, + prehistoric_handaxe = create_artifact(Artifact.prehistoric_handaxe, 13.7, (Region.mountain, Region.forest, Region.bus_stop), geodes=Geode.artifact_trove) dwarvish_helm = create_artifact("Dwarvish Helm", 8.7, Region.mines_floor_20, @@ -153,7 +153,7 @@ class Artifact: prehistoric_tibia = create_artifact("Prehistoric Tibia", 16.6, (Region.dig_site, Region.forest, Region.railroad)) prehistoric_skull = create_artifact("Prehistoric Skull", 3.9, (Region.dig_site, Region.mountain)) - skeletal_hand = create_artifact("Skeletal Hand", 7.9, (Region.dig_site, Region.backwoods, Region.beach)) + skeletal_hand = create_artifact(Fossil.skeletal_hand, 7.9, (Region.dig_site, Region.backwoods, Region.beach)) prehistoric_rib = create_artifact("Prehistoric Rib", 15, (Region.dig_site, Region.farm, Region.town), monsters=Monster.pepper_rex) prehistoric_vertebra = create_artifact("Prehistoric Vertebra", 12.7, (Region.dig_site, Region.bus_stop), diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 12fb3c944542..da678c122ff0 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -61,6 +61,8 @@ class BundleName: treasure_hunter = "Treasure Hunter's Bundle" engineer = "Engineer's Bundle" demolition = "Demolition Bundle" + paleontologist = "Paleontologist's Bundle" + archaeologist = "Archaeologist's Bundle" chef = "Chef's Bundle" dye = "Dye Bundle" field_research = "Field Research Bundle" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 3828b7c28e2d..59e23ac4d32d 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -47,6 +47,7 @@ class Mineral: class Artifact: + prehistoric_handaxe = "Prehistoric Handaxe" dwarf_gadget = artifact("Dwarf Gadget") ancient_seed = artifact("Ancient Seed") glass_shards = artifact("Glass Shards") @@ -79,7 +80,10 @@ class Artifact: class Fossil: + amphibian_fossil = fossil("Amphibian Fossil") bone_fragment = "Bone Fragment" + dinosaur_egg = fossil("Dinosaur Egg") + dried_starfish = fossil("Dried Starfish") fossilized_leg = fossil("Fossilized Leg") fossilized_ribs = fossil("Fossilized Ribs") fossilized_skull = fossil("Fossilized Skull") @@ -87,18 +91,16 @@ class Fossil: fossilized_tail = fossil("Fossilized Tail") mummified_bat = fossil("Mummified Bat") mummified_frog = fossil("Mummified Frog") - snake_skull = fossil("Snake Skull") - snake_vertebrae = fossil("Snake Vertebrae") - amphibian_fossil = fossil("Amphibian Fossil") - dinosaur_egg = fossil("Dinosaur Egg") - dried_starfish = fossil("Dried Starfish") nautilus_fossil = fossil("Nautilus Fossil") palm_fossil = fossil("Palm Fossil") + prehistoric_hand = fossil("Skeletal Hand") prehistoric_rib = fossil("Prehistoric Rib") prehistoric_scapula = fossil("Prehistoric Scapula") prehistoric_skull = fossil("Prehistoric Skull") prehistoric_tibia = fossil("Prehistoric Tibia") - prehistoric_hand = fossil("Skeletal Hand") + prehistoric_vertebra = fossil("Prehistoric Vertebra") + skeletal_hand = "Skeletal Hand" skeletal_tail = fossil("Skeletal Tail") + snake_skull = fossil("Snake Skull") + snake_vertebrae = fossil("Snake Vertebrae") trilobite = fossil("Trilobite") - prehistoric_vertebra = fossil("Prehistoric Vertebra") From b2da4e8c1c7a9db2ee41d919c3d28545e19fb2b2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 31 Dec 2023 12:07:04 -0500 Subject: [PATCH 379/482] - Made Bundle Items more dynamic, and possibly reliant on different settings than the island --- worlds/stardew_valley/bundles/bundle.py | 39 +++++++++------ worlds/stardew_valley/bundles/bundle_item.py | 19 +++++-- worlds/stardew_valley/bundles/bundle_room.py | 8 +-- worlds/stardew_valley/bundles/bundles.py | 50 +++++++++---------- worlds/stardew_valley/data/bundle_data.py | 17 ++++--- worlds/stardew_valley/data/locations.csv | 1 + worlds/stardew_valley/strings/bundle_names.py | 1 + 7 files changed, 77 insertions(+), 58 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle.py b/worlds/stardew_valley/bundles/bundle.py index 653ce54c991b..199826b96bc8 100644 --- a/worlds/stardew_valley/bundles/bundle.py +++ b/worlds/stardew_valley/bundles/bundle.py @@ -3,7 +3,7 @@ from typing import List from .bundle_item import BundleItem -from ..options import BundlePrice +from ..options import BundlePrice, StardewValleyOptions, ExcludeGingerIsland, FestivalLocations from ..strings.currency_names import Currency @@ -37,7 +37,7 @@ def __init__(self, room: str, name: str, items: List[BundleItem], number_possibl def extend_from(template, items: List[BundleItem]): return BundleTemplate(template.room, template.name, items, template.number_possible_items, template.number_required_items) - def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, options: StardewValleyOptions) -> Bundle: if bundle_price_option == BundlePrice.option_minimum: number_required = 1 elif bundle_price_option == BundlePrice.option_maximum: @@ -45,7 +45,7 @@ def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_ else: number_required = self.number_required_items + bundle_price_option.value number_required = max(1, number_required) - filtered_items = [item for item in self.items if allow_island_items or not item.requires_island] + filtered_items = [item for item in self.items if item.can_appear(options)] number_items = len(filtered_items) number_chosen_items = self.number_possible_items if number_chosen_items < number_required: @@ -57,9 +57,8 @@ def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_ chosen_items = random.sample(filtered_items, number_chosen_items) return Bundle(self.room, self.name, chosen_items, number_required) - @property - def requires_island(self) -> bool: - return False + def can_appear(self, options: StardewValleyOptions) -> bool: + return True class CurrencyBundleTemplate(BundleTemplate): @@ -69,7 +68,7 @@ def __init__(self, room: str, name: str, item: BundleItem): super().__init__(room, name, [item], 1, 1) self.item = item - def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, options: StardewValleyOptions) -> Bundle: currency_amount = self.get_currency_amount(bundle_price_option) return Bundle(self.room, self.name, [BundleItem(self.item.item_name, currency_amount)], 1) @@ -84,9 +83,14 @@ def get_currency_amount(self, bundle_price_option: BundlePrice): currency_amount = int(self.item.amount * price_multiplier) return currency_amount - @property - def requires_island(self) -> bool: - return self.item.item_name == Currency.qi_gem or self.item.item_name == Currency.golden_walnut + def can_appear(self, options: StardewValleyOptions) -> bool: + if options.exclude_ginger_island == ExcludeGingerIsland.option_true: + if self.item.item_name == Currency.qi_gem or self.item.item_name == Currency.golden_walnut or self.item.item_name == Currency.cinder_shard: + return False + if options.festival_locations == FestivalLocations.option_disabled: + if self.item.item_name == Currency.star_token: + return False + return True class MoneyBundleTemplate(CurrencyBundleTemplate): @@ -94,7 +98,7 @@ class MoneyBundleTemplate(CurrencyBundleTemplate): def __init__(self, room: str, item: BundleItem): super().__init__(room, "", item) - def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, options: StardewValleyOptions) -> Bundle: currency_amount = self.get_currency_amount(bundle_price_option) currency_name = "g" if currency_amount >= 1000: @@ -118,10 +122,13 @@ def get_currency_amount(self, bundle_price_option: BundlePrice): class IslandBundleTemplate(BundleTemplate): + def can_appear(self, options: StardewValleyOptions) -> bool: + return options.exclude_ginger_island == ExcludeGingerIsland.option_false - @property - def requires_island(self) -> bool: - return True + +class FestivalBundleTemplate(BundleTemplate): + def can_appear(self, options: StardewValleyOptions) -> bool: + return options.festival_locations != FestivalLocations.option_disabled class DeepBundleTemplate(BundleTemplate): @@ -131,7 +138,7 @@ def __init__(self, room: str, name: str, categories: List[List[BundleItem]], num super().__init__(room, name, [], number_possible_items, number_required_items) self.categories = categories - def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool) -> Bundle: + def create_bundle(self, bundle_price_option: BundlePrice, random: Random, options: StardewValleyOptions) -> Bundle: if bundle_price_option == BundlePrice.option_minimum: number_required = 1 elif bundle_price_option == BundlePrice.option_maximum: @@ -150,7 +157,7 @@ def create_bundle(self, bundle_price_option: BundlePrice, random: Random, allow_ chosen_items = [] for category in chosen_categories: - filtered_items = [item for item in category if allow_island_items or not item.requires_island] + filtered_items = [item for item in category if item.can_appear(options)] chosen_items.append(random.choice(filtered_items)) return Bundle(self.room, self.name, chosen_items, number_required) diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index 4993b5cfb3a2..08a0f23aab9f 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -1,5 +1,6 @@ from dataclasses import dataclass +from ..options import StardewValleyOptions, ExcludeGingerIsland, FestivalLocations from ..strings.crop_names import Fruit from ..strings.currency_names import Currency from ..strings.quality_names import CropQuality, FishQuality, ForageQuality @@ -10,17 +11,16 @@ class BundleItem: item_name: str amount: int = 1 quality: str = CropQuality.basic - requires_island: bool = False @staticmethod def money_bundle(amount: int): return BundleItem(Currency.money, amount) def as_amount(self, amount: int): - return BundleItem(self.item_name, amount, self.quality, requires_island=self.requires_island) + return BundleItem(self.item_name, amount, self.quality) def as_quality(self, quality: str): - return BundleItem(self.item_name, self.amount, quality, requires_island=self.requires_island) + return BundleItem(self.item_name, self.amount, quality) def as_quality_crop(self): amount = 5 @@ -39,6 +39,15 @@ def __repr__(self): quality = "" if self.quality == CropQuality.basic else self.quality return f"{self.amount} {quality} {self.item_name}" + def can_appear(self, options: StardewValleyOptions) -> bool: + return True -def IslandBundleItem(*args, **kwargs): - return BundleItem(*args, requires_island=True, **kwargs) + +class IslandBundleItem(BundleItem): + def can_appear(self, options: StardewValleyOptions) -> bool: + return options.exclude_ginger_island == ExcludeGingerIsland.option_false + + +class FestivalBundleItem(BundleItem): + def can_appear(self, options: StardewValleyOptions) -> bool: + return options.festival_locations != FestivalLocations.option_disabled diff --git a/worlds/stardew_valley/bundles/bundle_room.py b/worlds/stardew_valley/bundles/bundle_room.py index 5c43da985b13..a5cdb89144f5 100644 --- a/worlds/stardew_valley/bundles/bundle_room.py +++ b/worlds/stardew_valley/bundles/bundle_room.py @@ -3,7 +3,7 @@ from typing import List from .bundle import Bundle, BundleTemplate -from ..options import BundlePrice +from ..options import BundlePrice, StardewValleyOptions @dataclass @@ -18,7 +18,7 @@ class BundleRoomTemplate: bundles: List[BundleTemplate] number_bundles: int - def create_bundle_room(self, bundle_price_option: BundlePrice, random: Random, allow_island_items: bool): - filtered_bundles = [bundle for bundle in self.bundles if allow_island_items or not bundle.requires_island] + def create_bundle_room(self, bundle_price_option: BundlePrice, random: Random, options: StardewValleyOptions): + filtered_bundles = [bundle for bundle in self.bundles if bundle.can_appear(options)] chosen_bundles = random.sample(filtered_bundles, self.number_bundles) - return BundleRoom(self.name, [bundle.create_bundle(bundle_price_option, random, allow_island_items) for bundle in chosen_bundles]) + return BundleRoom(self.name, [bundle.create_bundle(bundle_price_option, random, options) for bundle in chosen_bundles]) diff --git a/worlds/stardew_valley/bundles/bundles.py b/worlds/stardew_valley/bundles/bundles.py index f4dca7f14df6..260ee17cbe82 100644 --- a/worlds/stardew_valley/bundles/bundles.py +++ b/worlds/stardew_valley/bundles/bundles.py @@ -24,44 +24,40 @@ def get_all_bundles(random: Random, logic: StardewLogic, options: StardewValleyO def get_vanilla_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: - allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false - pantry = pantry_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - crafts_room = crafts_room_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - fish_tank = fish_tank_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - boiler_room = boiler_room_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - bulletin_board = bulletin_board_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - vault = vault_vanilla.create_bundle_room(options.bundle_price, random, allow_island) - abandoned_joja_mart = abandoned_joja_mart_vanilla.create_bundle_room(options.bundle_price, random, allow_island) + pantry = pantry_vanilla.create_bundle_room(options.bundle_price, random, options) + crafts_room = crafts_room_vanilla.create_bundle_room(options.bundle_price, random, options) + fish_tank = fish_tank_vanilla.create_bundle_room(options.bundle_price, random, options) + boiler_room = boiler_room_vanilla.create_bundle_room(options.bundle_price, random, options) + bulletin_board = bulletin_board_vanilla.create_bundle_room(options.bundle_price, random, options) + vault = vault_vanilla.create_bundle_room(options.bundle_price, random, options) + abandoned_joja_mart = abandoned_joja_mart_vanilla.create_bundle_room(options.bundle_price, random, options) return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart] def get_thematic_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: - allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false - pantry = pantry_thematic.create_bundle_room(options.bundle_price, random, allow_island) - crafts_room = crafts_room_thematic.create_bundle_room(options.bundle_price, random, allow_island) - fish_tank = fish_tank_thematic.create_bundle_room(options.bundle_price, random, allow_island) - boiler_room = boiler_room_thematic.create_bundle_room(options.bundle_price, random, allow_island) - bulletin_board = bulletin_board_thematic.create_bundle_room(options.bundle_price, random, allow_island) - vault = vault_thematic.create_bundle_room(options.bundle_price, random, allow_island) - abandoned_joja_mart = abandoned_joja_mart_thematic.create_bundle_room(options.bundle_price, random, allow_island) + pantry = pantry_thematic.create_bundle_room(options.bundle_price, random, options) + crafts_room = crafts_room_thematic.create_bundle_room(options.bundle_price, random, options) + fish_tank = fish_tank_thematic.create_bundle_room(options.bundle_price, random, options) + boiler_room = boiler_room_thematic.create_bundle_room(options.bundle_price, random, options) + bulletin_board = bulletin_board_thematic.create_bundle_room(options.bundle_price, random, options) + vault = vault_thematic.create_bundle_room(options.bundle_price, random, options) + abandoned_joja_mart = abandoned_joja_mart_thematic.create_bundle_room(options.bundle_price, random, options) return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart] def get_remixed_bundles(random: Random, options: StardewValleyOptions) -> List[BundleRoom]: - allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false - pantry = pantry_remixed.create_bundle_room(options.bundle_price, random, allow_island) - crafts_room = crafts_room_remixed.create_bundle_room(options.bundle_price, random, allow_island) - fish_tank = fish_tank_remixed.create_bundle_room(options.bundle_price, random, allow_island) - boiler_room = boiler_room_remixed.create_bundle_room(options.bundle_price, random, allow_island) - bulletin_board = bulletin_board_remixed.create_bundle_room(options.bundle_price, random, allow_island) - vault = vault_remixed.create_bundle_room(options.bundle_price, random, allow_island) - abandoned_joja_mart = abandoned_joja_mart_remixed.create_bundle_room(options.bundle_price, random, allow_island) + pantry = pantry_remixed.create_bundle_room(options.bundle_price, random, options) + crafts_room = crafts_room_remixed.create_bundle_room(options.bundle_price, random, options) + fish_tank = fish_tank_remixed.create_bundle_room(options.bundle_price, random, options) + boiler_room = boiler_room_remixed.create_bundle_room(options.bundle_price, random, options) + bulletin_board = bulletin_board_remixed.create_bundle_room(options.bundle_price, random, options) + vault = vault_remixed.create_bundle_room(options.bundle_price, random, options) + abandoned_joja_mart = abandoned_joja_mart_remixed.create_bundle_room(options.bundle_price, random, options) return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart] def get_shuffled_bundles(random: Random, logic: StardewLogic, options: StardewValleyOptions) -> List[BundleRoom]: - allow_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false - valid_bundle_items = [bundle_item for bundle_item in all_bundle_items_except_money if allow_island or not bundle_item.requires_island] + valid_bundle_items = [bundle_item for bundle_item in all_bundle_items_except_money if bundle_item.can_appear(options)] rooms = [room for room in get_remixed_bundles(random, options) if room.name != "Vault"] required_items = 0 @@ -79,6 +75,6 @@ def get_shuffled_bundles(random: Random, logic: StardewLogic, options: StardewVa bundle.items = sorted_bundle_items[:num_items] sorted_bundle_items = sorted_bundle_items[num_items:] - vault = vault_remixed.create_bundle_room(options.bundle_price, random, allow_island) + vault = vault_remixed.create_bundle_room(options.bundle_price, random, options) return [*rooms, vault] diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index add85c885a6a..8355713bbdab 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -1,5 +1,5 @@ -from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate, MoneyBundleTemplate -from ..bundles.bundle_item import BundleItem, IslandBundleItem +from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate, MoneyBundleTemplate, FestivalBundleTemplate +from ..bundles.bundle_item import BundleItem, IslandBundleItem, FestivalBundleItem from ..bundles.bundle_room import BundleRoomTemplate from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood @@ -76,7 +76,7 @@ kale = BundleItem(Vegetable.kale) parsnip = BundleItem(Vegetable.parsnip) potato = BundleItem(Vegetable.potato) -strawberry = BundleItem(Fruit.strawberry) +strawberry = FestivalBundleItem(Fruit.strawberry) tulip = BundleItem(Flower.tulip) unmilled_rice = BundleItem(Vegetable.unmilled_rice) coffee_bean = BundleItem(Seed.coffee) @@ -352,6 +352,7 @@ void_salmon = BundleItem(Fish.void_salmon) tea_leaves = BundleItem(Vegetable.tea_leaves) blobfish = BundleItem(Fish.blobfish) +spook_fish = BundleItem(Fish.spook_fish) lionfish = IslandBundleItem(Fish.lionfish) blue_discus = IslandBundleItem(Fish.blue_discus) stingray = IslandBundleItem(Fish.stingray) @@ -377,6 +378,7 @@ magnet = BundleItem(Fishing.magnet) wild_bait = BundleItem(Fishing.wild_bait, 10) magic_bait = IslandBundleItem(Fishing.magic_bait, 5) +pearl = BundleItem(Gift.pearl) ginger = IslandBundleItem(Forageable.ginger) magma_cap = IslandBundleItem(Forageable.magma_cap) @@ -467,7 +469,7 @@ fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4) fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic) -all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) +all_crops_items = list({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]] quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items] @@ -540,7 +542,7 @@ ocean_fish_bundle_thematic = BundleTemplate.extend_from(ocean_fish_bundle_vanilla, ocean_fish_items_thematic) night_fish_items_vanilla = [walleye, bream, eel] -night_fish_items_thematic = [*night_fish_items_vanilla, super_cucumber, squid, midnight_carp] +night_fish_items_thematic = [*night_fish_items_vanilla, super_cucumber, squid, midnight_carp, midnight_squid] night_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.night_fish, night_fish_items_vanilla, 3, 3) night_fish_bundle_thematic = BundleTemplate.extend_from(night_fish_bundle_vanilla, night_fish_items_thematic) @@ -593,6 +595,9 @@ bait_items = [bait, magnet, wild_bait, magic_bait] bait_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.bait, bait_items, 2, 2) +deep_fishing_items = [blobfish, spook_fish, midnight_squid, sea_cucumber, super_cucumber, octopus, pearl, seaweed] +deep_fishing_bundle = FestivalBundleTemplate(CCRoom.fish_tank, BundleName.deep_fishing, deep_fishing_items, 4, 3) + fish_tank_bundles_vanilla = [river_fish_bundle_vanilla, lake_fish_bundle_vanilla, ocean_fish_bundle_vanilla, night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla] fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic, @@ -745,7 +750,7 @@ vault_gambler_items = BundleItem(Currency.qi_coin, 10000) vault_gambler_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.gambler, vault_gambler_items) -vault_carnival_items = BundleItem(Currency.star_token, 2500) +vault_carnival_items = FestivalBundleItem(Currency.star_token, 2500) vault_carnival_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.carnival, vault_carnival_items) vault_walnut_hunter_items = BundleItem(Currency.golden_walnut, 25) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 71643a29ae7d..a20cab21a70b 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -36,6 +36,7 @@ id,region,name,tags,mod_name 35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", 36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", 37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +39,Fish Tank,Deep Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", 40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", 41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", 42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index da678c122ff0..2b8ac48b8a86 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -53,6 +53,7 @@ class BundleName: master_fisher = "Master Fisher's Bundle" legendary_fish = "Legendary Fish Bundle" island_fish = "Island Bundle" + deep_fishing = "Deep Fishing Bundle" tackle = "Tackle Bundle" bait = "Master Baiter Bundle" blacksmith = "Blacksmith's Bundle" From 8dd11ccc9002aa07f6d3f2ef7601183dc5a3690d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 31 Dec 2023 12:13:27 -0500 Subject: [PATCH 380/482] - Slight improvement to bundle items --- worlds/stardew_valley/data/bundle_data.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 8355713bbdab..f6ad47856aad 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -220,6 +220,7 @@ stonefish = BundleItem(Fish.stonefish) ghostfish = BundleItem(Fish.ghostfish) +bouquet = BundleItem(Gift.bouquet) wilted_bouquet = BundleItem(Gift.wilted_bouquet) copper_bar = BundleItem(MetalBar.copper) iron_Bar = BundleItem(MetalBar.iron) @@ -298,6 +299,7 @@ chocolate_cake = BundleItem(Meal.chocolate_cake) rhubarb_pie = BundleItem(Meal.rhubarb_pie) shrimp_cocktail = BundleItem(Meal.shrimp_cocktail) +pina_colada = IslandBundleItem(Beverage.pina_colada) green_algae = BundleItem(WaterItem.green_algae) white_algae = BundleItem(WaterItem.white_algae) @@ -493,7 +495,7 @@ fish_farmer_items = [roe.as_amount(15), aged_roe.as_amount(15), squid_ink] fish_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.fish_farmer, fish_farmer_items, 3, 2) -garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose, poppy, crocus, sweet_pea] +garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose, poppy, bouquet] garden_bundle = BundleTemplate(CCRoom.pantry, BundleName.garden, garden_items, 5, 4) brewer_items = [mead, pale_ale, wine, juice, green_tea, beer] @@ -708,7 +710,7 @@ chocolate_cake, pancakes, rhubarb_pie] home_cook_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.home_cook, home_cook_items, 3, 3) -bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, cranberry_candy, beer, pale_ale] +bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, cranberry_candy, beer, pale_ale, pina_colada] bartender_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.bartender, bartender_items, 3, 3) bulletin_board_bundles_vanilla = [chef_bundle_vanilla, dye_bundle_vanilla, field_research_bundle_vanilla, fodder_bundle_vanilla, enchanter_bundle_vanilla] From 5de708c04424618c53856ee54fc15b48f9967db2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 31 Dec 2023 13:10:38 -0500 Subject: [PATCH 381/482] - Rework Shuffle Trap to be more progressive in its difficulty --- worlds/stardew_valley/bundles/bundle_item.py | 15 +++++++++++++-- worlds/stardew_valley/data/bundle_data.py | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index 08a0f23aab9f..cb334d4e6317 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -16,11 +16,14 @@ class BundleItem: def money_bundle(amount: int): return BundleItem(Currency.money, amount) + def create(self, item_name: str, amount: int, quality: str): + return BundleItem(item_name, amount, quality) + def as_amount(self, amount: int): - return BundleItem(self.item_name, amount, self.quality) + return self.create(self.item_name, amount, self.quality) def as_quality(self, quality: str): - return BundleItem(self.item_name, self.amount, quality) + return self.create(self.item_name, self.amount, quality) def as_quality_crop(self): amount = 5 @@ -44,10 +47,18 @@ def can_appear(self, options: StardewValleyOptions) -> bool: class IslandBundleItem(BundleItem): + + def create(self, item_name: str, amount: int, quality: str): + return IslandBundleItem(item_name, amount, quality) + def can_appear(self, options: StardewValleyOptions) -> bool: return options.exclude_ginger_island == ExcludeGingerIsland.option_false class FestivalBundleItem(BundleItem): + + def create(self, item_name: str, amount: int, quality: str): + return FestivalBundleItem(item_name, amount, quality) + def can_appear(self, options: StardewValleyOptions) -> bool: return options.festival_locations != FestivalLocations.option_disabled diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index f6ad47856aad..c14f4ef19b14 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -439,7 +439,7 @@ wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3) -quality_foraging_items = sorted({item.as_quality(ForageQuality.gold).as_amount(1) +quality_foraging_items = list({item.as_quality(ForageQuality.gold).as_amount(1) for item in [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap]}) From 1dbd93c2adccc70331be1479140f2ce7b98e1dfa Mon Sep 17 00:00:00 2001 From: Jouramie Date: Sat, 30 Dec 2023 20:51:19 -0500 Subject: [PATCH 382/482] split animal logic --- worlds/stardew_valley/logic/animal_logic.py | 59 +++++++++++++ worlds/stardew_valley/logic/logic.py | 96 +++++---------------- 2 files changed, 82 insertions(+), 73 deletions(-) create mode 100644 worlds/stardew_valley/logic/animal_logic.py diff --git a/worlds/stardew_valley/logic/animal_logic.py b/worlds/stardew_valley/logic/animal_logic.py new file mode 100644 index 000000000000..eb1ebeeec54b --- /dev/null +++ b/worlds/stardew_valley/logic/animal_logic.py @@ -0,0 +1,59 @@ +from typing import Union + +from .base_logic import BaseLogicMixin, BaseLogic +from .building_logic import BuildingLogicMixin +from .has_logic import HasLogicMixin +from .money_logic import MoneyLogicMixin +from ..stardew_rule import StardewRule, true_ +from ..strings.animal_names import Animal, coop_animals, barn_animals +from ..strings.building_names import Building +from ..strings.forageable_names import Forageable +from ..strings.generic_names import Generic +from ..strings.region_names import Region + +cost_and_building_by_animal = { + Animal.chicken: (800, Building.coop), + Animal.cow: (1500, Building.barn), + Animal.goat: (4000, Building.big_barn), + Animal.duck: (1200, Building.big_coop), + Animal.sheep: (8000, Building.deluxe_barn), + Animal.rabbit: (8000, Building.deluxe_coop), + Animal.pig: (16000, Building.deluxe_barn) +} + + +class AnimalLogicMixin(BaseLogicMixin): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.animal = AnimalLogic(*args, **kwargs) + + +class AnimalLogic(BaseLogic[Union[HasLogicMixin, MoneyLogicMixin, BuildingLogicMixin]]): + + def can_buy_animal(self, animal: str) -> StardewRule: + try: + price, building = cost_and_building_by_animal[animal] + except KeyError: + return true_ + return self.logic.money.can_spend_at(Region.ranch, price) & self.logic.building.has_building(building) + + def has_animal(self, animal: str) -> StardewRule: + if animal == Generic.any: + return self.has_any_animal() + elif animal == Building.coop: + return self.has_any_coop_animal() + elif animal == Building.barn: + return self.has_any_barn_animal() + return self.logic.has(animal) + + def has_happy_animal(self, animal: str) -> StardewRule: + return self.has_animal(animal) & self.logic.has(Forageable.hay) + + def has_any_animal(self) -> StardewRule: + return self.has_any_coop_animal() | self.has_any_barn_animal() + + def has_any_coop_animal(self) -> StardewRule: + return self.logic.has_any(*coop_animals) + + def has_any_barn_animal(self) -> StardewRule: + return self.logic.has_any(*barn_animals) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 47ec0cd558b2..1fcbc80e588f 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -4,6 +4,7 @@ from .ability_logic import AbilityLogicMixin from .action_logic import ActionLogicMixin +from .animal_logic import AnimalLogicMixin from .arcade_logic import ArcadeLogicMixin from .artisan_logic import ArtisanLogicMixin from .base_logic import LogicRegistry @@ -47,7 +48,7 @@ from ..mods.mod_data import ModNames from ..options import Cropsanity, SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, Fishsanity, Friendsanity, StardewValleyOptions from ..stardew_rule import False_, Or, True_, And, StardewRule -from ..strings.animal_names import Animal, coop_animals, barn_animals +from ..strings.animal_names import Animal from ..strings.animal_product_names import AnimalProduct from ..strings.ap_names.ap_weapon_names import APWeapon from ..strings.ap_names.buff_names import Buff @@ -90,7 +91,7 @@ @dataclass(frozen=False, repr=False) class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, BuffLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin, SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin, - BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, + BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, AnimalLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, CropLogicMixin, SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin, SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin): @@ -176,37 +177,37 @@ def __init__(self, player: int, options: StardewValleyOptions): # self.received("Deluxe Fertilizer Recipe") & self.has(MetalBar.iridium) & self.has(SVItem.sap), # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.emily, 3) & self.has(Forageable.leek) & self.has(Forageable.dandelion) & # | (self.ability.can_cook() & self.relationship.has_hearts(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)), - Animal.chicken: self.can_buy_animal(Animal.chicken), - Animal.cow: self.can_buy_animal(Animal.cow), + Animal.chicken: self.animal.can_buy_animal(Animal.chicken), + Animal.cow: self.animal.can_buy_animal(Animal.cow), Animal.dinosaur: self.building.has_building(Building.big_coop) & self.has(AnimalProduct.dinosaur_egg), - Animal.duck: self.can_buy_animal(Animal.duck), - Animal.goat: self.can_buy_animal(Animal.goat), + Animal.duck: self.animal.can_buy_animal(Animal.duck), + Animal.goat: self.animal.can_buy_animal(Animal.goat), Animal.ostrich: self.building.has_building(Building.barn) & self.has(AnimalProduct.ostrich_egg) & self.has(Machine.ostrich_incubator), - Animal.pig: self.can_buy_animal(Animal.pig), - Animal.rabbit: self.can_buy_animal(Animal.rabbit), - Animal.sheep: self.can_buy_animal(Animal.sheep), + Animal.pig: self.animal.can_buy_animal(Animal.pig), + Animal.rabbit: self.animal.can_buy_animal(Animal.rabbit), + Animal.sheep: self.animal.can_buy_animal(Animal.sheep), AnimalProduct.any_egg: self.has_any(AnimalProduct.chicken_egg, AnimalProduct.duck_egg), - AnimalProduct.brown_egg: self.has_animal(Animal.chicken), + AnimalProduct.brown_egg: self.animal.has_animal(Animal.chicken), AnimalProduct.chicken_egg: self.has_any(AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg), AnimalProduct.cow_milk: self.has_any(AnimalProduct.milk, AnimalProduct.large_milk), - AnimalProduct.duck_egg: self.has_animal(Animal.duck), - AnimalProduct.duck_feather: self.has_happy_animal(Animal.duck), - AnimalProduct.egg: self.has_animal(Animal.chicken), + AnimalProduct.duck_egg: self.animal.has_animal(Animal.duck), + AnimalProduct.duck_feather: self.animal.has_happy_animal(Animal.duck), + AnimalProduct.egg: self.animal.has_animal(Animal.chicken), AnimalProduct.goat_milk: self.has(Animal.goat), AnimalProduct.golden_egg: self.received(AnimalProduct.golden_egg) & (self.money.can_spend_at(Region.ranch, 100000) | self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 100)), - AnimalProduct.large_brown_egg: self.has_happy_animal(Animal.chicken), - AnimalProduct.large_egg: self.has_happy_animal(Animal.chicken), - AnimalProduct.large_goat_milk: self.has_happy_animal(Animal.goat), - AnimalProduct.large_milk: self.has_happy_animal(Animal.cow), - AnimalProduct.milk: self.has_animal(Animal.cow), + AnimalProduct.large_brown_egg: self.animal.has_happy_animal(Animal.chicken), + AnimalProduct.large_egg: self.animal.has_happy_animal(Animal.chicken), + AnimalProduct.large_goat_milk: self.animal.has_happy_animal(Animal.goat), + AnimalProduct.large_milk: self.animal.has_happy_animal(Animal.cow), + AnimalProduct.milk: self.animal.has_animal(Animal.cow), AnimalProduct.ostrich_egg: self.tool.can_forage(Generic.any, Region.island_north, True), - AnimalProduct.rabbit_foot: self.has_happy_animal(Animal.rabbit), + AnimalProduct.rabbit_foot: self.animal.has_happy_animal(Animal.rabbit), AnimalProduct.roe: self.skill.can_fish() & self.building.has_building(Building.fish_pond), AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.building.has_building(Building.fish_pond) & self.has(Fish.squid)), AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.building.has_building(Building.fish_pond), - AnimalProduct.truffle: self.has_animal(Animal.pig) & self.season.has_any_not_winter(), + AnimalProduct.truffle: self.animal.has_animal(Animal.pig) & self.season.has_any_not_winter(), AnimalProduct.void_egg: self.money.can_spend_at(Region.sewer, 5000) | (self.building.has_building(Building.fish_pond) & self.has(Fish.void_salmon)), - AnimalProduct.wool: self.has_animal(Animal.rabbit) | self.has_animal(Animal.sheep), + AnimalProduct.wool: self.animal.has_animal(Animal.rabbit) | self.animal.has_animal(Animal.sheep), AnimalProduct.slime_egg_green: self.has(Machine.slime_egg_press) & self.has(Loot.slime), AnimalProduct.slime_egg_blue: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(3), AnimalProduct.slime_egg_red: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(6), @@ -545,7 +546,7 @@ def can_succeed_luau_soup(self) -> StardewRule: def can_succeed_grange_display(self) -> StardewRule: if self.options.festival_locations != FestivalLocations.option_hard: return True_() - animal_rule = self.has_animal(Generic.any) + animal_rule = self.animal.has_animal(Generic.any) artisan_rule = self.artisan.can_keg(Generic.any) | self.artisan.can_preserves_jar(Generic.any) cooking_rule = self.money.can_spend_at(Region.saloon, 220) # Salads at the bar are good enough fish_rule = self.skill.can_fish(difficulty=50) @@ -564,57 +565,6 @@ def can_succeed_grange_display(self) -> StardewRule: def can_win_fishing_competition(self) -> StardewRule: return self.skill.can_fish(difficulty=60) - def can_buy_animal(self, animal: str) -> StardewRule: - price = 0 - building = "" - if animal == Animal.chicken: - price = 800 - building = Building.coop - elif animal == Animal.cow: - price = 1500 - building = Building.barn - elif animal == Animal.goat: - price = 4000 - building = Building.big_barn - elif animal == Animal.duck: - price = 1200 - building = Building.big_coop - elif animal == Animal.sheep: - price = 8000 - building = Building.deluxe_barn - elif animal == Animal.rabbit: - price = 8000 - building = Building.deluxe_coop - elif animal == Animal.pig: - price = 16000 - building = Building.deluxe_barn - else: - return True_() - return self.money.can_spend_at(Region.ranch, price) & self.building.has_building(building) - - def has_animal(self, animal: str) -> StardewRule: - if animal == Generic.any: - return self.has_any_animal() - elif animal == Building.coop: - return self.has_any_coop_animal() - elif animal == Building.barn: - return self.has_any_barn_animal() - return self.has(animal) - - def has_happy_animal(self, animal: str) -> StardewRule: - return self.has_animal(animal) & self.has(Forageable.hay) - - def has_any_animal(self) -> StardewRule: - return self.has_any_coop_animal() | self.has_any_barn_animal() - - def has_any_coop_animal(self) -> StardewRule: - coop_rule = Or(*(self.has_animal(coop_animal) for coop_animal in coop_animals)) - return coop_rule - - def has_any_barn_animal(self) -> StardewRule: - barn_rule = Or(*(self.has_animal(barn_animal) for barn_animal in barn_animals)) - return barn_rule - def has_island_trader(self) -> StardewRule: if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: return False_() From 26701ceebf2f160a9ac00497ce62311242e632a9 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 1 Jan 2024 23:21:46 -0500 Subject: [PATCH 383/482] maybe fix test setup --- .../test/stability/TestStability.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py index a13ebaa92322..1526d3ea6a0a 100644 --- a/worlds/stardew_valley/test/stability/TestStability.py +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -4,9 +4,11 @@ import unittest from BaseClasses import get_seed +from Utils import Version # at 0x102ca98a0> -lambda_regex = re.compile(r" at (.*)>") +lambda_regex = re.compile(r"^ at (.*)>$") +python_version_regex = re.compile(r"^Python (\d+)\.(\d+)\.(\d+)\s*$") class TestGenerationIsStable(unittest.TestCase): @@ -16,8 +18,18 @@ class TestGenerationIsStable(unittest.TestCase): def test_all_locations_and_items_are_the_same_between_two_generations(self): seed = get_seed() - output_a = subprocess.check_output(['python3', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) - output_b = subprocess.check_output(['python3', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) + try: + python_version = subprocess.check_output(['python', '--version']) + except subprocess.CalledProcessError: + return self.skipTest("It seems that python is not available in you classpath. Skipping.") + + match = python_version_regex.match(python_version.decode("UTF-8")) + version = Version(*(int(m) for m in match.groups())) + if version.major < 3: + return self.skipTest("It seems that the python available in your classpath is python2 instead of python3. Skipping.") + + output_a = subprocess.check_output(['python', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) + output_b = subprocess.check_output(['python', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) result_a = json.loads(output_a) result_b = json.loads(output_b) From f58ce0b369c3f6460e06e1e0a1c55afba7011b43 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Mon, 1 Jan 2024 23:49:00 -0500 Subject: [PATCH 384/482] trying to use the same environment as the parent python --- .../test/stability/TestStability.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py index 1526d3ea6a0a..941274d874f6 100644 --- a/worlds/stardew_valley/test/stability/TestStability.py +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -1,13 +1,14 @@ import json import re import subprocess +import sys import unittest from BaseClasses import get_seed -from Utils import Version # at 0x102ca98a0> lambda_regex = re.compile(r"^ at (.*)>$") +# Python 3.10.2\r\n python_version_regex = re.compile(r"^Python (\d+)\.(\d+)\.(\d+)\s*$") @@ -18,18 +19,8 @@ class TestGenerationIsStable(unittest.TestCase): def test_all_locations_and_items_are_the_same_between_two_generations(self): seed = get_seed() - try: - python_version = subprocess.check_output(['python', '--version']) - except subprocess.CalledProcessError: - return self.skipTest("It seems that python is not available in you classpath. Skipping.") - - match = python_version_regex.match(python_version.decode("UTF-8")) - version = Version(*(int(m) for m in match.groups())) - if version.major < 3: - return self.skipTest("It seems that the python available in your classpath is python2 instead of python3. Skipping.") - - output_a = subprocess.check_output(['python', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) - output_b = subprocess.check_output(['python', '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) + output_a = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) + output_b = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) result_a = json.loads(output_a) result_b = json.loads(output_b) From 241f6c16f1967e812f633a87aac765bea98a043d Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 2 Jan 2024 00:05:26 -0500 Subject: [PATCH 385/482] fix stability --- worlds/stardew_valley/bundles/bundle_item.py | 56 ++++++++++++------- worlds/stardew_valley/data/bundle_data.py | 4 +- .../test/stability/TestStability.py | 2 +- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index cb334d4e6317..910eb89684ea 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -1,3 +1,4 @@ +from abc import ABC, abstractmethod from dataclasses import dataclass from ..options import StardewValleyOptions, ExcludeGingerIsland, FestivalLocations @@ -6,24 +7,49 @@ from ..strings.quality_names import CropQuality, FishQuality, ForageQuality +class BundleItemSource(ABC): + @abstractmethod + def can_appear(self, options: StardewValleyOptions) -> bool: + ... + + +class VanillaItemSource(BundleItemSource): + def can_appear(self, options: StardewValleyOptions) -> bool: + return True + + +class IslandItemSource(BundleItemSource): + def can_appear(self, options: StardewValleyOptions) -> bool: + return options.exclude_ginger_island == ExcludeGingerIsland.option_false + + +class FestivalItemSource(BundleItemSource): + def can_appear(self, options: StardewValleyOptions) -> bool: + return options.festival_locations != FestivalLocations.option_disabled + + +class BundleItemSources: + vanilla = VanillaItemSource() + island = IslandItemSource() + festival = FestivalItemSource() + + @dataclass(frozen=True, order=True) class BundleItem: item_name: str amount: int = 1 quality: str = CropQuality.basic + source: BundleItemSource = BundleItemSources.vanilla @staticmethod def money_bundle(amount: int): return BundleItem(Currency.money, amount) - def create(self, item_name: str, amount: int, quality: str): - return BundleItem(item_name, amount, quality) - def as_amount(self, amount: int): - return self.create(self.item_name, amount, self.quality) + return BundleItem(self.item_name, amount, self.quality, self.source) def as_quality(self, quality: str): - return self.create(self.item_name, self.amount, quality) + return BundleItem(self.item_name, self.amount, quality, self.source) def as_quality_crop(self): amount = 5 @@ -43,22 +69,12 @@ def __repr__(self): return f"{self.amount} {quality} {self.item_name}" def can_appear(self, options: StardewValleyOptions) -> bool: - return True + return self.source.can_appear(options) -class IslandBundleItem(BundleItem): +def IslandBundleItem(*args, **kwargs): + return BundleItem(*args, source=BundleItemSources.island, **kwargs) - def create(self, item_name: str, amount: int, quality: str): - return IslandBundleItem(item_name, amount, quality) - def can_appear(self, options: StardewValleyOptions) -> bool: - return options.exclude_ginger_island == ExcludeGingerIsland.option_false - - -class FestivalBundleItem(BundleItem): - - def create(self, item_name: str, amount: int, quality: str): - return FestivalBundleItem(item_name, amount, quality) - - def can_appear(self, options: StardewValleyOptions) -> bool: - return options.festival_locations != FestivalLocations.option_disabled +def FestivalBundleItem(*args, **kwargs): + return BundleItem(*args, source=BundleItemSources.festival, **kwargs) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index c14f4ef19b14..9c03e0e78d45 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -439,7 +439,7 @@ wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]] wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3) -quality_foraging_items = list({item.as_quality(ForageQuality.gold).as_amount(1) +quality_foraging_items = sorted({item.as_quality(ForageQuality.gold).as_amount(1) for item in [*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic, *winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap]}) @@ -471,7 +471,7 @@ fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4) fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic) -all_crops_items = list({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) +all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic}) quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]] quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items] diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py index 941274d874f6..7710b1788daa 100644 --- a/worlds/stardew_valley/test/stability/TestStability.py +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -17,7 +17,7 @@ class TestGenerationIsStable(unittest.TestCase): """ def test_all_locations_and_items_are_the_same_between_two_generations(self): - seed = get_seed() + seed = get_seed(33778671150797368040) output_a = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) output_b = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) From 575d7dc8b44f15e75290c6192edf0cad4bc032f9 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 2 Jan 2024 00:19:50 -0500 Subject: [PATCH 386/482] remove old methods to create island and festival items --- worlds/stardew_valley/bundles/bundle_item.py | 13 +++--- worlds/stardew_valley/data/bundle_data.py | 42 ++++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index 910eb89684ea..d9d571fe6b4d 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -41,6 +41,11 @@ class BundleItem: quality: str = CropQuality.basic source: BundleItemSource = BundleItemSources.vanilla + class Sources: + vanilla = VanillaItemSource() + island = IslandItemSource() + festival = FestivalItemSource() + @staticmethod def money_bundle(amount: int): return BundleItem(Currency.money, amount) @@ -70,11 +75,3 @@ def __repr__(self): def can_appear(self, options: StardewValleyOptions) -> bool: return self.source.can_appear(options) - - -def IslandBundleItem(*args, **kwargs): - return BundleItem(*args, source=BundleItemSources.island, **kwargs) - - -def FestivalBundleItem(*args, **kwargs): - return BundleItem(*args, source=BundleItemSources.festival, **kwargs) diff --git a/worlds/stardew_valley/data/bundle_data.py b/worlds/stardew_valley/data/bundle_data.py index 9c03e0e78d45..0e6aacdfb8a5 100644 --- a/worlds/stardew_valley/data/bundle_data.py +++ b/worlds/stardew_valley/data/bundle_data.py @@ -1,5 +1,5 @@ from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate, MoneyBundleTemplate, FestivalBundleTemplate -from ..bundles.bundle_item import BundleItem, IslandBundleItem, FestivalBundleItem +from ..bundles.bundle_item import BundleItem from ..bundles.bundle_room import BundleRoomTemplate from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood @@ -76,7 +76,7 @@ kale = BundleItem(Vegetable.kale) parsnip = BundleItem(Vegetable.parsnip) potato = BundleItem(Vegetable.potato) -strawberry = FestivalBundleItem(Fruit.strawberry) +strawberry = BundleItem(Fruit.strawberry, source=BundleItem.Sources.festival) tulip = BundleItem(Flower.tulip) unmilled_rice = BundleItem(Vegetable.unmilled_rice) coffee_bean = BundleItem(Seed.coffee) @@ -106,8 +106,8 @@ red_cabbage = BundleItem(Vegetable.red_cabbage) starfruit = BundleItem(Fruit.starfruit) artichoke = BundleItem(Vegetable.artichoke) -pineapple = IslandBundleItem(Fruit.pineapple) -taro_root = IslandBundleItem(Vegetable.taro_root) +pineapple = BundleItem(Fruit.pineapple, source=BundleItem.Sources.island) +taro_root = BundleItem(Vegetable.taro_root, source=BundleItem.Sources.island, ) egg = BundleItem(AnimalProduct.egg) large_egg = BundleItem(AnimalProduct.large_egg) @@ -124,7 +124,7 @@ rabbit_foot = BundleItem(AnimalProduct.rabbit_foot) dinosaur_egg = BundleItem(AnimalProduct.dinosaur_egg) void_egg = BundleItem(AnimalProduct.void_egg) -ostrich_egg = IslandBundleItem(AnimalProduct.ostrich_egg) +ostrich_egg = BundleItem(AnimalProduct.ostrich_egg, source=BundleItem.Sources.island, ) golden_egg = BundleItem(AnimalProduct.golden_egg) truffle_oil = BundleItem(ArtisanGood.truffle_oil) @@ -151,18 +151,18 @@ peach = BundleItem(Fruit.peach) pomegranate = BundleItem(Fruit.pomegranate) cherry = BundleItem(Fruit.cherry) -banana = IslandBundleItem(Fruit.banana) -mango = IslandBundleItem(Fruit.mango) +banana = BundleItem(Fruit.banana, source=BundleItem.Sources.island) +mango = BundleItem(Fruit.mango, source=BundleItem.Sources.island) basic_fertilizer = BundleItem(Fertilizer.basic, 100) quality_fertilizer = BundleItem(Fertilizer.quality, 20) -deluxe_fertilizer = IslandBundleItem(Fertilizer.deluxe, 5) +deluxe_fertilizer = BundleItem(Fertilizer.deluxe, 5, source=BundleItem.Sources.island) basic_retaining_soil = BundleItem(RetainingSoil.basic, 80) quality_retaining_soil = BundleItem(RetainingSoil.quality, 50) -deluxe_retaining_soil = IslandBundleItem(RetainingSoil.deluxe, 20) +deluxe_retaining_soil = BundleItem(RetainingSoil.deluxe, 20, source=BundleItem.Sources.island) speed_gro = BundleItem(SpeedGro.basic, 40) deluxe_speed_gro = BundleItem(SpeedGro.deluxe, 20) -hyper_speed_gro = IslandBundleItem(SpeedGro.hyper, 5) +hyper_speed_gro = BundleItem(SpeedGro.hyper, 5, source=BundleItem.Sources.island) tree_fertilizer = BundleItem(Fertilizer.tree, 20) lobster = BundleItem(Fish.lobster) @@ -256,7 +256,7 @@ red_slime_egg = BundleItem(Loot.red_slime_egg) purple_slime_egg = BundleItem(Loot.purple_slime_egg) green_slime_egg = BundleItem(Loot.green_slime_egg) -tiger_slime_egg = IslandBundleItem(Loot.tiger_slime_egg) +tiger_slime_egg = BundleItem(Loot.tiger_slime_egg, source=BundleItem.Sources.island) cherry_bomb = BundleItem(Bomb.cherry_bomb, 5) bomb = BundleItem(Bomb.bomb, 2) @@ -293,13 +293,13 @@ ancient_doll = BundleItem(Artifact.ancient_doll) ice_cream = BundleItem(Meal.ice_cream) cranberry_candy = BundleItem(Meal.cranberry_candy) -ginger_ale = IslandBundleItem(Beverage.ginger_ale) +ginger_ale = BundleItem(Beverage.ginger_ale, source=BundleItem.Sources.island) pink_cake = BundleItem(Meal.pink_cake) plum_pudding = BundleItem(Meal.plum_pudding) chocolate_cake = BundleItem(Meal.chocolate_cake) rhubarb_pie = BundleItem(Meal.rhubarb_pie) shrimp_cocktail = BundleItem(Meal.shrimp_cocktail) -pina_colada = IslandBundleItem(Beverage.pina_colada) +pina_colada = BundleItem(Beverage.pina_colada, source=BundleItem.Sources.island) green_algae = BundleItem(WaterItem.green_algae) white_algae = BundleItem(WaterItem.white_algae) @@ -355,9 +355,9 @@ tea_leaves = BundleItem(Vegetable.tea_leaves) blobfish = BundleItem(Fish.blobfish) spook_fish = BundleItem(Fish.spook_fish) -lionfish = IslandBundleItem(Fish.lionfish) -blue_discus = IslandBundleItem(Fish.blue_discus) -stingray = IslandBundleItem(Fish.stingray) +lionfish = BundleItem(Fish.lionfish, source=BundleItem.Sources.island) +blue_discus = BundleItem(Fish.blue_discus, source=BundleItem.Sources.island) +stingray = BundleItem(Fish.stingray, source=BundleItem.Sources.island) spookfish = BundleItem(Fish.spookfish) midnight_squid = BundleItem(Fish.midnight_squid) @@ -379,11 +379,11 @@ bait = BundleItem(Fishing.bait, 100) magnet = BundleItem(Fishing.magnet) wild_bait = BundleItem(Fishing.wild_bait, 10) -magic_bait = IslandBundleItem(Fishing.magic_bait, 5) +magic_bait = BundleItem(Fishing.magic_bait, 5, source=BundleItem.Sources.island) pearl = BundleItem(Gift.pearl) -ginger = IslandBundleItem(Forageable.ginger) -magma_cap = IslandBundleItem(Forageable.magma_cap) +ginger = BundleItem(Forageable.ginger, source=BundleItem.Sources.island) +magma_cap = BundleItem(Forageable.magma_cap, source=BundleItem.Sources.island) wheat_flour = BundleItem(Ingredient.wheat_flour) sugar = BundleItem(Ingredient.sugar) @@ -752,13 +752,13 @@ vault_gambler_items = BundleItem(Currency.qi_coin, 10000) vault_gambler_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.gambler, vault_gambler_items) -vault_carnival_items = FestivalBundleItem(Currency.star_token, 2500) +vault_carnival_items = BundleItem(Currency.star_token, 2500, source=BundleItem.Sources.festival) vault_carnival_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.carnival, vault_carnival_items) vault_walnut_hunter_items = BundleItem(Currency.golden_walnut, 25) vault_walnut_hunter_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.walnut_hunter, vault_walnut_hunter_items) -vault_qi_helper_items = IslandBundleItem(Currency.qi_gem, 25) +vault_qi_helper_items = BundleItem(Currency.qi_gem, 25, source=BundleItem.Sources.island) vault_qi_helper_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.qi_helper, vault_qi_helper_items) vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle] From 76d0ac76387186f0d958d8cbfd2e839eb6dd5990 Mon Sep 17 00:00:00 2001 From: Jouramie Date: Tue, 2 Jan 2024 00:24:31 -0500 Subject: [PATCH 387/482] remove old methods to create island and festival items --- worlds/stardew_valley/bundles/bundle_item.py | 30 +++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/worlds/stardew_valley/bundles/bundle_item.py b/worlds/stardew_valley/bundles/bundle_item.py index d9d571fe6b4d..8aaa67c5f242 100644 --- a/worlds/stardew_valley/bundles/bundle_item.py +++ b/worlds/stardew_valley/bundles/bundle_item.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from abc import ABC, abstractmethod from dataclasses import dataclass @@ -28,45 +30,39 @@ def can_appear(self, options: StardewValleyOptions) -> bool: return options.festival_locations != FestivalLocations.option_disabled -class BundleItemSources: - vanilla = VanillaItemSource() - island = IslandItemSource() - festival = FestivalItemSource() - - @dataclass(frozen=True, order=True) class BundleItem: - item_name: str - amount: int = 1 - quality: str = CropQuality.basic - source: BundleItemSource = BundleItemSources.vanilla - class Sources: vanilla = VanillaItemSource() island = IslandItemSource() festival = FestivalItemSource() + item_name: str + amount: int = 1 + quality: str = CropQuality.basic + source: BundleItemSource = Sources.vanilla + @staticmethod - def money_bundle(amount: int): + def money_bundle(amount: int) -> BundleItem: return BundleItem(Currency.money, amount) - def as_amount(self, amount: int): + def as_amount(self, amount: int) -> BundleItem: return BundleItem(self.item_name, amount, self.quality, self.source) - def as_quality(self, quality: str): + def as_quality(self, quality: str) -> BundleItem: return BundleItem(self.item_name, self.amount, quality, self.source) - def as_quality_crop(self): + def as_quality_crop(self) -> BundleItem: amount = 5 difficult_crops = [Fruit.sweet_gem_berry, Fruit.ancient_fruit] if self.item_name in difficult_crops: amount = 1 return self.as_quality(CropQuality.gold).as_amount(amount) - def as_quality_fish(self): + def as_quality_fish(self) -> BundleItem: return self.as_quality(FishQuality.gold) - def as_quality_forage(self): + def as_quality_forage(self) -> BundleItem: return self.as_quality(ForageQuality.gold) def __repr__(self): From c28acc546b8b97b35aa6332416cbc80337fabfd0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 7 Jan 2024 20:59:25 -0500 Subject: [PATCH 388/482] - Fixed Island Fish bundle name --- worlds/stardew_valley/strings/bundle_names.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/strings/bundle_names.py b/worlds/stardew_valley/strings/bundle_names.py index 2b8ac48b8a86..de8d8af3877f 100644 --- a/worlds/stardew_valley/strings/bundle_names.py +++ b/worlds/stardew_valley/strings/bundle_names.py @@ -52,7 +52,7 @@ class BundleName: quality_fish = "Quality Fish Bundle" master_fisher = "Master Fisher's Bundle" legendary_fish = "Legendary Fish Bundle" - island_fish = "Island Bundle" + island_fish = "Island Fish Bundle" deep_fishing = "Deep Fishing Bundle" tackle = "Tackle Bundle" bait = "Master Baiter Bundle" From d7b1faa25b46fe6d1b28a56c44c46058ffa8dcb4 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 10 Jan 2024 14:35:12 -0500 Subject: [PATCH 389/482] - Add Alien rarecrow and deluxe retaining soil recipe as checks --- worlds/stardew_valley/data/items.csv | 2 ++ worlds/stardew_valley/data/locations.csv | 2 ++ worlds/stardew_valley/logic/logic.py | 1 + worlds/stardew_valley/strings/festival_check_names.py | 1 + 4 files changed, 6 insertions(+) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index a624b071089f..3edc002f9897 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -730,6 +730,8 @@ id,name,classification,groups,mod_name 5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5266,Resource Pack: 5 Staircase,filler,"RESOURCE_PACK", +5267,Auto-Petter,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5268,Auto-Grabber,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill 10002,Magic Level,progression,SKILL_LEVEL_UP,Magic 10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a20cab21a70b..3eb19e9c3513 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1020,6 +1020,7 @@ id,region,name,tags,mod_name 2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, 2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, 2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, +2036,Casino,Rarecrow #3 (Alien),FESTIVAL, 2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", 2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, 2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, @@ -2086,6 +2087,7 @@ id,region,name,tags,mod_name 3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, 3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, 3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", +3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 1fcbc80e588f..b4ba17e04d51 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -456,6 +456,7 @@ def __init__(self, player: int, options: StardewValleyOptions): FestivalCheck.lupini_land_of_clay: self.time.has_year_three & self.money.can_spend(1200), FestivalCheck.secret_santa: self.gifts.has_any_universal_love, FestivalCheck.legend_of_the_winter_star: True_(), + FestivalCheck.rarecrow_3: True_(), FestivalCheck.all_rarecrows: self.region.can_reach(Region.farm) & self.has_all_rarecrows(), }) diff --git a/worlds/stardew_valley/strings/festival_check_names.py b/worlds/stardew_valley/strings/festival_check_names.py index ff34c59e8aad..73a9d3978eab 100644 --- a/worlds/stardew_valley/strings/festival_check_names.py +++ b/worlds/stardew_valley/strings/festival_check_names.py @@ -20,6 +20,7 @@ class FestivalCheck: moonlight_jellies = "Dance of the Moonlight Jellies" rarecrow_1 = "Rarecrow #1 (Turnip Head)" rarecrow_2 = "Rarecrow #2 (Witch)" + rarecrow_3 = "Rarecrow #3 (Alien)" rarecrow_4 = "Rarecrow #4 (Snowman)" rarecrow_5 = "Rarecrow #5 (Woman)" rarecrow_7 = "Rarecrow #7 (Tanuki)" From 732c9d90030e0f0172a482dfc3531760a07361bb Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 10 Jan 2024 14:41:21 -0500 Subject: [PATCH 390/482] - Deluxe Retaining Soil is now tagged as ginger island --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3eb19e9c3513..57a0a28eb3ec 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2087,7 +2087,7 @@ id,region,name,tags,mod_name 3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, 3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, 3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", -3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY", +3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY,GINGER_ISLAND", 5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill 5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill From 4a1bd0e67b0143420cb930aace1df15c4ed05e0e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 10 Jan 2024 14:48:37 -0500 Subject: [PATCH 391/482] - Created tests for monster eradication goals all having rules --- worlds/stardew_valley/test/TestGeneration.py | 58 +++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 5ebcfc2640f8..3208f0ede0a3 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -171,6 +171,13 @@ def test_when_generate_world_then_4_shoes_in_the_pool(self): item_pool = [item.name for item in self.multiworld.itempool] self.assertEqual(item_pool.count("Progressive Footwear"), 4) + def test_when_generate_world_then_all_monster_checks_are_inaccessible(self): + for location in get_real_locations(self, self.multiworld): + if LocationTags.MONSTERSANITY not in location_table[location.name].tags: + continue + with self.subTest(location.name): + self.assertFalse(location.can_reach(self.multiworld.state)) + class TestMonstersanityOnePerCategory(SVTestBase): options = {options.Monstersanity.internal_name: options.Monstersanity.option_one_per_category} @@ -193,6 +200,13 @@ def test_when_generate_world_then_4_shoes_in_the_pool(self): item_pool = [item.name for item in self.multiworld.itempool] self.assertEqual(item_pool.count("Progressive Footwear"), 4) + def test_when_generate_world_then_all_monster_checks_are_inaccessible(self): + for location in get_real_locations(self, self.multiworld): + if LocationTags.MONSTERSANITY not in location_table[location.name].tags: + continue + with self.subTest(location.name): + self.assertFalse(location.can_reach(self.multiworld.state)) + class TestMonstersanityProgressive(SVTestBase): options = {options.Monstersanity.internal_name: options.Monstersanity.option_progressive_goals} @@ -215,12 +229,54 @@ def test_when_generate_world_then_4_shoes_in_the_pool(self): item_pool = [item.name for item in self.multiworld.itempool] self.assertEqual(item_pool.count("Progressive Footwear"), 4) - def test_when_generate_world_then_many_rings_shoes_in_the_pool(self): + def test_when_generate_world_then_many_rings_in_the_pool(self): item_pool = [item.name for item in self.multiworld.itempool] self.assertIn("Hot Java Ring", item_pool) self.assertIn("Wedding Ring", item_pool) self.assertIn("Slime Charmer Ring", item_pool) + def test_when_generate_world_then_all_monster_checks_are_inaccessible(self): + for location in get_real_locations(self, self.multiworld): + if LocationTags.MONSTERSANITY not in location_table[location.name].tags: + continue + with self.subTest(location.name): + self.assertFalse(location.can_reach(self.multiworld.state)) + + +class TestMonstersanitySplit(SVTestBase): + options = {options.Monstersanity.internal_name: options.Monstersanity.option_split_goals} + + def test_when_generate_world_then_no_generic_weapons_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Weapon"), 0) + + def test_when_generate_world_then_5_specific_weapons_of_each_type_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Sword"), 5) + self.assertEqual(item_pool.count("Progressive Club"), 5) + self.assertEqual(item_pool.count("Progressive Dagger"), 5) + + def test_when_generate_world_then_2_slingshots_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Slingshot"), 2) + + def test_when_generate_world_then_4_shoes_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertEqual(item_pool.count("Progressive Footwear"), 4) + + def test_when_generate_world_then_many_rings_in_the_pool(self): + item_pool = [item.name for item in self.multiworld.itempool] + self.assertIn("Hot Java Ring", item_pool) + self.assertIn("Wedding Ring", item_pool) + self.assertIn("Slime Charmer Ring", item_pool) + + def test_when_generate_world_then_all_monster_checks_are_inaccessible(self): + for location in get_real_locations(self, self.multiworld): + if LocationTags.MONSTERSANITY not in location_table[location.name].tags: + continue + with self.subTest(location.name): + self.assertFalse(location.can_reach(self.multiworld.state)) + class TestProgressiveElevator(SVTestBase): options = { From 96711550755f5a0d0cafd56479e4d57f5b07b07e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 10 Jan 2024 14:48:44 -0500 Subject: [PATCH 392/482] - Fix monster names --- worlds/stardew_valley/strings/monster_names.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/strings/monster_names.py b/worlds/stardew_valley/strings/monster_names.py index 00faef8efb16..e995d563f059 100644 --- a/worlds/stardew_valley/strings/monster_names.py +++ b/worlds/stardew_valley/strings/monster_names.py @@ -1,8 +1,8 @@ class Monster: green_slime = "Green Slime" - blue_slime = "Blue Slime" - red_slime = "Red Slime" - purple_slime = "Purple Slime" + blue_slime = "Frost Jelly" + red_slime = "Sludge" # Yeah I know this is weird that these two are the same name + purple_slime = "Sludge" # Blame CA yellow_slime = "Yellow Slime" black_slime = "Black Slime" copper_slime = "Copper Slime" @@ -24,7 +24,7 @@ class Monster: skeleton_mage = "Skeleton Mage" bug = "Bug" bug_dangerous = "Dangerous Bug" - cave_fly = "Cave Fly" + cave_fly = "Fly" cave_fly_dangerous = "Dangerous Cave Fly" grub = "Grub" grub_dangerous = "Dangerous Grub" From 58229168942cddbc0287b449f7585a53ced74349 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Tue, 16 Jan 2024 01:04:21 -0500 Subject: [PATCH 393/482] - Bone Fragment doesn't need Ginger Island --- worlds/stardew_valley/data/locations.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 57a0a28eb3ec..ede08b08c6f6 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1549,7 +1549,7 @@ id,region,name,tags,mod_name 2835,Shipping,Shipsanity: Topaz,SHIPSANITY, 2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, 2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND", +2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, 2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", 2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", From 9955f18ea18d609d0cf6c267e3dbbd2829d87df0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 17 Jan 2024 20:06:13 -0500 Subject: [PATCH 394/482] - Added logic for the new master-angler <-> fishsanity behavior --- worlds/stardew_valley/__init__.py | 5 +- worlds/stardew_valley/logic/base_logic.py | 2 +- worlds/stardew_valley/logic/fishing_logic.py | 19 ++- worlds/stardew_valley/logic/logic.py | 1 + .../stardew_valley/test/TestDynamicGoals.py | 118 ++++++++++++++++++ worlds/stardew_valley/test/TestGeneration.py | 2 - .../test/checks/world_checks.py | 14 ++- 7 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 worlds/stardew_valley/test/TestDynamicGoals.py diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index d6f97c88f6e5..be3915532d27 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -229,7 +229,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_master_angler: self.create_event_location(location_table[GoalName.master_angler], - self.logic.fishing.can_catch_every_fish(), + self.logic.fishing.can_catch_every_fish_in_slot(self.get_all_location_names()), Event.victory) elif self.options.goal == Goal.option_complete_collection: self.create_event_location(location_table[GoalName.complete_museum], @@ -278,6 +278,9 @@ def setup_victory(self): self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player) + def get_all_location_names(self) -> List[str]: + return list(location.name for location in self.multiworld.get_locations(self.player)) + def create_item(self, item: Union[str, ItemData], override_classification: ItemClassification = None) -> StardewItem: if isinstance(item, str): item = item_table[item] diff --git a/worlds/stardew_valley/logic/base_logic.py b/worlds/stardew_valley/logic/base_logic.py index 2ff35f08e7d1..57303ce13322 100644 --- a/worlds/stardew_valley/logic/base_logic.py +++ b/worlds/stardew_valley/logic/base_logic.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TypeVar, Generic, Dict +from typing import TypeVar, Generic, Dict, List from ..options import StardewValleyOptions from ..stardew_rule import StardewRule diff --git a/worlds/stardew_valley/logic/fishing_logic.py b/worlds/stardew_valley/logic/fishing_logic.py index 31046eb49d1a..65b3cdc2ac88 100644 --- a/worlds/stardew_valley/logic/fishing_logic.py +++ b/worlds/stardew_valley/logic/fishing_logic.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, List from Utils import cache_self1 from .base_logic import BaseLogicMixin, BaseLogic @@ -8,7 +8,8 @@ from .skill_logic import SkillLogicMixin from .tool_logic import ToolLogicMixin from ..data import FishItem, fish_data -from ..options import ExcludeGingerIsland +from ..locations import LocationTags, locations_by_tag +from ..options import ExcludeGingerIsland, Fishsanity from ..options import SpecialOrderLocations from ..stardew_rule import StardewRule, True_, False_, And from ..strings.fish_names import SVEFish @@ -75,7 +76,7 @@ def can_catch_quality_fish(self, fish_quality: str) -> StardewRule: return False_() def can_catch_every_fish(self) -> StardewRule: - rules = [self.logic.skill.has_level(Skill.fishing, 10), self.logic.tool.has_fishing_rod(4)] + rules = [self.has_max_fishing()] exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true exclude_extended_family = self.options.special_order_locations != SpecialOrderLocations.option_board_qi for fish in fish_data.get_fish_for_mods(self.options.mods.value): @@ -85,3 +86,15 @@ def can_catch_every_fish(self) -> StardewRule: continue rules.append(self.logic.fishing.can_catch_fish(fish)) return And(*rules) + + def can_catch_every_fish_in_slot(self, all_location_names_in_slot: List[str]) -> StardewRule: + if self.options.fishsanity == Fishsanity.option_none: + return self.can_catch_every_fish() + + rules = [self.has_max_fishing()] + + for fishsanity_location in locations_by_tag[LocationTags.FISHSANITY]: + if fishsanity_location.name not in all_location_names_in_slot: + continue + rules.append(self.logic.region.can_reach_location(fishsanity_location.name)) + return And(*rules) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index b4ba17e04d51..d460355dc713 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -1,6 +1,7 @@ from __future__ import annotations from dataclasses import dataclass +from typing import List from .ability_logic import AbilityLogicMixin from .action_logic import ActionLogicMixin diff --git a/worlds/stardew_valley/test/TestDynamicGoals.py b/worlds/stardew_valley/test/TestDynamicGoals.py new file mode 100644 index 000000000000..41668e499304 --- /dev/null +++ b/worlds/stardew_valley/test/TestDynamicGoals.py @@ -0,0 +1,118 @@ +from typing import List, Tuple + +from . import SVTestBase +from .checks.world_checks import can_reach_victory +from .. import options, StardewItem +from ..strings.ap_names.ap_weapon_names import APWeapon +from ..strings.ap_names.transport_names import Transportation +from ..strings.fish_names import Fish +from ..strings.tool_names import APTool +from ..strings.wallet_item_names import Wallet + + +def collect_fishing_abilities(tester: SVTestBase): + for i in range(4): + tester.multiworld.state.collect(tester.world.create_item(APTool.fishing_rod), event=False) + tester.multiworld.state.collect(tester.world.create_item(APTool.pickaxe), event=False) + tester.multiworld.state.collect(tester.world.create_item(APTool.axe), event=False) + tester.multiworld.state.collect(tester.world.create_item(APWeapon.weapon), event=False) + for i in range(10): + tester.multiworld.state.collect(tester.world.create_item("Fishing Level"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Combat Level"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Mining Level"), event=False) + for i in range(17): + tester.multiworld.state.collect(tester.world.create_item("Progressive Mine Elevator"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Spring"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Summer"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Fall"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Winter"), event=False) + tester.multiworld.state.collect(tester.world.create_item(Transportation.desert_obelisk), event=False) + tester.multiworld.state.collect(tester.world.create_item("Railroad Boulder Removed"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Island North Turtle"), event=False) + tester.multiworld.state.collect(tester.world.create_item("Island West Turtle"), event=False) + + +def create_and_collect(tester: SVTestBase, item_name: str) -> StardewItem: + item = tester.world.create_item(item_name) + tester.multiworld.state.collect(item, event=False) + return item + + +def create_and_collect_fishing_access_items(tester: SVTestBase) -> List[Tuple[StardewItem, str]]: + items = [(create_and_collect(tester, Wallet.dark_talisman), Fish.void_salmon), + (create_and_collect(tester, Wallet.rusty_key), Fish.slimejack), + (create_and_collect(tester, "Progressive Mine Elevator"), Fish.lava_eel), + (create_and_collect(tester, Transportation.island_obelisk), Fish.lionfish), + (create_and_collect(tester, "Island Resort"), Fish.stingray)] + return items + + +def assert_item_was_necessary_for_victory(tester: SVTestBase, item: StardewItem): + tester.assertTrue(*can_reach_victory(tester.multiworld)) + tester.multiworld.state.remove(item) + tester.assertFalse(*can_reach_victory(tester.multiworld)) + tester.multiworld.state.collect(item, event=False) + tester.assertTrue(*can_reach_victory(tester.multiworld)) + + +def assert_item_was_not_necessary_for_victory(tester: SVTestBase, item: StardewItem): + tester.assertTrue(*can_reach_victory(tester.multiworld)) + tester.multiworld.state.remove(item) + tester.assertTrue(*can_reach_victory(tester.multiworld)) + tester.multiworld.state.collect(item, event=False) + tester.assertTrue(*can_reach_victory(tester.multiworld)) + + +class TestMasterAnglerNoFishsanity(SVTestBase): + options = {options.Goal.internal_name: options.Goal.option_master_angler, + options.Fishsanity.internal_name: options.Fishsanity.option_none, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false} + + def test_need_all_fish_to_win(self): + collect_fishing_abilities(self) + self.assertFalse(*can_reach_victory(self.multiworld)) + critical_items = create_and_collect_fishing_access_items(self) + self.assertTrue(*can_reach_victory(self.multiworld)) + for item, fish in critical_items: + with self.subTest(f"Needed: {fish}"): + assert_item_was_necessary_for_victory(self, item) + + +class TestMasterAnglerNoFishsanityNoGingerIsland(SVTestBase): + options = {options.Goal.internal_name: options.Goal.option_master_angler, + options.Fishsanity.internal_name: options.Fishsanity.option_none, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true} + + def test_need_fish_to_win(self): + collect_fishing_abilities(self) + self.assertFalse(*can_reach_victory(self.multiworld)) + items = create_and_collect_fishing_access_items(self) + self.assertTrue(*can_reach_victory(self.multiworld)) + unecessary_items = [(item, fish) for (item, fish) in items if fish in [Fish.lionfish, Fish.stingray]] + necessary_items = [(item, fish) for (item, fish) in items if (item, fish) not in unecessary_items] + for item, fish in necessary_items: + with self.subTest(f"Needed: {fish}"): + assert_item_was_necessary_for_victory(self, item) + for item, fish in unecessary_items: + with self.subTest(f"Not Needed: {fish}"): + assert_item_was_not_necessary_for_victory(self, item) + + +class TestMasterAnglerFishsanityNoHardFish(SVTestBase): + options = {options.Goal.internal_name: options.Goal.option_master_angler, + options.Fishsanity.internal_name: options.Fishsanity.option_exclude_hard_fish, + options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false} + + def test_need_fish_to_win(self): + collect_fishing_abilities(self) + self.assertFalse(*can_reach_victory(self.multiworld)) + items = create_and_collect_fishing_access_items(self) + self.assertTrue(*can_reach_victory(self.multiworld)) + unecessary_items = [(item, fish) for (item, fish) in items if fish in [Fish.void_salmon, Fish.stingray, Fish.lava_eel]] + necessary_items = [(item, fish) for (item, fish) in items if (item, fish) not in unecessary_items] + for item, fish in necessary_items: + with self.subTest(f"Needed: {fish}"): + assert_item_was_necessary_for_victory(self, item) + for item, fish in unecessary_items: + with self.subTest(f"Not Needed: {fish}"): + assert_item_was_not_necessary_for_victory(self, item) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 3208f0ede0a3..148849cde27f 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -961,7 +961,6 @@ def test_only_full_shipment_shipsanity_locations(self): def test_exclude_island_items_shipsanity_locations(self): location_names = [location.name for location in self.multiworld.get_locations(self.player)] self.assertNotIn("Shipsanity: Cinder Shard", location_names) - self.assertNotIn("Shipsanity: Bone Fragment", location_names) self.assertNotIn("Shipsanity: Radioactive Ore", location_names) self.assertNotIn("Shipsanity: Radioactive Bar", location_names) self.assertNotIn("Shipsanity: Banana", location_names) @@ -1050,7 +1049,6 @@ def test_only_full_shipment_and_fish_shipsanity_locations(self): def test_exclude_island_items_shipsanity_locations(self): location_names = [location.name for location in self.multiworld.get_locations(self.player)] self.assertNotIn("Shipsanity: Cinder Shard", location_names) - self.assertNotIn("Shipsanity: Bone Fragment", location_names) self.assertNotIn("Shipsanity: Radioactive Ore", location_names) self.assertNotIn("Shipsanity: Radioactive Bar", location_names) self.assertNotIn("Shipsanity: Banana", location_names) diff --git a/worlds/stardew_valley/test/checks/world_checks.py b/worlds/stardew_valley/test/checks/world_checks.py index 2e9d6a88c1b0..d99bc628c45a 100644 --- a/worlds/stardew_valley/test/checks/world_checks.py +++ b/worlds/stardew_valley/test/checks/world_checks.py @@ -17,12 +17,20 @@ def assert_victory_exists(tester: unittest.TestCase, multiworld: MultiWorld): tester.assertIn(StardewItem("Victory", ItemClassification.progression, None, 1), multiworld.get_items()) +def can_reach_victory(multiworld: MultiWorld) -> (bool, str): + victory = multiworld.find_item("Victory", 1) + can_win = victory.can_reach(multiworld.state) + return can_win, victory.access_rule.explain(multiworld.state) + + +def assert_can_reach_victory(tester: unittest.TestCase, multiworld: MultiWorld): + tester.assertTrue(*can_reach_victory(multiworld)) + + def collect_all_then_assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): for item in multiworld.get_items(): multiworld.state.collect(item) - victory = multiworld.find_item("Victory", 1) - can_win = victory.can_reach(multiworld.state) - tester.assertTrue(can_win, victory.access_rule.explain(multiworld.state)) + assert_can_reach_victory(tester, multiworld) def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): From bd6c2ad60543a99709444d3b7621a323ce2c22b9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 22 Jan 2024 16:19:22 -0500 Subject: [PATCH 395/482] - Switched the farm type to a setting --- worlds/stardew_valley/__init__.py | 22 +------------------ worlds/stardew_valley/data/items.csv | 7 ------ worlds/stardew_valley/items.py | 1 - worlds/stardew_valley/logic/shipping_logic.py | 18 ++++++++++++--- worlds/stardew_valley/options.py | 15 +++++++++++++ worlds/stardew_valley/test/TestGeneration.py | 2 -- worlds/stardew_valley/test/TestItems.py | 7 ++---- worlds/stardew_valley/test/mods/TestMods.py | 2 -- 8 files changed, 33 insertions(+), 41 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index be3915532d27..ab4bae5345f3 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -129,7 +129,6 @@ def add_location(name: str, code: Optional[int], region: str): def create_items(self): self.total_progression_items = 0 - self.precollect_farm_type() self.precollect_starting_season() items_to_exclude = [excluded_items for excluded_items in self.multiworld.precollected_items[self.player] @@ -153,25 +152,6 @@ def create_items(self): self.setup_player_events() self.setup_victory() - def precollect_farm_type(self): - all_farm_types = items_by_group[Group.FARM_TYPE] - all_farm_type_names = [farm_type.name for farm_type in all_farm_types] - - chosen_farm_types = [] - for item in self.multiworld.precollected_items[self.player]: - if item.name in all_farm_type_names: - chosen_farm_types.append(item) - - for item in chosen_farm_types: - self.multiworld.precollected_items[self.player].remove(item) - - chosen_farm_types = [item.name for item in chosen_farm_types] - if not chosen_farm_types: - chosen_farm_types = all_farm_type_names - - starting_farm = self.create_starting_item(self.multiworld.random.choice(chosen_farm_types)) - self.multiworld.push_precollected(starting_farm) - def precollect_starting_season(self): if self.options.season_randomization == SeasonRandomization.option_progressive: return @@ -249,7 +229,7 @@ def setup_victory(self): Event.victory) elif self.options.goal == Goal.option_full_shipment: self.create_event_location(location_table[GoalName.full_shipment], - self.logic.shipping.can_ship_everything(), + self.logic.shipping.can_ship_everything_in_slot(self.get_all_location_names()), Event.victory) elif self.options.goal == Goal.option_gourmet_chef: self.create_event_location(location_table[GoalName.gourmet_chef], diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 3edc002f9897..4a946c04b3b3 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -435,13 +435,6 @@ id,name,classification,groups,mod_name 459,Chest Recipe,progression,CRAFTSANITY, 460,Wood Sign Recipe,progression,CRAFTSANITY, 461,Stone Sign Recipe,progression,CRAFTSANITY, -462,Standard Farm,progression,FARM_TYPE, -463,Riverland Farm,progression,FARM_TYPE, -464,Forest Farm,progression,FARM_TYPE, -465,Hill-top Farm,progression,FARM_TYPE, -466,Wilderness Farm,progression,FARM_TYPE, -467,Four Corners Farm,progression,FARM_TYPE, -468,Beach Farm,progression,FARM_TYPE, 469,Railroad Boulder Removed,progression,, 470,Fruit Bats,progression,, 471,Mushroom Boxes,progression,, diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index d7f0a1db8b6a..bebc888c2f70 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -80,7 +80,6 @@ class Group(enum.Enum): CHEFSANITY_FRIENDSHIP = enum.auto() CHEFSANITY_SKILL = enum.auto() CRAFTSANITY = enum.auto() - FARM_TYPE = enum.auto() # Mods MAGIC_SPELL = enum.auto() MOD_WARP = enum.auto() diff --git a/worlds/stardew_valley/logic/shipping_logic.py b/worlds/stardew_valley/logic/shipping_logic.py index b004d48006e0..52c97561b326 100644 --- a/worlds/stardew_valley/logic/shipping_logic.py +++ b/worlds/stardew_valley/logic/shipping_logic.py @@ -1,5 +1,5 @@ from functools import cached_property -from typing import Union +from typing import Union, List from Utils import cache_self1 from .base_logic import BaseLogic, BaseLogicMixin @@ -8,9 +8,9 @@ from .received_logic import ReceivedLogicMixin from .region_logic import RegionLogicMixin from ..locations import LocationTags, locations_by_tag -from ..options import ExcludeGingerIsland +from ..options import ExcludeGingerIsland, Shipsanity from ..options import SpecialOrderLocations -from ..stardew_rule import StardewRule +from ..stardew_rule import StardewRule, And from ..strings.ap_names.event_names import Event from ..strings.building_names import Building @@ -46,3 +46,15 @@ def can_ship_everything(self) -> StardewRule: continue all_items_to_ship.append(location.name[len(shipsanity_prefix):]) return self.logic.building.has_building(Building.shipping_bin) & self.logic.has_all(*all_items_to_ship) + + def can_ship_everything_in_slot(self, all_location_names_in_slot: List[str]) -> StardewRule: + if self.options.shipsanity == Shipsanity.option_none: + return self.can_ship_everything() + + rules = [self.logic.building.has_building(Building.shipping_bin)] + + for shipsanity_location in locations_by_tag[LocationTags.SHIPSANITY]: + if shipsanity_location.name not in all_location_names_in_slot: + continue + rules.append(self.logic.region.can_reach_location(shipsanity_location.name)) + return And(*rules) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 22b170a86202..147eab059702 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -57,6 +57,20 @@ def get_option_name(cls, value) -> str: return super().get_option_name(value) +class FarmType(Choice): + """What farm to play on?""" + internal_name = "farm_type" + display_name = "Farm Type" + default = "random" + option_standard = 0 + option_riverland = 1 + option_forest = 2 + option_hill_top = 3 + option_wilderness = 4 + option_four_corners = 5 + option_beach = 6 + + class StartingMoney(NamedRange): """Amount of gold when arriving at the farm. Set to -1 or unlimited for infinite money""" @@ -679,6 +693,7 @@ class Mods(OptionSet): @dataclass class StardewValleyOptions(PerGameCommonOptions): goal: Goal + farm_type: FarmType starting_money: StartingMoney profit_margin: ProfitMargin bundle_randomization: BundleRandomization diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 148849cde27f..16a12dd11b1f 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -41,7 +41,6 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) - items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] for progression_item in progression_items: @@ -93,7 +92,6 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(season.name for season in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) - items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] for progression_item in progression_items: with self.subTest(f"{progression_item.name}"): diff --git a/worlds/stardew_valley/test/TestItems.py b/worlds/stardew_valley/test/TestItems.py index b37b0bad7619..8887450e8e7a 100644 --- a/worlds/stardew_valley/test/TestItems.py +++ b/worlds/stardew_valley/test/TestItems.py @@ -87,9 +87,6 @@ def test_can_start_on_any_farm(self): break seed = random.randrange(sys.maxsize) multiworld = setup_solo_multiworld(seed=seed) - starting_farm_items = [item for item in multiworld.precollected_items[1] if item.name in all_farms] - farm_items = [item for item in multiworld.get_items() if item.name in all_farms] - self.assertEqual(len(starting_farm_items), 1) - self.assertEqual(len(farm_items), 0) - starting_farms_rolled.add(f"{starting_farm_items[0]}") + starting_farm = multiworld.worlds[1].fill_slot_data()["farm_type"] + starting_farms_rolled.add(starting_farm) self.assertEqual(len(starting_farms_rolled), 7) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 6eb451cb973c..e5504a8f9ee8 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -95,7 +95,6 @@ def test_all_progression_items_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) - items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] @@ -123,7 +122,6 @@ def test_all_progression_items_except_island_are_added_to_the_pool(self): items_to_ignore.extend(season.name for season in items.items_by_group[Group.SEASON]) items_to_ignore.extend(weapon.name for weapon in items.items_by_group[Group.WEAPON]) items_to_ignore.extend(baby.name for baby in items.items_by_group[Group.BABY]) - items_to_ignore.extend(farm_type.name for farm_type in items.items_by_group[Group.FARM_TYPE]) items_to_ignore.extend(resource_pack.name for resource_pack in items.items_by_group[Group.RESOURCE_PACK]) progression_items = [item for item in items.all_items if item.classification is ItemClassification.progression and item.name not in items_to_ignore] From d711dbaf74906d2e4e1ff97a9c1a4402780ec2fc Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 22 Jan 2024 16:54:08 -0500 Subject: [PATCH 396/482] - Add new tests validating that the presets have been configured properly for new settings --- worlds/stardew_valley/presets.py | 54 +++++++++++++++++++++-- worlds/stardew_valley/test/TestPresets.py | 21 +++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 worlds/stardew_valley/test/TestPresets.py diff --git a/worlds/stardew_valley/presets.py b/worlds/stardew_valley/presets.py index 03203c7549f3..020b3f49277f 100644 --- a/worlds/stardew_valley/presets.py +++ b/worlds/stardew_valley/presets.py @@ -5,12 +5,13 @@ BackpackProgression, ToolProgression, ElevatorProgression, SkillProgression, BuildingProgression, FestivalLocations, ArcadeMachineLocations, \ SpecialOrderLocations, QuestLocations, Fishsanity, Museumsanity, Friendsanity, FriendsanityHeartSize, NumberOfMovementBuffs, NumberOfLuckBuffs, \ ExcludeGingerIsland, TrapItems, MultipleDaySleepEnabled, MultipleDaySleepCost, ExperienceMultiplier, FriendshipMultiplier, DebrisMultiplier, QuickStart, \ - Gifting + Gifting, FarmType, Monstersanity, Shipsanity, Cooksanity, Chefsanity, Craftsanity all_random_settings = { "progression_balancing": "random", "accessibility": "random", Goal.internal_name: "random", + FarmType.internal_name: "random", StartingMoney.internal_name: "random", ProfitMargin.internal_name: "random", BundleRandomization.internal_name: "random", @@ -29,6 +30,11 @@ QuestLocations.internal_name: "random", Fishsanity.internal_name: "random", Museumsanity.internal_name: "random", + Monstersanity.internal_name: "random", + Shipsanity.internal_name: "random", + Cooksanity.internal_name: "random", + Chefsanity.internal_name: "random", + Craftsanity.internal_name: "random", Friendsanity.internal_name: "random", FriendsanityHeartSize.internal_name: "random", NumberOfMovementBuffs.internal_name: "random", @@ -49,6 +55,7 @@ "progression_balancing": ProgressionBalancing.default, "accessibility": Accessibility.option_items, Goal.internal_name: Goal.option_community_center, + FarmType.internal_name: "random", StartingMoney.internal_name: "very rich", ProfitMargin.internal_name: "double", BundleRandomization.internal_name: BundleRandomization.option_thematic, @@ -67,6 +74,11 @@ QuestLocations.internal_name: "minimum", Fishsanity.internal_name: Fishsanity.option_only_easy_fish, Museumsanity.internal_name: Museumsanity.option_milestones, + Monstersanity.internal_name: Monstersanity.option_one_per_category, + Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_none, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, FriendsanityHeartSize.internal_name: 4, NumberOfMovementBuffs.internal_name: 8, @@ -87,6 +99,7 @@ "progression_balancing": 25, "accessibility": Accessibility.option_locations, Goal.internal_name: Goal.option_community_center, + FarmType.internal_name: "random", StartingMoney.internal_name: "rich", ProfitMargin.internal_name: 150, BundleRandomization.internal_name: BundleRandomization.option_thematic, @@ -105,6 +118,11 @@ QuestLocations.internal_name: "normal", Fishsanity.internal_name: Fishsanity.option_exclude_legendaries, Museumsanity.internal_name: Museumsanity.option_milestones, + Monstersanity.internal_name: Monstersanity.option_one_per_monster, + Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_queen_of_sauce, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_starting_npcs, FriendsanityHeartSize.internal_name: 4, NumberOfMovementBuffs.internal_name: 6, @@ -125,6 +143,7 @@ "progression_balancing": 0, "accessibility": Accessibility.option_locations, Goal.internal_name: Goal.option_grandpa_evaluation, + FarmType.internal_name: "random", StartingMoney.internal_name: "extra", ProfitMargin.internal_name: "normal", BundleRandomization.internal_name: BundleRandomization.option_thematic, @@ -143,6 +162,11 @@ QuestLocations.internal_name: "lots", Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, + Monstersanity.internal_name: Monstersanity.option_progressive_goals, + Shipsanity.internal_name: Shipsanity.option_crops, + Cooksanity.internal_name: Cooksanity.option_queen_of_sauce, + Chefsanity.internal_name: Chefsanity.option_qos_and_purchases, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_all, FriendsanityHeartSize.internal_name: 4, NumberOfMovementBuffs.internal_name: 4, @@ -163,6 +187,7 @@ "progression_balancing": 0, "accessibility": Accessibility.option_locations, Goal.internal_name: Goal.option_community_center, + FarmType.internal_name: "random", StartingMoney.internal_name: "vanilla", ProfitMargin.internal_name: "half", BundleRandomization.internal_name: BundleRandomization.option_shuffled, @@ -181,6 +206,11 @@ QuestLocations.internal_name: "maximum", Fishsanity.internal_name: Fishsanity.option_special, Museumsanity.internal_name: Museumsanity.option_all, + Monstersanity.internal_name: Monstersanity.option_split_goals, + Shipsanity.internal_name: Shipsanity.option_full_shipment_with_fish, + Cooksanity.internal_name: Cooksanity.option_queen_of_sauce, + Chefsanity.internal_name: Chefsanity.option_qos_and_purchases, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_all_with_marriage, FriendsanityHeartSize.internal_name: 4, NumberOfMovementBuffs.internal_name: 2, @@ -201,6 +231,7 @@ "progression_balancing": ProgressionBalancing.default, "accessibility": Accessibility.option_items, Goal.internal_name: Goal.option_bottom_of_the_mines, + FarmType.internal_name: "random", StartingMoney.internal_name: "filthy rich", ProfitMargin.internal_name: "quadruple", BundleRandomization.internal_name: BundleRandomization.option_thematic, @@ -219,6 +250,11 @@ QuestLocations.internal_name: "none", Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_none, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, FriendsanityHeartSize.internal_name: 4, NumberOfMovementBuffs.internal_name: 10, @@ -235,10 +271,11 @@ "death_link": "false", } -lowsanity_settings = { +minsanity_settings = { "progression_balancing": ProgressionBalancing.default, "accessibility": Accessibility.option_minimal, Goal.internal_name: Goal.default, + FarmType.internal_name: "random", StartingMoney.internal_name: StartingMoney.default, ProfitMargin.internal_name: ProfitMargin.default, BundleRandomization.internal_name: BundleRandomization.default, @@ -257,6 +294,11 @@ QuestLocations.internal_name: "none", Fishsanity.internal_name: Fishsanity.option_none, Museumsanity.internal_name: Museumsanity.option_none, + Monstersanity.internal_name: Monstersanity.option_none, + Shipsanity.internal_name: Shipsanity.option_none, + Cooksanity.internal_name: Cooksanity.option_none, + Chefsanity.internal_name: Chefsanity.option_none, + Craftsanity.internal_name: Craftsanity.option_none, Friendsanity.internal_name: Friendsanity.option_none, FriendsanityHeartSize.internal_name: FriendsanityHeartSize.default, NumberOfMovementBuffs.internal_name: NumberOfMovementBuffs.default, @@ -277,6 +319,7 @@ "progression_balancing": ProgressionBalancing.default, "accessibility": Accessibility.option_locations, Goal.internal_name: Goal.default, + FarmType.internal_name: "random", StartingMoney.internal_name: StartingMoney.default, ProfitMargin.internal_name: ProfitMargin.default, BundleRandomization.internal_name: BundleRandomization.default, @@ -295,6 +338,11 @@ QuestLocations.internal_name: "maximum", Fishsanity.internal_name: Fishsanity.option_all, Museumsanity.internal_name: Museumsanity.option_all, + Monstersanity.internal_name: Monstersanity.option_progressive_goals, + Shipsanity.internal_name: Shipsanity.option_everything, + Cooksanity.internal_name: Cooksanity.option_all, + Chefsanity.internal_name: Chefsanity.option_all, + Craftsanity.internal_name: Craftsanity.option_all, Friendsanity.internal_name: Friendsanity.option_all, FriendsanityHeartSize.internal_name: 1, NumberOfMovementBuffs.internal_name: 12, @@ -318,6 +366,6 @@ "Hard": hard_settings, "Nightmare": nightmare_settings, "Short": short_settings, - "Lowsanity": lowsanity_settings, + "Minsanity": minsanity_settings, "Allsanity": allsanity_settings, } diff --git a/worlds/stardew_valley/test/TestPresets.py b/worlds/stardew_valley/test/TestPresets.py new file mode 100644 index 000000000000..2bb1c7fbaeaf --- /dev/null +++ b/worlds/stardew_valley/test/TestPresets.py @@ -0,0 +1,21 @@ +import builtins +import inspect + +from Options import PerGameCommonOptions, OptionSet +from . import SVTestCase +from .. import sv_options_presets, StardewValleyOptions + + +class TestPresets(SVTestCase): + def test_all_presets_explicitly_set_all_options(self): + all_option_names = {option_key for option_key in StardewValleyOptions.type_hints} + omitted_option_names = {option_key for option_key in PerGameCommonOptions.type_hints} + mandatory_option_names = {option_key for option_key in all_option_names + if option_key not in omitted_option_names and + not issubclass(StardewValleyOptions.type_hints[option_key], OptionSet)} + + for preset_name in sv_options_presets: + with self.subTest(f"{preset_name}"): + for option_name in mandatory_option_names: + with self.subTest(f"{preset_name} -> {option_name}"): + self.assertIn(option_name, sv_options_presets[preset_name]) \ No newline at end of file From a7eee38fdd4f3bfad32e2d5c7be224c45735e653 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 12 Dec 2023 23:11:37 -0600 Subject: [PATCH 397/482] Fix DL and Scarlett --- .../logic/relationship_logic.py | 3 ++ .../stardew_valley/mods/logic/quests_logic.py | 31 ++++++++++--------- worlds/stardew_valley/rules.py | 12 ++++--- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 5baf6bf58458..2bc0850b7b55 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -17,6 +17,7 @@ from ..strings.crop_names import Fruit from ..strings.generic_names import Generic from ..strings.gift_names import Gift +from ..strings.quest_names import Quest from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC @@ -134,6 +135,8 @@ def can_meet(self, npc: str) -> StardewRule: rules.append(scarlett_job & (scarlett_spring | scarlett_summer | scarlett_fall)) elif npc == ModNPC.morgan: rules.append(self.logic.received(SVEQuestItem.morgan_schooling)) + elif npc == ModNPC.goblin: + rules.append(self.logic.region.can_reach_all((Region.witch_hut, Region.wizard_tower))) return And(*rules) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 245c79a256a4..fb4bd3537ba4 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -3,6 +3,7 @@ from ..mod_data import ModNames from ...logic.base_logic import BaseLogic, BaseLogicMixin from ...logic.has_logic import HasLogicMixin +from ...logic.quest_logic import QuestLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin @@ -18,7 +19,7 @@ from ...strings.material_names import Material from ...strings.metal_names import Ore, MetalBar from ...strings.monster_drop_names import Loot -from ...strings.quest_names import ModQuest +from ...strings.quest_names import Quest, ModQuest from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season from ...strings.villager_names import ModNPC @@ -31,7 +32,7 @@ def __init__(self, *args, **kwargs): self.quest = ModQuestLogic(*args, **kwargs) -class ModQuestLogic(BaseLogic[Union[HasLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin]]): +class ModQuestLogic(BaseLogic[Union[HasLogicMixin, QuestLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin]]): def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = dict() quests.update(self._get_juna_quest_rules()) @@ -72,14 +73,14 @@ def _get_sve_quest_rules(self): return {} return { - ModQuest.RailroadBoulder: (self.logic.received(Wallet.skull_key) & self.logic.has_all(Ore.iridium, Material.coal) & - self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad)), - ModQuest.GrandpasShed: (self.logic.has_all(Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone) & - self.logic.region.can_reach(SVERegion.grandpas_shed)), - ModQuest.MarlonsBoat: (self.logic.has_all(Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat) & - self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit)), + ModQuest.RailroadBoulder: self.logic.received(Wallet.skull_key) & self.logic.has((Ore.iridium, Material.coal)) & + self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad), + ModQuest.GrandpasShed: self.logic.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & + self.logic.region.can_reach(SVERegion.grandpas_shed), + ModQuest.MarlonsBoat: self.logic.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & + self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.logic.has_all(SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root), + ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul), } @@ -87,13 +88,15 @@ def _get_distant_lands_quest_rules(self): if ModNames.distant_lands not in self.options.mods: return {} - return { - ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.has(Fertilizer.deluxe), - ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.deluxe), + return{ + ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.has(Fertilizer.deluxe) & + self.logic.quest.can_complete_quest(Quest.magic_ink), + ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.deluxe) & + self.logic.quest.can_complete_quest(Quest.magic_ink), ModQuest.ANewPot: self.logic.region.can_reach(Region.saloon) & self.logic.region.can_reach(Region.sam_house) & self.logic.region.can_reach(Region.pierre_store) & - self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron), + self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron) & self.logic.relationship.has_hearts(ModNPC.goblin, 6), ModQuest.FancyBlanketTask: self.logic.region.can_reach(Region.haley_house) & self.logic.has(AnimalProduct.wool) & - self.logic.has(ArtisanGood.cloth) + self.logic.has(ArtisanGood.cloth) & self.logic.relationship.has_hearts(ModNPC.goblin, 10) } diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 64a9bcb51aa4..8984487c9241 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -19,9 +19,9 @@ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And from .strings.ap_names.event_names import Event -from .strings.ap_names.mods.mod_items import SVELocation from .strings.ap_names.mods.mod_items import SVEQuestItem from .strings.ap_names.transport_names import Transportation +from .strings.ap_names.mods.mod_items import SVELocation from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building from .strings.bundle_names import CCRoom @@ -853,7 +853,8 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze: Heal", player), logic.has("Life Elixir")) MultiWorldRules.add_rule(multiworld.get_location("Analyze All Life School Locations", player), - logic.has_all("Coffee", "Life Elixir") & logic.ability.can_mine_perfectly()) + (logic.has("Coffee") & logic.has("Life Elixir") + & logic.ability.can_mine_perfectly())) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Descend", player), logic.region.can_reach(Region.mines)) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Fireball", player), @@ -882,8 +883,9 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i MultiWorldRules.add_rule(multiworld.get_location("Analyze Every Magic School Location", player), (logic.tool.has_tool("Watering Can", "Basic") & logic.tool.has_tool("Hoe", "Basic") & (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) & - logic.has_all("Coffee", "Life Elixir", "Earth Crystal", "Fire Quartz") & - logic.ability.can_mine_perfectly() & logic.skill.can_fish(difficulty=85) & + logic.has("Coffee") & logic.has("Life Elixir") + & logic.ability.can_mine_perfectly() & logic.has("Earth Crystal") & + logic.has("Fire Quartz") & logic.skill.can_fish(difficulty=85) & logic.region.can_reach(Region.witch_hut) & logic.region.can_reach(Region.mines_floor_100) & logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12))) @@ -902,6 +904,8 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl logic.has("Aegis Elixir")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), logic.quest.can_complete_quest(Quest.magic_ink)) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.railroad_to_grampleton_station, player), + logic.received(SVEQuestItem.scarlett_job_offer)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), From 89920bb6b829355d4027b639c9bb8637676f1488 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 12 Dec 2023 23:19:11 -0600 Subject: [PATCH 398/482] Remove unneeded strings --- worlds/stardew_valley/logic/relationship_logic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 2bc0850b7b55..e7b867c1277e 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -17,7 +17,6 @@ from ..strings.crop_names import Fruit from ..strings.generic_names import Generic from ..strings.gift_names import Gift -from ..strings.quest_names import Quest from ..strings.region_names import Region from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC From 6fad23dcea2b390e553959c1d3929d800394a2f5 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 13 Dec 2023 12:57:22 -0600 Subject: [PATCH 399/482] Make mod skill logic smoother. --- .../stardew_valley/mods/logic/skills_logic.py | 17 ++++++++++++++--- .../strings/ap_names/mods/mod_items.py | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index a32fecd8ff0c..4862b95f973b 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -15,6 +15,7 @@ from ...mods.mod_data import ModNames from ...options import SkillProgression from ...stardew_rule import StardewRule, False_, True_ +from ...strings.ap_names.mods.mod_items import SkillItem from ...strings.building_names import Building from ...strings.geode_names import Geode from ...strings.machine_names import Machine @@ -59,8 +60,9 @@ def can_earn_mod_skill_level(self, skill: str, level: int) -> StardewRule: def can_earn_luck_skill_level(self, level: int) -> StardewRule: if level >= 6: return self.logic.fishing.can_fish_chests() | self.logic.action.can_open_geode(Geode.magma) - else: + if level >= 3: return self.logic.fishing.can_fish_chests() | self.logic.action.can_open_geode(Geode.geode) + return True_() # You can literally wake up and or get them by opening starting chests. def can_earn_magic_skill_level(self, level: int) -> StardewRule: spell_count = [self.logic.received(MagicSpell.clear_debris), self.logic.received(MagicSpell.water), @@ -80,8 +82,17 @@ def can_earn_socializing_skill_level(self, level: int) -> StardewRule: return self.logic.count(level * 2, *villager_count) def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: - if level >= 6: - return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.gold) + shifter_rule = True_() + preservation_rule = True_() + if self.options.skill_progression == self.options.skill_progression.option_progressive: + shifter_rule = self.logic.received(SkillItem.archaeology_level, 4) + preservation_rule = self.logic.received(SkillItem.archaeology_level, 7) + if level >= 8: + return (self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.gold)) & shifter_rule & preservation_rule + if level >= 5: + return (self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iron)) & shifter_rule + if level >= 3: + return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.copper) else: return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic) diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 59f9d1782780..d02d05da96b7 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -10,6 +10,7 @@ class DeepWoodsItem: class SkillItem: luck_skill = "Luck Level" + archaeology_level = "Archaeology Level" class SVEQuestItem: From df2ee612c2badef80395f8d22a8994ee7685d918 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 13 Dec 2023 12:59:55 -0600 Subject: [PATCH 400/482] Ensure pans don't muck it up --- worlds/stardew_valley/mods/logic/skills_logic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 4862b95f973b..fa64de1e186a 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -88,9 +88,9 @@ def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: shifter_rule = self.logic.received(SkillItem.archaeology_level, 4) preservation_rule = self.logic.received(SkillItem.archaeology_level, 7) if level >= 8: - return (self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.gold)) & shifter_rule & preservation_rule + return (self.logic.action.can_pan() & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.gold)) & shifter_rule & preservation_rule if level >= 5: - return (self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iron)) & shifter_rule + return (self.logic.action.can_pan() & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iron)) & shifter_rule if level >= 3: return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.copper) else: From 3ff80f09983f97d8fed5490be3213bbe7d66f9c5 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 13 Dec 2023 16:44:21 -0600 Subject: [PATCH 401/482] Remove wizard requirement for magic. --- worlds/stardew_valley/rules.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 8984487c9241..4800d505237b 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -833,9 +833,6 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i if ModNames.magic not in world_options.mods: return - MultiWorldRules.set_rule(multiworld.get_entrance(MagicEntrance.store_to_altar, player), - (logic.relationship.has_hearts(NPC.wizard, 3) & - logic.region.can_reach(Region.wizard_tower))) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Clear Debris", player), (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic"))) MultiWorldRules.add_rule(multiworld.get_location("Analyze: Till", player), From 93c90428c955fa7488f473ebd217999a0eac7fea Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 14 Dec 2023 03:18:44 -0600 Subject: [PATCH 402/482] Fix improper shipment labeling --- worlds/stardew_valley/data/locations.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index ede08b08c6f6..3f3af35f7bb4 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2642,7 +2642,7 @@ id,region,name,tags,mod_name 8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded 8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded -8013,Shipping,Shipsanity: Big Conch,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded 8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded 8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded @@ -2650,7 +2650,7 @@ id,region,name,tags,mod_name 8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded 8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded 8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8021,Shipping,Shipsanity: Dried Sand Dollar,SHIPSANITY,Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded 8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded From 6c14bb3d97a7466c9fe2891278a2bf5268c58eed Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 15:24:57 -0600 Subject: [PATCH 403/482] Fix name as its fixed on client --- worlds/stardew_valley/strings/craftable_names.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index 5ba6dc291038..dedc69166eb9 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -161,7 +161,7 @@ class ModCraftable: class ModMachine: preservation_chamber = "Preservation Chamber" - hardwood_preservation_chamber = "hardwood Preservation Chamber" + hardwood_preservation_chamber = "Hardwood Preservation Chamber" grinder = "Grinder" ancient_battery = "Ancient Battery Production Station" From ffb57d4548d5a140ef2ea9e12df8a50e0e1ac4ad Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 15:25:40 -0600 Subject: [PATCH 404/482] Return to older structure --- worlds/stardew_valley/data/items.csv | 10 +++++----- worlds/stardew_valley/data/locations.csv | 4 ++++ worlds/stardew_valley/rules.py | 8 ++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 4a946c04b3b3..cb4855b98a66 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -809,17 +809,17 @@ id,name,classification,groups,mod_name 10504,Krobus' Protection,useful,,Stardew Valley Expanded 10505,Kittyfish Spell,progression,,Stardew Valley Expanded 10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded -10507,Nexus: Junimo and Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded 10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded 10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,DEPRECATED,Stardew Valley Expanded -10511,Nexus: Farm and Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded -10512,Nexus: Wizard Runes,progression,DEPRECATED,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded +10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded 10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded 10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10517,Abandoned House Outskirts Clean-up,progression,MOD_WARP,Stardew Valley Expanded +10517,Abandoned House Outskirts Clean-up,progression,DEPRECATED,Stardew Valley Expanded 10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded 10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded 10520,Morgan's Schooling,progression,,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 3f3af35f7bb4..c3c706ac4dec 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2533,6 +2533,10 @@ id,region,name,tags,mod_name 7412,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology 7413,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology 7414,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology +7415,Farm,Craft Grinder,CRAFTSANITY,Archaeology +7416,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology +7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology +7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology 7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 4800d505237b..2213fdb1545f 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -910,17 +910,17 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.aurora_warp_to_aurora, player), logic.received("Nexus: Aurora Vineyard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.farm_warp_to_farm, player), - logic.received("Nexus: Farm and Wizard Runes")) + logic.received("Nexus: Farm Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.guild_warp_to_guild, player), logic.received("Nexus: Adventurer's Guild Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.junimo_warp_to_junimo, player), - logic.received("Nexus: Junimo and Outpost Runes")) + logic.received("Nexus: Junimo Woods Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.spring_warp_to_spring, player), logic.received("Nexus: Sprite Spring Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.outpost_warp_to_outpost, player), - logic.received("Nexus: Junimo and Outpost Runes")) + logic.received("Nexus: Outpost Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_warp_to_wizard, player), - logic.received("Nexus: Farm and Wizard Runes")) + logic.received("Nexus: Wizard Runes")) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), logic.relationship.has_hearts(ModNPC.apples, 10)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), From 44590377f6d833c734b9bd37270fae5203d064f7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 15:26:02 -0600 Subject: [PATCH 405/482] Missing name changes --- worlds/stardew_valley/strings/ap_names/mods/mod_items.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index d02d05da96b7..7085fd1a29d6 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -38,10 +38,12 @@ class SVELocation: class SVERunes: nexus_guild = "Nexus: Adventurer's Guild Runes" - nexus_junimo_outpost = "Nexus: Junimo and Outpost Runes" + nexus_junimo = "Nexus: Junimo Woods Runes" + nexus_outpost = "Nexus: Outpost Runes" nexus_aurora = "Nexus: Aurora Vineyard Runes" nexus_spring = "Nexus: Sprite Spring Runes" - nexus_farm_wizard = "Nexus: Farm and Wizard Runes" + nexus_farm = "Nexus: Farm Runes" + nexus_wizard = "Nexus: Wizard Runes" - nexus_items: List[str] = [nexus_farm_wizard, nexus_spring, nexus_aurora, nexus_guild, nexus_junimo_outpost] + nexus_items: List[str] = [nexus_farm, nexus_wizard, nexus_spring, nexus_aurora, nexus_guild, nexus_junimo, nexus_outpost] From 0200d7d00074faae92efc253d09a0dea686be099 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 15:26:23 -0600 Subject: [PATCH 406/482] Allow for jasper marlon/gunther --- worlds/stardew_valley/data/villagers_data.py | 17 +++++++++++++---- .../stardew_valley/logic/relationship_logic.py | 12 ++++++++++-- worlds/stardew_valley/mods/mod_data.py | 5 +++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 40959c51a032..0f4e5d87b1ad 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -3,7 +3,7 @@ from ..strings.food_names import Beverage from ..strings.region_names import Region, SVERegion, AlectoRegion -from ..mods.mod_data import ModNames +from ..mods.mod_data import ModNames, mods_with_multiple_villager_sources from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC @@ -432,9 +432,9 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu victor = villager(ModNPC.victor, True, town, Season.summer, universal_loves + victor_loves, True, ModNames.sve) andy = villager(ModNPC.andy, False, forest, Season.spring, universal_loves + andy_loves, True, ModNames.sve) apples = villager(ModNPC.apples, False, aurora + junimo, Season.spring, starfruit, False, ModNames.sve) -gunther = villager(ModNPC.gunther, False, museum, Season.winter, universal_loves + gunther_loves, True, ModNames.sve) +gunther = villager(ModNPC.gunther, False, museum, Season.winter, universal_loves + gunther_loves, True, ModNames.jasper_sve) martin = villager(ModNPC.martin, False, town + jojamart, Season.summer, universal_loves + martin_loves, True, ModNames.sve) -marlon = villager(ModNPC.marlon, False, adventurer, Season.winter, universal_loves + marlon_loves, False, ModNames.sve) +marlon = villager(ModNPC.marlon, False, adventurer, Season.winter, universal_loves + marlon_loves, False, ModNames.jasper_sve) morgan = villager(ModNPC.morgan, False, forest, Season.fall, universal_loves_no_rabbit_foot + morgan_loves, False, ModNames.sve) scarlett = villager(ModNPC.scarlett, False, bluemoon, Season.summer, universal_loves + scarlett_loves, False, ModNames.sve) susan = villager(ModNPC.susan, False, railroad, Season.fall, universal_loves + susan_loves, False, ModNames.sve) @@ -460,10 +460,19 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu all_villagers_by_mod_by_name[mod][name] = npc +def villager_included_for_any_mod(npc: Villager, mods: Set[str]): + for mod in npc.mod_name.split(","): + if mod in mods: + return True + return False + + def get_villagers_for_mods(mods: Set[str]) -> List[Villager]: villagers_for_current_mods = [] for npc in all_villagers: - if npc.mod_name and npc.mod_name not in mods: + if npc.mod_name in mods_with_multiple_villager_sources and not villager_included_for_any_mod(npc, mods): + continue + elif npc.mod_name not in mods_with_multiple_villager_sources and npc.mod_name and npc.mod_name not in mods: continue modified_npc = npc for active_mod in mods: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index e7b867c1277e..b7a642816d5e 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -11,8 +11,9 @@ from .season_logic import SeasonLogicMixin from .time_logic import TimeLogicMixin from ..data.villagers_data import all_villagers_by_name, Villager +from ..mods.mod_data import mods_with_multiple_villager_sources from ..options import Friendsanity -from ..stardew_rule import StardewRule, True_, And, Or +from ..stardew_rule import StardewRule, True_, False_, And, Or, Count from ..strings.ap_names.mods.mod_items import SVEQuestItem from ..strings.crop_names import Fruit from ..strings.generic_names import Generic @@ -176,4 +177,11 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] mod = npc.mod_name - return mod is None or mod in self.options.mods + if mod not in mods_with_multiple_villager_sources: + mod_rule_if_exists = mod in self.options.mods + else: + sources = mod.split(",") + mod_rule_if_exists = False_() + for single_mod in sources: + mod_rule_if_exists = mod_rule_if_exists | (single_mod in self.options.mods) + return not mod or mod_rule_if_exists diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index f5cd26889450..5eef460e5b6c 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -25,6 +25,11 @@ class ModNames: alecto = "Alecto the Witch" distant_lands = "Distant Lands - Witch Swamp Overhaul" + jasper_sve = jasper + "," + sve + + +mods_with_multiple_villager_sources = [ModNames.jasper_sve] + all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, From 3b307a42bf6ea3c2ca71cc0f9df0ccfce58a3593 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 15:26:40 -0600 Subject: [PATCH 407/482] shift to craft rule --- worlds/stardew_valley/mods/logic/skills_logic.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index fa64de1e186a..28d1f2de98a0 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -16,6 +16,7 @@ from ...options import SkillProgression from ...stardew_rule import StardewRule, False_, True_ from ...strings.ap_names.mods.mod_items import SkillItem +from ...strings.craftable_names import ModCraftable, ModMachine from ...strings.building_names import Building from ...strings.geode_names import Geode from ...strings.machine_names import Machine @@ -85,8 +86,8 @@ def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: shifter_rule = True_() preservation_rule = True_() if self.options.skill_progression == self.options.skill_progression.option_progressive: - shifter_rule = self.logic.received(SkillItem.archaeology_level, 4) - preservation_rule = self.logic.received(SkillItem.archaeology_level, 7) + shifter_rule = self.logic.has(ModCraftable.water_shifter) + preservation_rule = self.logic.has(ModMachine.hardwood_preservation_chamber) if level >= 8: return (self.logic.action.can_pan() & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.gold)) & shifter_rule & preservation_rule if level >= 5: From 111a4c4452790d0583e65d4f1ff7f8284a0ef98f Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 16:11:20 -0600 Subject: [PATCH 408/482] add willy bedroom to ER --- worlds/stardew_valley/mods/mod_regions.py | 6 ++++-- worlds/stardew_valley/strings/entrance_names.py | 2 ++ worlds/stardew_valley/strings/region_names.py | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index ad5e0fb11244..ee9559c5cd0e 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -165,6 +165,8 @@ RegionData(SVERegion.jenkins_cellar), RegionData(SVERegion.unclaimed_plot, [SVEEntrance.plot_to_bridge]), RegionData(SVERegion.shearwater), + RegionData(Region.fish_shop, [SVEEntrance.fish_shop_to_willy_bedroom]), + RegionData(SVERegion.willy_bedroom), RegionData(Region.mountain, [SVEEntrance.mountain_to_guild_summit]), RegionData(SVERegion.guild_summit, [SVEEntrance.guild_to_interior, SVEEntrance.guild_to_mines, SVEEntrance.summit_to_highlands]), @@ -193,7 +195,6 @@ RegionData(SVERegion.lost_woods, [SVEEntrance.lost_woods_to_junimo_woods]), RegionData(SVERegion.junimo_woods, [SVEEntrance.use_purple_junimo]), RegionData(SVERegion.purple_junimo_shop), - RegionData(SVERegion.alesia_shop), RegionData(SVERegion.isaac_shop), RegionData(SVERegion.summit), @@ -267,7 +268,8 @@ ConnectionData(SVEEntrance.grampleton_suburbs_to_scarlett_house, SVERegion.scarlett_house, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.first_slash_guild_to_hallway, SVERegion.first_slash_hallway, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS) + ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.fish_shop_to_willy_bedroom, SVERegion.willy_bedroom, flag=RandomizationFlag.BUILDINGS), ] alecto_regions = [ diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 838cb571fbd3..8970569f69ae 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -324,6 +324,8 @@ class SVEEntrance: first_slash_guild_to_hallway = "First Slash Guild to First Slash Hallway" first_slash_hallway_to_room = "First Slash Hallway to First Slash Spare Room" sprite_spring_to_cave = "Sprite Spring to Sprite Spring Cave" + fish_shop_to_willy_bedroom = "Willy's Fish Shop to Willy's Bedroom" + museum_to_gunther_bedroom = "Museum to Gunther's Bedroom" class AlectoEntrance: diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 213fef3a3818..84ae358f414d 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -271,6 +271,7 @@ class SVERegion: first_slash_hallway = "First Slash Hallway" first_slash_spare_room = "First Slash Spare Room" sprite_spring_cave = "Sprite Spring Cave" + willy_bedroom = "Willy's Bedroom" class AlectoRegion: From aa07483452de38944763ab8c9f5ac05b77fe299a Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 20 Dec 2023 17:09:09 -0600 Subject: [PATCH 409/482] fix special order logic --- worlds/stardew_valley/mods/logic/special_orders_logic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index d4d788bb8179..6ee61f6e4fb4 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -1,5 +1,6 @@ from typing import Union +from ...data.craftable_data import all_crafting_recipes_by_name from ..mod_data import ModNames from ...logic.action_logic import ActionLogicMixin from ...logic.artisan_logic import ArtisanLogicMixin @@ -58,7 +59,8 @@ def get_modded_special_orders_rules(self): self.logic.region.can_reach(Region.island_south) & ( self.logic.action.can_open_geode(Geode.frozen) | self.logic.action.can_open_geode(Geode.omni)) & self.logic.region.can_reach(SVERegion.blue_moon_vineyard), - ModSpecialOrder.homemade_fertilizer: self.logic.has(Fertilizer.quality) & self.logic.region.can_reach(SVERegion.susans_house) + ModSpecialOrder.homemade_fertilizer: self.logic.crafting.can_craft(all_crafting_recipes_by_name[Fertilizer.quality]) & + self.logic.region.can_reach(SVERegion.susans_house) # quest requires you make the fertilizer }) return special_orders From 384b8aacf8e7db18bff845dd75df354b33eb050e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 21 Dec 2023 01:52:36 -0600 Subject: [PATCH 410/482] Fix friendsanity to bday locale --- worlds/stardew_valley/data/locations.csv | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c3c706ac4dec..be54c7230d46 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2321,20 +2321,20 @@ id,region,name,tags,mod_name 6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded 6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded 6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded -6153,Highlands Outside,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6154,Highlands Outside,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6155,Highlands Outside,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6156,Highlands Outside,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6157,Highlands Outside,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6158,Highlands Outside,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6159,Highlands Outside,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6160,Highlands Outside,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6161,Highlands Outside,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6162,Highlands Outside,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6163,Highlands Outside,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6164,Highlands Outside,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6165,Highlands Outside,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6166,Highlands Outside,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6153,Galmoran Outpost,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Galmoran Outpost,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Galmoran Outpost,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Galmoran Outpost,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Galmoran Outpost,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Galmoran Outpost,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Galmoran Outpost,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Galmoran Outpost,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Galmoran Outpost,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Galmoran Outpost,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Galmoran Outpost,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Galmoran Outpost,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Galmoran Outpost,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Galmoran Outpost,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded 6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded 6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded 6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded @@ -2441,16 +2441,16 @@ id,region,name,tags,mod_name 6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded 6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded 6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6273,Blue Moon Vineyard,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded -6274,Blue Moon Vineyard,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded -6275,Blue Moon Vineyard,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded -6276,Blue Moon Vineyard,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded -6277,Blue Moon Vineyard,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded -6278,Blue Moon Vineyard,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded -6279,Blue Moon Vineyard,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded -6280,Blue Moon Vineyard,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded -6281,Blue Moon Vineyard,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded -6282,Blue Moon Vineyard,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded +6273,Scarlett's House,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded +6274,Scarlett's House,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded +6275,Scarlett's House,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded +6276,Scarlett's House,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded +6277,Scarlett's House,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded +6278,Scarlett's House,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded +6279,Scarlett's House,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded +6280,Scarlett's House,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded +6281,Scarlett's House,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded +6282,Scarlett's House,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded 6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded 6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded 6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded From 95e592f5e33a15f462acb460dccff48674fc1d52 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 21 Dec 2023 03:31:15 -0600 Subject: [PATCH 411/482] Add resource packs, fix class --- worlds/stardew_valley/data/items.csv | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index cb4855b98a66..e4ccd24c7489 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -738,14 +738,14 @@ id,name,classification,groups,mod_name 10011,Spell: Water,progression,MAGIC_SPELL,Magic 10012,Spell: Blink,progression,MAGIC_SPELL,Magic 10013,Spell: Evac,useful,MAGIC_SPELL,Magic -10014,Spell: Haste,filler,MAGIC_SPELL,Magic +10014,Spell: Haste,useful,MAGIC_SPELL,Magic 10015,Spell: Heal,progression,MAGIC_SPELL,Magic 10016,Spell: Buff,useful,MAGIC_SPELL,Magic 10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic 10018,Spell: Fireball,progression,MAGIC_SPELL,Magic 10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic 10020,Spell: Teleport,progression,MAGIC_SPELL,Magic -10021,Spell: Lantern,filler,MAGIC_SPELL,Magic +10021,Spell: Lantern,useful,MAGIC_SPELL,Magic 10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic 10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic 10024,Spell: Descend,progression,MAGIC_SPELL,Magic @@ -828,3 +828,19 @@ id,name,classification,groups,mod_name 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10701,Resource Pack: 3 Magic Elixir,filler,RESOURCE_PACK,Magic +10702,Resource Pack: 3 Travel Core,filler,RESOURCE_PACK,Magic +10703,Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10704,Hardwood Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10705,Resource Pack: 3 Water Shifter,filler,RESOURCE_PACK,Archaeology +10706,Resource Pack: 5 Hardwood Display,filler,RESOURCE_PACK,Archaeology +10707,Resource Pack: 5 Wooden Display,filler,RESOURCE_PACK,Archaeology +10708,Grinder,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10709,Ancient Battery Production Station,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10710,Resource Pack: Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded +10711,Resource Pack: Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10712,Resource Pack: Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10713,Resource Pack: Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10714,Resource Pack: Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10715,Resource Pack: Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10716,Resource Pack: Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded From da9804babf83babee37a9631538ae93670f7ad48 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 21 Dec 2023 22:31:18 -0600 Subject: [PATCH 412/482] Use Zic for Goblin --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 20 +++++++++---------- .../stardew_valley/strings/villager_names.py | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index e4ccd24c7489..e436f5973897 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -783,7 +783,7 @@ id,name,classification,groups,mod_name 10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded 10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch -10127,Goblin <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator 10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index be54c7230d46..791b11743888 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2471,16 +2471,16 @@ id,region,name,tags,mod_name 6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded 6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded 6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded -6303,Witch's Swamp,Friendsanity: Goblin 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6304,Witch's Swamp,Friendsanity: Goblin 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6305,Witch's Swamp,Friendsanity: Goblin 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6306,Witch's Swamp,Friendsanity: Goblin 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6307,Witch's Swamp,Friendsanity: Goblin 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6308,Witch's Swamp,Friendsanity: Goblin 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6309,Witch's Swamp,Friendsanity: Goblin 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6310,Witch's Swamp,Friendsanity: Goblin 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6311,Witch's Swamp,Friendsanity: Goblin 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6312,Witch's Swamp,Friendsanity: Goblin 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6303,Witch's Swamp,Friendsanity: Zic 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6304,Witch's Swamp,Friendsanity: Zic 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6305,Witch's Swamp,Friendsanity: Zic 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6306,Witch's Swamp,Friendsanity: Zic 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6307,Witch's Swamp,Friendsanity: Zic 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6308,Witch's Swamp,Friendsanity: Zic 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6309,Witch's Swamp,Friendsanity: Zic 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6310,Witch's Swamp,Friendsanity: Zic 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6311,Witch's Swamp,Friendsanity: Zic 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6312,Witch's Swamp,Friendsanity: Zic 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul 6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch 6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch 6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch diff --git a/worlds/stardew_valley/strings/villager_names.py b/worlds/stardew_valley/strings/villager_names.py index 448065875bf9..b4b363c20942 100644 --- a/worlds/stardew_valley/strings/villager_names.py +++ b/worlds/stardew_valley/strings/villager_names.py @@ -62,4 +62,4 @@ class ModNPC: scarlett = "Scarlett" susan = "Susan" alecto = "Alecto" - goblin = "Goblin" + goblin = "Zic" From 7c4140531a0c98d5631049208ac689f79c60604c Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sat, 23 Dec 2023 01:14:29 -0600 Subject: [PATCH 413/482] Add Purple Algae and Quests --- worlds/stardew_valley/data/fish_data.py | 1 + worlds/stardew_valley/data/locations.csv | 2 ++ worlds/stardew_valley/mods/logic/item_logic.py | 1 - worlds/stardew_valley/mods/logic/quests_logic.py | 9 +++++---- worlds/stardew_valley/strings/quest_names.py | 4 +++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/fish_data.py b/worlds/stardew_valley/data/fish_data.py index 73238f9e9eb1..aeb416733950 100644 --- a/worlds/stardew_valley/data/fish_data.py +++ b/worlds/stardew_valley/data/fish_data.py @@ -158,6 +158,7 @@ def create_fish(name: str, locations: Tuple[str, ...], seasons: Union[str, Tuple dulse_seaweed = create_fish(SVEFish.dulse_seaweed, vineyard, season.all_seasons, 50, mod_name=ModNames.sve) void_minnow = create_fish(DistantLandsFish.void_minnow, witch_swamp, season.all_seasons, 15, mod_name=ModNames.distant_lands) +purple_algae = create_fish(DistantLandsFish.purple_algae, witch_swamp, season.all_seasons, 15, mod_name=ModNames.distant_lands) swamp_leech = create_fish(DistantLandsFish.swamp_leech, witch_swamp, season.all_seasons, 15, mod_name=ModNames.distant_lands) giant_horsehoe_crab = create_fish(DistantLandsFish.giant_horsehoe_crab, witch_swamp, season.all_seasons, 90, mod_name=ModNames.distant_lands) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 791b11743888..52a2755af49e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2564,6 +2564,7 @@ id,region,name,tags,mod_name 7520,Witch's Swamp,A New Pot,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul 7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul 7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +7523,Boarding House - First Floor,Pumpkin Soup,"MANDATORY,STORY_QUEST",Boarding House and Bus Stop Extension 7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded @@ -2626,6 +2627,7 @@ id,region,name,tags,mod_name 7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul 7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul 7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7731,Witch's Swamp,Fishsanity: Purple Algae,FISHSANITY,Distant Lands - Witch Swamp Overhaul 7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded 7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded 7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 44dc9392773b..c4daf2e3920d 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -127,7 +127,6 @@ def get_distant_lands_item_rules(self): return{ DistantLandsForageable.swamp_herb: self.logic.region.can_reach(Region.witch_swamp), DistantLandsForageable.brown_amanita: self.logic.region.can_reach(Region.witch_swamp), - DistantLandsFish.purple_algae: self.logic.fishing.can_fish_at(Region.witch_swamp), DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.has_seed_unlocked(DistantLandsSeed.vile_ancient_fruit), DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.has_seed_unlocked(DistantLandsSeed.void_mint), DistantLandsCrop.void_mint: self.logic.season.has_any_not_winter() & self.logic.has(DistantLandsSeed.void_mint), diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index fb4bd3537ba4..800091d24838 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -12,7 +12,7 @@ from ...stardew_rule import StardewRule from ...strings.animal_product_names import AnimalProduct from ...strings.artisan_good_names import ArtisanGood -from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable +from ...strings.crop_names import Fruit, SVEFruit, SVEVegetable, Vegetable from ...strings.fertilizer_names import Fertilizer from ...strings.food_names import Meal, Beverage from ...strings.forageable_names import SVEForage @@ -20,7 +20,7 @@ from ...strings.metal_names import Ore, MetalBar from ...strings.monster_drop_names import Loot from ...strings.quest_names import Quest, ModQuest -from ...strings.region_names import Region, SVERegion +from ...strings.region_names import Region, SVERegion, BoardingHouseRegion from ...strings.season_names import Season from ...strings.villager_names import ModNPC from ...strings.wallet_item_names import Wallet @@ -88,14 +88,15 @@ def _get_distant_lands_quest_rules(self): if ModNames.distant_lands not in self.options.mods: return {} - return{ + return { ModQuest.CorruptedCropsTask: self.logic.region.can_reach(Region.wizard_tower) & self.logic.has(Fertilizer.deluxe) & self.logic.quest.can_complete_quest(Quest.magic_ink), ModQuest.WitchOrder: self.logic.region.can_reach(Region.witch_swamp) & self.logic.has(Fertilizer.deluxe) & self.logic.quest.can_complete_quest(Quest.magic_ink), ModQuest.ANewPot: self.logic.region.can_reach(Region.saloon) & self.logic.region.can_reach(Region.sam_house) & self.logic.region.can_reach(Region.pierre_store) & - self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron) & self.logic.relationship.has_hearts(ModNPC.goblin, 6), + self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron) & self.logic.relationship.has_hearts(ModNPC.goblin, + 6), ModQuest.FancyBlanketTask: self.logic.region.can_reach(Region.haley_house) & self.logic.has(AnimalProduct.wool) & self.logic.has(ArtisanGood.cloth) & self.logic.relationship.has_hearts(ModNPC.goblin, 10) diff --git a/worlds/stardew_valley/strings/quest_names.py b/worlds/stardew_valley/strings/quest_names.py index 4cc2b48418b0..04faae81cf0c 100644 --- a/worlds/stardew_valley/strings/quest_names.py +++ b/worlds/stardew_valley/strings/quest_names.py @@ -67,4 +67,6 @@ class ModQuest: CorruptedCropsTask = "Corrupted Crops Task" ANewPot = "A New Pot" FancyBlanketTask = "Fancy Blanket Task" - WitchOrder = "Witch's order" \ No newline at end of file + WitchOrder = "Witch's order" + PumpkinSoup = "Pumpkin Soup" + HatMouseHat = "Hats for the Hat Mouse" From 18c059673abd38e0655f0d25ec15fa185029d41d Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sat, 23 Dec 2023 01:23:06 -0600 Subject: [PATCH 414/482] Add Shed as item and clean up --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/rules.py | 22 +++++++++---------- .../strings/ap_names/mods/mod_items.py | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index e436f5973897..e23c7f7e43e1 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -819,7 +819,7 @@ id,name,classification,groups,mod_name 10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10517,Abandoned House Outskirts Clean-up,progression,DEPRECATED,Stardew Valley Expanded +10517,Grandpa's Shed,progression,,Stardew Valley Expanded 10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded 10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded 10520,Morgan's Schooling,progression,,Stardew Valley Expanded diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 2213fdb1545f..ee81b88ec08f 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -19,7 +19,7 @@ Monstersanity, Chefsanity, Craftsanity, ArcadeMachineLocations, Cooksanity, Cropsanity, SkillProgression from .stardew_rule import And from .strings.ap_names.event_names import Event -from .strings.ap_names.mods.mod_items import SVEQuestItem +from .strings.ap_names.mods.mod_items import SVEQuestItem, SVERunes from .strings.ap_names.transport_names import Transportation from .strings.ap_names.mods.mod_items import SVELocation from .strings.artisan_good_names import ArtisanGood @@ -908,23 +908,23 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.aurora_warp_to_aurora, player), - logic.received("Nexus: Aurora Vineyard Runes")) + logic.received(SVERunes.nexus_aurora)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.farm_warp_to_farm, player), - logic.received("Nexus: Farm Runes")) + logic.received(SVERunes.nexus_farm)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.guild_warp_to_guild, player), - logic.received("Nexus: Adventurer's Guild Runes")) + logic.received(SVERunes.nexus_guild)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.junimo_warp_to_junimo, player), - logic.received("Nexus: Junimo Woods Runes")) + logic.received(SVERunes.nexus_junimo)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.spring_warp_to_spring, player), - logic.received("Nexus: Sprite Spring Runes")) + logic.received(SVERunes.nexus_spring)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.outpost_warp_to_outpost, player), - logic.received("Nexus: Outpost Runes")) + logic.received(SVERunes.nexus_outpost)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_warp_to_wizard, player), - logic.received("Nexus: Wizard Runes")) + logic.received(SVERunes.nexus_wizard)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), logic.relationship.has_hearts(ModNPC.apples, 10)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), - logic.quest.can_complete_quest(ModQuest.GrandpasShed)) + logic.received(SVEQuestItem.grandpa_shed)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) @@ -941,9 +941,9 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.summit_to_highlands, player), - logic.received("Marlon's Boat Paddle")) + logic.received(SVEQuestItem.marlon_boat_paddle)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), - logic.received("Fable Reef Portal")) + logic.received(SVEQuestItem.fable_reef_portal)) MultiWorldRules.set_rule(multiworld.get_location(SVELocation.diamond_wand, player), logic.quest.can_complete_quest(ModQuest.MonsterCrops) & logic.region.can_reach(SVERegion.lances_house)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 7085fd1a29d6..6c27f7e63109 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -23,8 +23,9 @@ class SVEQuestItem: diamond_wand = "Diamond Wand" marlon_boat_paddle = "Marlon's Boat Paddle" fable_reef_portal = "Fable Reef Portal" + grandpa_shed = "Grandpa's Shed" - sve_quest_items: List[str] = [aurora_vineyard_tablet, iridium_bomb, void_soul, kittyfish_spell, scarlett_job_offer, morgan_schooling] + sve_quest_items: List[str] = [aurora_vineyard_tablet, iridium_bomb, void_soul, kittyfish_spell, scarlett_job_offer, morgan_schooling, grandpa_shed] sve_quest_items_ginger_island: List[str] = [diamond_wand, marlon_boat_paddle, fable_reef_portal] From e2ae4066a4890dddfcf76ac564d7218808be963f Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 24 Dec 2023 17:30:52 -0600 Subject: [PATCH 415/482] New bear logic --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/recipe_data.py | 4 ++-- worlds/stardew_valley/items.py | 5 ++++- worlds/stardew_valley/mods/logic/sve_logic.py | 13 ++++++++++++- worlds/stardew_valley/rules.py | 3 +-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index e23c7f7e43e1..33a9ff114e2b 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -81,7 +81,7 @@ id,name,classification,groups,mod_name 95,Adventurer's Guild,progression,DEPRECATED, 96,Club Card,progression,, 97,Magnifying Glass,progression,, -98,Bear's Knowledge,useful,, +98,Bear's Knowledge,progression,, 99,Iridium Snake Milk,useful,, 100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, 101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 55dad717ca3c..8ecfbe85a64d 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -174,11 +174,11 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, trout_soup = queen_of_sauce_recipe(Meal.trout_soup, 1, Season.fall, 14, {Fish.rainbow_trout: 1, WaterItem.green_algae: 1}) vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Vegetable.tomato: 1, Vegetable.beet: 1}) -baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 12500, {Forageable.salmonberry: 15, Forageable.blackberry: 15, +baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 0, {Forageable.salmonberry: 15, Forageable.blackberry: 15, Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve) big_bark_burger = friendship_and_shop_recipe(SVEMeal.big_bark_burger, NPC.gus, 5, Region.saloon, 5500, {SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, ModNames.sve) -flower_cookie = shop_recipe(SVEMeal.flower_cookie, SVERegion.bear_shop, 8750, {SVEForage.ferngill_primrose: 1, SVEForage.goldenrod: 1, +flower_cookie = shop_recipe(SVEMeal.flower_cookie, SVERegion.bear_shop, 0, {SVEForage.ferngill_primrose: 1, SVEForage.goldenrod: 1, SVEForage.winter_star_rose: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.large_egg: 1}, ModNames.sve) frog_legs = shop_recipe(SVEMeal.frog_legs, Region.adventurer_guild, 2000, {SVEFish.frog: 1, Ingredient.oil: 1, Ingredient.wheat_flour: 1}, ModNames.sve) diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index bebc888c2f70..6e590ae1ef1b 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -355,7 +355,10 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, options: Star # items.append(item_factory("Adventurer's Guild")) # Now unlocked always! items.append(item_factory(Wallet.club_card)) items.append(item_factory(Wallet.magnifying_glass)) - items.append(item_factory(Wallet.bears_knowledge)) + if ModNames.sve in options.mods: + items.append(item_factory(Wallet.bears_knowledge)) + else: + items.append(item_factory(Wallet.bears_knowledge, ItemClassification.useful)) # Not necessary outside of SVE items.append(item_factory(Wallet.iridium_snake_milk)) items.append(item_factory("Fairy Dust Recipe")) items.append(item_factory("Dark Talisman")) diff --git a/worlds/stardew_valley/mods/logic/sve_logic.py b/worlds/stardew_valley/mods/logic/sve_logic.py index a28f78a717c5..1254338fe2fc 100644 --- a/worlds/stardew_valley/mods/logic/sve_logic.py +++ b/worlds/stardew_valley/mods/logic/sve_logic.py @@ -14,7 +14,10 @@ from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes, SVEQuestItem -from ...strings.quest_names import ModQuest +from ...strings.quest_names import Quest +from ...strings.region_names import Region +from ...strings.tool_names import Tool, ToolMaterial +from ...strings.wallet_item_names import Wallet from ...stardew_rule import Or from ...strings.quest_names import ModQuest @@ -42,3 +45,11 @@ def has_iridium_bomb(self): if self.options.quest_locations < 0: return self.logic.quest.can_complete_quest(ModQuest.RailroadBoulder) return self.logic.received(SVEQuestItem.iridium_bomb) + + def can_buy_bear_recipe(self): + access_rule = (self.logic.quest.can_complete_quest(Quest.strange_note) & self.logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & + self.logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic)) + forage_rule = self.logic.region.can_reach_any((Region.forest, Region.backwoods, Region.mountain)) + knowledge_rule = self.logic.received(Wallet.bears_knowledge) + return access_rule & forage_rule & knowledge_rule + diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index ee81b88ec08f..a567393818c5 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -926,8 +926,7 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), logic.received(SVEQuestItem.grandpa_shed)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), - (logic.quest.can_complete_quest(Quest.strange_note) & logic.tool.has_tool(Tool.axe, ToolMaterial.basic) & - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.basic))) + (logic.mod.sve.can_buy_bear_recipe())) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.railroad_to_grampleton_station, player), logic.received(SVEQuestItem.scarlett_job_offer)) logic.mod.sve.initialize_rules() From 55d657a25921615daa26611fc90dcfb9cd8e80c8 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 26 Dec 2023 13:47:15 -0600 Subject: [PATCH 416/482] Fix Trilobite Fossil name --- worlds/stardew_valley/data/locations.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 52a2755af49e..a1ab89b5c2e7 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2820,8 +2820,8 @@ id,region,name,tags,mod_name 8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology 8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology 8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology -8194,Shipping,Shipsanity: Wooden Display: Trilobite,SHIPSANITY,Archaeology -8195,Shipping,Shipsanity: Hardwood Display: Trilobite,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite Fossil,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite Fossil,SHIPSANITY,Archaeology 8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology 8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology 8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology From e99b3e54b5dd1a7732a25dafd4c41260a6db4f2b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 1 Jan 2024 02:27:17 -0600 Subject: [PATCH 417/482] Add ships to full shipment --- worlds/stardew_valley/data/locations.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a1ab89b5c2e7..d46ff9401257 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2637,7 +2637,7 @@ id,region,name,tags,mod_name 7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul 7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul 8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic -8002,Shipping,Shipsanity: Travel Core,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Magic 8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded 8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded 8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded @@ -2829,7 +2829,7 @@ id,region,name,tags,mod_name 8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology 8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology 8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology -8203,Shipping,Shipsanity: Brown Amanita,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8203,Shipping,Shipsanity: Brown Amanita,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul 8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul 8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul From d0f5d7ca7d767fc25695b7a8fdf78dd44bbfb78e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 1 Jan 2024 18:43:13 -0600 Subject: [PATCH 418/482] Fix trilobite fossil rule --- worlds/stardew_valley/mods/logic/item_logic.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index c4daf2e3920d..6d68654c5254 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -115,7 +115,10 @@ def get_archaeology_item_rules(self): hardwood_preservation_chamber_rule = self.logic.has(ModMachine.hardwood_preservation_chamber) for item in display_items: for display_type in display_types: - location_name = f"{display_type}: {item}" + if item == "Trilobite": + location_name = f"{display_type}: Trilobite Fossil" + else: + location_name = f"{display_type}: {item}" display_item_rule = self.logic.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.logic.has(item) if "Wooden" in display_type: archaeology_item_rules[location_name] = display_item_rule & preservation_chamber_rule From c6553e3eda042f0c8d9746f0cc45a49dc45e651b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 1 Jan 2024 18:43:33 -0600 Subject: [PATCH 419/482] Give any season --- worlds/stardew_valley/data/villagers_data.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 0f4e5d87b1ad..0a8b1089222d 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -4,6 +4,7 @@ from ..strings.food_names import Beverage from ..strings.region_names import Region, SVERegion, AlectoRegion from ..mods.mod_data import ModNames, mods_with_multiple_villager_sources +from ..strings.generic_names import Generic from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC @@ -422,7 +423,7 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu yoba = villager(ModNPC.yoba, False, secret_woods, Season.spring, universal_loves + yoba_loves, False, ModNames.yoba) riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley) zic = villager(ModNPC.goblin, False, witch_swamp, Season.fall, void_mayonnaise, False, ModNames.distant_lands) -alecto = villager(ModNPC.alecto, False, witch_attic, Season.fall, universal_loves, False, ModNames.alecto) +alecto = villager(ModNPC.alecto, False, witch_attic, Generic.any, universal_loves, False, ModNames.alecto) # SVE Villagers claire = villager(ModNPC.claire, True, town + jojamart, Season.fall, universal_loves + claire_loves, True, ModNames.sve) @@ -431,7 +432,7 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu sophia = villager(ModNPC.sophia, True, bluemoon, Season.winter, universal_loves_no_rabbit_foot + sophia_loves, True, ModNames.sve) victor = villager(ModNPC.victor, True, town, Season.summer, universal_loves + victor_loves, True, ModNames.sve) andy = villager(ModNPC.andy, False, forest, Season.spring, universal_loves + andy_loves, True, ModNames.sve) -apples = villager(ModNPC.apples, False, aurora + junimo, Season.spring, starfruit, False, ModNames.sve) +apples = villager(ModNPC.apples, False, aurora + junimo, Generic.any, starfruit, False, ModNames.sve) gunther = villager(ModNPC.gunther, False, museum, Season.winter, universal_loves + gunther_loves, True, ModNames.jasper_sve) martin = villager(ModNPC.martin, False, town + jojamart, Season.summer, universal_loves + martin_loves, True, ModNames.sve) marlon = villager(ModNPC.marlon, False, adventurer, Season.winter, universal_loves + marlon_loves, False, ModNames.jasper_sve) From e1beb4e4d83095c8caea6d3f94cc138a6b76d1f4 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 1 Jan 2024 18:54:40 -0600 Subject: [PATCH 420/482] Give logic for no birthday --- worlds/stardew_valley/logic/relationship_logic.py | 2 ++ worlds/stardew_valley/logic/season_logic.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index b7a642816d5e..53deb5e9a2d8 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -165,6 +165,8 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: villager = all_villagers_by_name[npc] if hearts > 2 or hearts > self.options.friendsanity_heart_size: rules.append(self.logic.season.has(villager.birthday)) + if villager.birthday == Generic.any: + rules.append(self.logic.season.has_all() | self.logic.time.has_year_three) # push logic back for any birthday-less villager if villager.bachelor: if hearts > 8: rules.append(self.logic.relationship.can_date(npc)) diff --git a/worlds/stardew_valley/logic/season_logic.py b/worlds/stardew_valley/logic/season_logic.py index 03a5fd423813..1953502099b4 100644 --- a/worlds/stardew_valley/logic/season_logic.py +++ b/worlds/stardew_valley/logic/season_logic.py @@ -5,7 +5,7 @@ from .received_logic import ReceivedLogicMixin from .time_logic import TimeLogicMixin from ..options import SeasonRandomization -from ..stardew_rule import StardewRule, True_, Or +from ..stardew_rule import StardewRule, True_, Or, And from ..strings.generic_names import Generic from ..strings.season_names import Season @@ -38,3 +38,7 @@ def has_any(self, seasons: Iterable[str]): def has_any_not_winter(self): return self.logic.season.has_any([Season.spring, Season.summer, Season.fall]) + + def has_all(self): + seasons = [Season.spring, Season.summer, Season.fall, Season.winter] + return And(*(self.logic.season.has(season) for season in seasons)) From 443702d0fad1eeba9f41a6253d3ea1ca913679c8 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 2 Jan 2024 12:03:01 -0600 Subject: [PATCH 421/482] Add more logic to void shard --- worlds/stardew_valley/mods/logic/item_logic.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 6d68654c5254..8e680f2fba8e 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -15,6 +15,8 @@ from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin +from ...logic.skill_logic import SkillLogicMixin +from ...logic.time_logic import TimeLogicMixin from ...logic.tool_logic import ToolLogicMixin from ...options import Cropsanity from ...stardew_rule import StardewRule, True_ @@ -29,6 +31,7 @@ from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed, DistantLandsSeed +from ...strings.skill_names import Skill from ...strings.tool_names import Tool, ToolMaterial from ...strings.villager_names import ModNPC @@ -43,7 +46,7 @@ def __init__(self, *args, **kwargs): class ModItemLogic(BaseLogic[Union[CombatLogicMixin, ReceivedLogicMixin, CropLogicMixin, CookingLogicMixin, FishingLogicMixin, HasLogicMixin, MoneyLogicMixin, -RegionLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin]]): +RegionLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin, SkillLogicMixin, TimeLogicMixin]]): def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() @@ -105,7 +108,8 @@ def get_sve_item_rules(self): "Stamina Capsule": self.logic.money.can_spend_at(Region.hospital, 4000), SVEForage.thistle: self.logic.region.can_reach(SVERegion.summit), SVEForage.void_pebble: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_great_weapon, - ModLoot.void_shard: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_galaxy_weapon + ModLoot.void_shard: self.logic.region.can_reach(SVERegion.crimson_badlands) & self.logic.combat.has_galaxy_weapon & + self.logic.skill.has_level(Skill.combat, 10) & self.logic.region.can_reach(Region.saloon) & self.logic.time.has_year_three } # @formatter:on From 78415fc562625a20e6a066965f2c2ca346e48c2c Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 2 Jan 2024 12:22:58 -0600 Subject: [PATCH 422/482] Fix Void Soul logic --- worlds/stardew_valley/mods/logic/quests_logic.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 800091d24838..9d34efdfa1f8 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -4,6 +4,7 @@ from ...logic.base_logic import BaseLogic, BaseLogicMixin from ...logic.has_logic import HasLogicMixin from ...logic.quest_logic import QuestLogicMixin +from ...logic.monster_logic import MonsterLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin @@ -19,10 +20,11 @@ from ...strings.material_names import Material from ...strings.metal_names import Ore, MetalBar from ...strings.monster_drop_names import Loot +from ...strings.monster_names import Monster from ...strings.quest_names import Quest, ModQuest from ...strings.region_names import Region, SVERegion, BoardingHouseRegion from ...strings.season_names import Season -from ...strings.villager_names import ModNPC +from ...strings.villager_names import ModNPC, NPC from ...strings.wallet_item_names import Wallet @@ -32,7 +34,7 @@ def __init__(self, *args, **kwargs): self.quest = ModQuestLogic(*args, **kwargs) -class ModQuestLogic(BaseLogic[Union[HasLogicMixin, QuestLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin]]): +class ModQuestLogic(BaseLogic[Union[HasLogicMixin, QuestLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MonsterLogicMixin]]): def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = dict() quests.update(self._get_juna_quest_rules()) @@ -81,7 +83,10 @@ def _get_sve_quest_rules(self): self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), - ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul), + ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul) & self.logic.region.can_reach(Region.farm) & + self.logic.season.has_any_not_winter() & self.logic.region.can_reach(SVERegion.badlands_entrance) & + self.logic.relationship.has_hearts(NPC.krobus, 10) & self.logic.quest.can_complete_quest(ModQuest.MonsterCrops) & + self.logic.monster.can_kill_any([Monster.shadow_brute, Monster.shadow_shaman, Monster.shadow_sniper]), } def _get_distant_lands_quest_rules(self): From 72a48f946c673d2dd2543f6fde514de8f35d7a2f Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 2 Jan 2024 12:23:13 -0600 Subject: [PATCH 423/482] Clean up void soul logic --- worlds/stardew_valley/mods/logic/quests_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 9d34efdfa1f8..ddb09f97f183 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -83,7 +83,7 @@ def _get_sve_quest_rules(self): self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), - ModQuest.VoidSoul: self.logic.region.can_reach(Region.sewer) & self.logic.has(SVEForage.void_soul) & self.logic.region.can_reach(Region.farm) & + ModQuest.VoidSoul: self.logic.has(SVEForage.void_soul) & self.logic.region.can_reach(Region.farm) & self.logic.season.has_any_not_winter() & self.logic.region.can_reach(SVERegion.badlands_entrance) & self.logic.relationship.has_hearts(NPC.krobus, 10) & self.logic.quest.can_complete_quest(ModQuest.MonsterCrops) & self.logic.monster.can_kill_any([Monster.shadow_brute, Monster.shadow_shaman, Monster.shadow_sniper]), From 44c9cf52833c8649b3d7b5ceed643e6074d20821 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 2 Jan 2024 14:26:39 -0600 Subject: [PATCH 424/482] Fix Void Soul quest name --- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/strings/quest_names.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index d46ff9401257..f9cb203a5dc5 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2554,7 +2554,7 @@ id,region,name,tags,mod_name 7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded 7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded 7511,Adventurer's Guild,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul,"STORY_QUEST",Stardew Valley Expanded +7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded 7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded diff --git a/worlds/stardew_valley/strings/quest_names.py b/worlds/stardew_valley/strings/quest_names.py index 04faae81cf0c..2c02381609ec 100644 --- a/worlds/stardew_valley/strings/quest_names.py +++ b/worlds/stardew_valley/strings/quest_names.py @@ -62,7 +62,7 @@ class ModQuest: MarlonsBoat = "Marlon's Boat" AuroraVineyard = "Aurora Vineyard" MonsterCrops = "Monster Crops" - VoidSoul = "Void Soul" + VoidSoul = "Void Soul Retrieval" WizardInvite = "Wizard's Invite" CorruptedCropsTask = "Corrupted Crops Task" ANewPot = "A New Pot" From 730ff0eed7b1bcb20c12a4c38a8ba5ed7bdcf480 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Wed, 3 Jan 2024 03:07:15 -0600 Subject: [PATCH 425/482] Modify green mushroom logic --- worlds/stardew_valley/mods/logic/item_logic.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 8e680f2fba8e..1b663a8639ce 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -27,7 +27,7 @@ from ...strings.forageable_names import SVEForage, DistantLandsForageable from ...strings.gift_names import SVEGift from ...strings.metal_names import all_fossils, all_artifacts -from ...strings.monster_drop_names import ModLoot +from ...strings.monster_drop_names import ModLoot, Loot from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed, DistantLandsSeed @@ -58,11 +58,16 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: items.update(self.get_distant_lands_item_rules()) return items + def append_vanilla_item_rules(self, item_rule: Dict[str, StardewRule]): + if ModNames.sve in self.options.mods: + self.append_vanilla_rules_for_sve(item_rule) + def get_sve_item_rules(self): return {SVEGift.aged_blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 28000), SVEGift.blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 3000), SVESeed.fungus_seed: self.logic.region.can_reach(SVERegion.highlands_cavern) & self.logic.combat.has_good_weapon, - ModLoot.green_mushroom: self.logic.region.can_reach(SVERegion.highlands_outside) & self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron), + ModLoot.green_mushroom: self.logic.region.can_reach(SVERegion.highlands_outside) & + self.logic.tool.has_tool(Tool.axe, ToolMaterial.iron) & self.logic.season.has_any_not_winter(), SVEFruit.monster_fruit: self.logic.season.has(Season.summer) & self.logic.has(SVESeed.stalk_seed), SVEVegetable.monster_mushroom: self.logic.season.has(Season.fall) & self.logic.has(SVESeed.fungus_seed), SVEForage.ornate_treasure_chest: self.logic.region.can_reach(SVERegion.highlands_outside) & self.logic.combat.has_galaxy_weapon & @@ -113,6 +118,12 @@ def get_sve_item_rules(self): } # @formatter:on + def append_vanilla_rules_for_sve(self, items: Dict[str, StardewRule]): + items.update({ + Loot.void_essence: items[Loot.void_essence] | self.logic.region.can_reach(SVERegion.highlands_cavern) | self.logic.region.can_reach(SVERegion.crimson_badlands), + Loot.solar_essence: items[Loot.solar_essence] | self.logic.region.can_reach(SVERegion.crimson_badlands) + }) + def get_archaeology_item_rules(self): archaeology_item_rules = {} preservation_chamber_rule = self.logic.has(ModMachine.preservation_chamber) From 754bbd1ed7c4d31db2b952a5fafe385b1ec46ac0 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 4 Jan 2024 08:51:05 -0600 Subject: [PATCH 426/482] Add item logic for mods --- worlds/stardew_valley/logic/logic.py | 2 + worlds/stardew_valley/logic/tool_logic.py | 16 +++- .../stardew_valley/mods/logic/item_logic.py | 82 +++++++++++++++---- worlds/stardew_valley/strings/season_names.py | 2 + 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index d460355dc713..ccee3ba1c148 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -402,7 +402,9 @@ def __init__(self, player: int, options: StardewValleyOptions): self.registry.item_rules.update(self.registry.tree_fruit_rules) self.registry.item_rules.update(self.registry.seed_rules) self.registry.item_rules.update(self.registry.crop_rules) + self.registry.item_rules.update(self.mod.item.get_modded_item_rules()) + self.mod.item.append_vanilla_item_rules(self.registry.item_rules) # New regions and content means new ways to obtain old items # For some recipes, the cooked item can be obtained directly, so we either cook it or get it for recipe in self.registry.cooking_rules: diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 92d85c10f392..0ae6a67f5086 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, Iterable from Utils import cache_self1 from .base_logic import BaseLogicMixin, BaseLogic @@ -9,9 +9,10 @@ from .season_logic import SeasonLogicMixin from ..mods.logic.magic_logic import MagicLogicMixin from ..options import ToolProgression -from ..stardew_rule import StardewRule, True_ +from ..stardew_rule import StardewRule, True_, False_ from ..strings.ap_names.skill_level_names import ModSkillLevel from ..strings.region_names import Region +from ..strings.skill_names import ModSkill from ..strings.spells import MagicSpell from ..strings.tool_names import ToolMaterial, Tool @@ -47,6 +48,9 @@ def has_tool(self, tool: str, material: str = ToolMaterial.basic) -> StardewRule return self.logic.has(f"{material} Bar") & self.logic.money.can_spend(tool_upgrade_prices[material]) + def can_use_tool_at(self, tool: str, material: str, region: str) -> StardewRule: + return self.has_tool(tool, material) & self.logic.region.can_reach(region) + @cache_self1 def has_fishing_rod(self, level: int) -> StardewRule: if self.options.tool_progression & ToolProgression.option_progressive: @@ -59,8 +63,12 @@ def has_fishing_rod(self, level: int) -> StardewRule: return self.logic.money.can_spend_at(Region.fish_shop, prices[level]) # Should be cached - def can_forage(self, season: str, region: str = Region.forest, need_hoe: bool = False) -> StardewRule: - season_rule = self.logic.season.has(season) + def can_forage(self, season: str | Iterable[str], region: str = Region.forest, need_hoe: bool = False) -> StardewRule: + season_rule = False_() + if type(season) is str: + season_rule = self.logic.season.has(season) + if type(season) is Iterable[str]: + season_rule = self.logic.season.has_any(season) region_rule = self.logic.region.can_reach(region) if need_hoe: return season_rule & region_rule & self.logic.tool.has_tool(Tool.hoe) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 1b663a8639ce..a8ddeaa10590 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -21,14 +21,18 @@ from ...options import Cropsanity from ...stardew_rule import StardewRule, True_ from ...strings.craftable_names import ModCraftable, ModEdible, ModMachine -from ...strings.crop_names import SVEVegetable, SVEFruit, DistantLandsCrop -from ...strings.fish_names import DistantLandsFish -from ...strings.food_names import SVEMeal, SVEBeverage -from ...strings.forageable_names import SVEForage, DistantLandsForageable +from ...strings.crop_names import SVEVegetable, SVEFruit, DistantLandsCrop, Fruit +from ...strings.fish_names import DistantLandsFish, WaterItem, Fish +from ...strings.flower_names import Flower +from ...strings.food_names import SVEMeal, SVEBeverage, Meal +from ...strings.forageable_names import SVEForage, DistantLandsForageable, Forageable from ...strings.gift_names import SVEGift -from ...strings.metal_names import all_fossils, all_artifacts +from ...strings.ingredient_names import Ingredient +from ...strings.material_names import Material +from ...strings.metal_names import all_fossils, all_artifacts, Ore from ...strings.monster_drop_names import ModLoot, Loot -from ...strings.region_names import Region, SVERegion +from ...strings.performance_names import Performance +from ...strings.region_names import Region, SVERegion, DeepWoodsRegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed, DistantLandsSeed from ...strings.skill_names import Skill @@ -60,7 +64,10 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: def append_vanilla_item_rules(self, item_rule: Dict[str, StardewRule]): if ModNames.sve in self.options.mods: - self.append_vanilla_rules_for_sve(item_rule) + item_rule.update(self.append_vanilla_item_rules_for_sve(item_rule)) + if ModNames.deepwoods in self.options.mods: + item_rule.update(self.append_vanilla_item_rules_for_deep_woods(item_rule)) + return item_rule def get_sve_item_rules(self): return {SVEGift.aged_blue_moon_wine: self.logic.money.can_spend_at(SVERegion.sophias_house, 28000), @@ -86,7 +93,7 @@ def get_sve_item_rules(self): SVEForage.red_baneberry: self.logic.region.can_reach(Region.secret_woods) & self.logic.season.has(Season.summer), SVEForage.ferngill_primrose: self.logic.region.can_reach(SVERegion.summit) & self.logic.season.has(Season.spring), SVEForage.goldenrod: self.logic.region.can_reach(SVERegion.summit) & ( - self.logic.season.has(Season.summer) | self.logic.season.has(Season.fall)), + self.logic.season.has(Season.summer) | self.logic.season.has(Season.fall)), SVESeed.shrub_seed: self.logic.region.can_reach(Region.secret_woods) & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic), SVEFruit.salal_berry: self.logic.crop.can_plant_and_grow_item([Season.spring, Season.summer]) & self.logic.has(SVESeed.shrub_seed), ModEdible.aegis_elixir: self.logic.money.can_spend_at(SVERegion.galmoran_outpost, 28000), @@ -118,11 +125,58 @@ def get_sve_item_rules(self): } # @formatter:on - def append_vanilla_rules_for_sve(self, items: Dict[str, StardewRule]): - items.update({ - Loot.void_essence: items[Loot.void_essence] | self.logic.region.can_reach(SVERegion.highlands_cavern) | self.logic.region.can_reach(SVERegion.crimson_badlands), - Loot.solar_essence: items[Loot.solar_essence] | self.logic.region.can_reach(SVERegion.crimson_badlands) - }) + def append_vanilla_item_rules_for_sve(self, items: Dict[str, StardewRule]): + return { + Loot.void_essence: items[Loot.void_essence] | self.logic.region.can_reach(SVERegion.highlands_cavern) | self.logic.region.can_reach( + SVERegion.crimson_badlands), + Loot.solar_essence: items[Loot.solar_essence] | self.logic.region.can_reach(SVERegion.crimson_badlands), + Flower.tulip: items[Flower.tulip] | self.logic.tool.can_forage(Season.spring, SVERegion.sprite_spring), + Flower.blue_jazz: items[Flower.blue_jazz] | self.logic.tool.can_forage(Season.spring, SVERegion.sprite_spring), + Flower.summer_spangle: items[Flower.summer_spangle] | self.logic.tool.can_forage(Season.summer, SVERegion.sprite_spring), + Flower.sunflower: items[Flower.sunflower] | self.logic.tool.can_forage((Season.summer, Season.fall), SVERegion.sprite_spring), + Flower.fairy_rose: items[Flower.fairy_rose] | self.logic.tool.can_forage(Season.fall, SVERegion.sprite_spring), + Fruit.ancient_fruit: items[Fruit.ancient_fruit] | ( + self.logic.tool.can_forage((Season.spring, Season.summer, Season.fall), SVERegion.sprite_spring) & + self.logic.time.has_year_three) | self.logic.region.can_reach(SVERegion.sprite_spring_cave), + Fruit.sweet_gem_berry: items[Fruit.sweet_gem_berry] | (self.logic.tool.can_forage((Season.spring, Season.summer, Season.fall), SVERegion.sprite_spring) & + self.logic.time.has_year_three), + WaterItem.coral: items[WaterItem.coral] | self.logic.region.can_reach(SVERegion.fable_reef), + Forageable.rainbow_shell: items[Forageable.rainbow_shell] | self.logic.region.can_reach(SVERegion.fable_reef), + WaterItem.sea_urchin: items[WaterItem.sea_urchin] | self.logic.region.can_reach(SVERegion.fable_reef), + Forageable.red_mushroom: items[Forageable.red_mushroom] | self.logic.tool.can_forage((Season.summer, Season.fall), SVERegion.forest_west) | + self.logic.region.can_reach(SVERegion.sprite_spring_cave), + Forageable.purple_mushroom: items[Forageable.purple_mushroom] | self.logic.tool.can_forage(Season.fall, SVERegion.forest_west) | + self.logic.region.can_reach(SVERegion.sprite_spring_cave), + Forageable.morel: items[Forageable.morel] | self.logic.tool.can_forage(Season.fall, SVERegion.forest_west), + Forageable.chanterelle: items[Forageable.chanterelle] | self.logic.tool.can_forage(Season.fall, SVERegion.forest_west) | + self.logic.region.can_reach(SVERegion.sprite_spring_cave), + Ore.copper: items[Ore.copper] | (self.logic.tool.can_use_tool_at(Tool.pickaxe, ToolMaterial.basic, SVERegion.highlands_cavern) & + self.logic.combat.can_fight_at_level(Performance.great)), + Ore.iron: items[Ore.iron] | (self.logic.tool.can_use_tool_at(Tool.pickaxe, ToolMaterial.basic, SVERegion.highlands_cavern) & + self.logic.combat.can_fight_at_level(Performance.great)), + Ore.iridium: items[Ore.iridium] | (self.logic.tool.can_use_tool_at(Tool.pickaxe, ToolMaterial.basic, SVERegion.crimson_badlands) & + self.logic.combat.can_fight_at_level(Performance.maximum)), + } + + def append_vanilla_item_rules_for_deep_woods(self, items: Dict[str, StardewRule]): + return { + Fruit.apple: items[Fruit.apple] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), # Deep enough to have seen such a tree at least once + Fruit.apricot: items[Fruit.apricot] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Fruit.cherry: items[Fruit.cherry] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Fruit.orange: items[Fruit.orange] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Fruit.peach: items[Fruit.peach] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Fruit.pomegranate: items[Fruit.pomegranate] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Fruit.mango: items[Fruit.mango] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Flower.tulip: items[Flower.tulip] | self.logic.tool.can_forage(Season.not_winter, DeepWoodsRegion.floor_10), + Flower.blue_jazz: items[Flower.blue_jazz] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Flower.summer_spangle: items[Flower.summer_spangle] | self.logic.tool.can_forage(Season.not_winter, DeepWoodsRegion.floor_10), + Flower.poppy: items[Flower.poppy] | self.logic.tool.can_forage(Season.not_winter, DeepWoodsRegion.floor_10), + Flower.fairy_rose: items[Flower.fairy_rose] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), + Material.hardwood: items[Material.hardwood] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.iron, DeepWoodsRegion.floor_10), + Ore.iridium: items[Ore.iridium] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.iridium, DeepWoodsRegion.floor_50), # Iridium Tree + Ingredient.sugar: items[Ingredient.sugar] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.gold, DeepWoodsRegion.floor_50), # Gingerbread House + Ingredient.wheat_flour: items[Ingredient.wheat_flour] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.gold, DeepWoodsRegion.floor_50), # Gingerbread House + } def get_archaeology_item_rules(self): archaeology_item_rules = {} @@ -142,7 +196,7 @@ def get_archaeology_item_rules(self): return archaeology_item_rules def get_distant_lands_item_rules(self): - return{ + return { DistantLandsForageable.swamp_herb: self.logic.region.can_reach(Region.witch_swamp), DistantLandsForageable.brown_amanita: self.logic.region.can_reach(Region.witch_swamp), DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.has_seed_unlocked(DistantLandsSeed.vile_ancient_fruit), diff --git a/worlds/stardew_valley/strings/season_names.py b/worlds/stardew_valley/strings/season_names.py index 5042c271e5bb..f3659bc87fe0 100644 --- a/worlds/stardew_valley/strings/season_names.py +++ b/worlds/stardew_valley/strings/season_names.py @@ -4,3 +4,5 @@ class Season: fall = "Fall" winter = "Winter" progressive = "Progressive Season" + + not_winter = (spring, summer, fall,) From 715af5c629ed09dac9a1706a4c5d94d76e62f467 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 5 Jan 2024 06:45:32 -0600 Subject: [PATCH 427/482] Add mod regions to monsters --- worlds/stardew_valley/data/monster_data.py | 68 +++++++++++++++++--- worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/logic/monster_logic.py | 6 +- worlds/stardew_valley/rules.py | 46 +++++++------ 4 files changed, 89 insertions(+), 33 deletions(-) diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 1852735d2609..99d187cb152b 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -1,9 +1,11 @@ from dataclasses import dataclass -from typing import List, Tuple +from typing import List, Tuple, Dict, Set, Callable +from Utils import cache_self1 +from ..mods.mod_data import ModNames from ..strings.monster_names import Monster, MonsterCategory from ..strings.performance_names import Performance -from ..strings.region_names import Region +from ..strings.region_names import Region, SVERegion, DeepWoodsRegion, BoardingHouseRegion @dataclass(frozen=True) @@ -35,6 +37,7 @@ def __repr__(self): volcano_high = (Region.volcano_floor_10,) all_monsters: List[StardewMonster] = [] +monster_modifications_by_mod: Dict[str, Dict[str, Callable[[str, StardewMonster], StardewMonster]]] = {} def create_monster(name: str, category: str, locations: Tuple[str, ...], difficulty: str) -> StardewMonster: @@ -43,6 +46,17 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu return monster +def update_monster_locations(monster: StardewMonster, locations: Tuple[str, ...]): + new_locations = monster.locations + locations + return StardewMonster(monster.name, monster.category, new_locations, monster.difficulty) + + +def register_monster_modification(mod_name: str, monster: StardewMonster, modification_function): + if mod_name not in monster_modifications_by_mod: + monster_modifications_by_mod[mod_name] = {} + monster_modifications_by_mod[mod_name][monster.name] = modification_function + + green_slime = create_monster(Monster.green_slime, MonsterCategory.slime, mines_floor_20, Performance.basic) blue_slime = create_monster(Monster.blue_slime, MonsterCategory.slime, mines_floor_60, Performance.decent) red_slime = create_monster(Monster.red_slime, MonsterCategory.slime, mines_floor_100, Performance.good) @@ -107,9 +121,47 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu magma_sprite = create_monster(Monster.magma_sprite, MonsterCategory.magma_sprites, volcano, Performance.galaxy) magma_sparker = create_monster(Monster.magma_sparker, MonsterCategory.magma_sprites, volcano_high, Performance.galaxy) -all_monsters_by_name = {monster.name: monster for monster in all_monsters} -all_monsters_by_category = {} -for monster in all_monsters: - if monster.category not in all_monsters_by_category: - all_monsters_by_category[monster.category] = () - all_monsters_by_category[monster.category] = all_monsters_by_category[monster.category] + (monster,) +register_monster_modification(ModNames.sve, shadow_brute_dangerous, update_monster_locations(shadow_brute_dangerous, (SVERegion.highlands_cavern,) )) +register_monster_modification(ModNames.sve, shadow_sniper, update_monster_locations(shadow_sniper, (SVERegion.highlands_cavern,) )) +register_monster_modification(ModNames.sve, shadow_shaman_dangerous, update_monster_locations(shadow_shaman_dangerous, (SVERegion.highlands_cavern,) )) +register_monster_modification(ModNames.sve, mummy_dangerous, update_monster_locations(mummy_dangerous, (SVERegion.crimson_badlands,) )) +register_monster_modification(ModNames.sve, royal_serpent, update_monster_locations(royal_serpent, (SVERegion.crimson_badlands,) )) +register_monster_modification(ModNames.sve, skeleton_dangerous, update_monster_locations(skeleton_dangerous, (SVERegion.crimson_badlands,) )) +register_monster_modification(ModNames.sve, skeleton_mage, update_monster_locations(skeleton_mage, (SVERegion.crimson_badlands,) )) +register_monster_modification(ModNames.sve, dust_sprite_dangerous, update_monster_locations(dust_sprite_dangerous, (SVERegion.highlands_outside,) )) + +register_monster_modification(ModNames.deepwoods, shadow_brute, update_monster_locations(shadow_brute, (DeepWoodsRegion.floor_10,) )) +register_monster_modification(ModNames.deepwoods, cave_fly, update_monster_locations(cave_fly, (DeepWoodsRegion.floor_10,) )) +register_monster_modification(ModNames.deepwoods, green_slime, update_monster_locations(green_slime, (DeepWoodsRegion.floor_10,) )) + +register_monster_modification(ModNames.boarding_house, shadow_brute, + update_monster_locations(shadow_brute, (BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,) )) +register_monster_modification(ModNames.boarding_house, pepper_rex, + update_monster_locations(pepper_rex, (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,) )) + + +def all_monsters_by_name(mods: Set[str]) -> Dict[str, StardewMonster]: + monsters_by_name = {} + for monster in all_monsters: + current_monster = monster + for mod in monster_modifications_by_mod: + if mod not in mods or monster.name not in monster_modifications_by_mod[mod]: + continue + current_monster = monster_modifications_by_mod[mod][monster.name] + monsters_by_name[monster.name] = current_monster + return monsters_by_name + + +def all_monsters_by_category(mods: Set[str]) -> Dict[str, Tuple[StardewMonster,...]]: + monsters_by_category = {} + for monster in all_monsters: + current_monster = monster + for mod in monster_modifications_by_mod: + if mod not in mods or monster.name not in monster_modifications_by_mod[mod]: + continue + current_monster = monster_modifications_by_mod[mod][monster.name] + if current_monster.category not in monsters_by_category: + monsters_by_category[monster.category] = () + monsters_by_category[current_monster.category] = monsters_by_category[current_monster.category] + (current_monster,) + return monsters_by_category diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index ccee3ba1c148..9cdf58ad71e0 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -254,7 +254,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Fish.periwinkle: self.skill.can_crab_pot_at(Region.town), Fish.shrimp: self.skill.can_crab_pot_at(Region.beach), Fish.snail: self.skill.can_crab_pot_at(Region.town), - Fishing.curiosity_lure: self.monster.can_kill(all_monsters_by_name[Monster.mummy]), + Fishing.curiosity_lure: self.monster.can_kill(all_monsters_by_name(self.options.mods)[Monster.mummy]), Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200), Forageable.blackberry: self.tool.can_forage(Season.fall) | self.has_fruit_bats(), Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index 0e84475c0af9..b57a68fc5498 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -20,7 +20,7 @@ def __init__(self, *args, **kwargs): class MonsterLogic(BaseLogic[Union[MonsterLogicMixin, RegionLogicMixin, CombatLogicMixin, TimeLogicMixin]]): def can_kill(self, monster: Union[str, monster_data.StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): - monster = monster_data.all_monsters_by_name[monster] + monster = monster_data.all_monsters_by_name(self.options.mods.value)[monster] region_rule = self.logic.region.can_reach_any(monster.locations) combat_rule = self.logic.combat.can_fight_at_level(monster.difficulty) if amount_tier <= 0: @@ -50,10 +50,10 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: rules = [self.logic.time.has_lived_max_months] exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern] - for category in monster_data.all_monsters_by_category: + for category in monster_data.all_monsters_by_category(self.options.mods.value): if exclude_island and all(all(location in island_regions for location in monster.locations) for monster in monster_data.all_monsters_by_category[category]): continue - rules.append(self.logic.monster.can_kill_any(monster_data.all_monsters_by_category[category])) + rules.append(self.logic.monster.can_kill_any(monster_data.all_monsters_by_category(self.options.mods.value)[category])) return And(*rules) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index a567393818c5..90c93c555201 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -624,53 +624,56 @@ def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, return if monstersanity_option == Monstersanity.option_one_per_monster or monstersanity_option == Monstersanity.option_split_goals: - set_monstersanity_monster_rules(all_location_names, logic, multiworld, player, monstersanity_option) + set_monstersanity_monster_rules(all_location_names, logic, multiworld, player, world_options) return if monstersanity_option == Monstersanity.option_progressive_goals: - set_monstersanity_progressive_category_rules(all_location_names, logic, multiworld, player) + set_monstersanity_progressive_category_rules(all_location_names, logic, multiworld, player, world_options) return - set_monstersanity_category_rules(all_location_names, logic, multiworld, player, monstersanity_option) + set_monstersanity_category_rules(all_location_names, logic, multiworld, player, world_options) -def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monstersanity_option): - for monster_name in all_monsters_by_name: +def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + monsters_by_name = all_monsters_by_name(world_options.mods.value) + for monster_name in monsters_by_name: location_name = f"{monster_eradication_prefix}{monster_name}" if location_name not in all_location_names: continue location = multiworld.get_location(location_name, player) - if monstersanity_option == Monstersanity.option_split_goals: - rule = logic.monster.can_kill_many(all_monsters_by_name[monster_name]) + if world_options.monstersanity == Monstersanity.option_split_goals: + rule = logic.monster.can_kill_many(monsters_by_name[monster_name]) else: - rule = logic.monster.can_kill(all_monsters_by_name[monster_name]) + rule = logic.monster.can_kill(monsters_by_name[monster_name]) MultiWorldRules.set_rule(location, rule) -def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): - for monster_category in all_monsters_by_category: - set_monstersanity_progressive_single_category_rules(all_location_names, logic, multiworld, player, monster_category) +def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + for monster_category in all_monsters_by_category(world_options.mods.value): + set_monstersanity_progressive_single_category_rules(all_location_names, logic, multiworld, player, monster_category, world_options) -def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monster_category: str): +def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monster_category: str, + world_options: StardewValleyOptions): location_names = [name for name in all_location_names if name.startswith(monster_eradication_prefix) and name.endswith(monster_category)] if not location_names: return location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) for i in range(5): location_name = location_names[i] - set_monstersanity_progressive_category_rule(all_location_names, logic, multiworld, player, monster_category, location_name, i) + set_monstersanity_progressive_category_rule(all_location_names, logic, multiworld, player, monster_category, location_name, world_options, i) def set_monstersanity_progressive_category_rule(all_location_names: List[str], logic: StardewLogic, multiworld, player, - monster_category: str, location_name: str, goal_index): + monster_category: str, location_name: str, world_options: StardewValleyOptions, goal_index): if location_name not in all_location_names: return + monsters_by_category = all_monsters_by_category(world_options.mods.value) location = multiworld.get_location(location_name, player) if goal_index < 3: - rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category], goal_index + 1) + rule = logic.monster.can_kill_any(monsters_by_category[monster_category], goal_index + 1) else: - rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], goal_index * 2) + rule = logic.monster.can_kill_all(monsters_by_category[monster_category], goal_index * 2) MultiWorldRules.set_rule(location, rule) @@ -682,16 +685,17 @@ def get_monster_eradication_number(location_name, monster_category) -> int: return 1000 -def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monstersanity_option): - for monster_category in all_monsters_by_category: +def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): + monsters_by_category = all_monsters_by_category(world_options.mods.value) + for monster_category in monsters_by_category: location_name = f"{monster_eradication_prefix}{monster_category}" if location_name not in all_location_names: continue location = multiworld.get_location(location_name, player) - if monstersanity_option == Monstersanity.option_one_per_category: - rule = logic.monster.can_kill_any(all_monsters_by_category[monster_category]) + if world_options.monstersanity == Monstersanity.option_one_per_category: + rule = logic.monster.can_kill_any(monsters_by_category[monster_category]) else: - rule = logic.monster.can_kill_all(all_monsters_by_category[monster_category], 4) + rule = logic.monster.can_kill_all(monsters_by_category[monster_category], 4) MultiWorldRules.set_rule(location, rule) From 12bd06e6ce4c0a14acb4dfe0f47403906774575d Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 5 Jan 2024 15:54:28 -0600 Subject: [PATCH 428/482] Clean up references to new content --- worlds/stardew_valley/data/monster_data.py | 9 +-------- worlds/stardew_valley/mods/logic/quests_logic.py | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 99d187cb152b..e93a33fb6011 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -5,7 +5,7 @@ from ..mods.mod_data import ModNames from ..strings.monster_names import Monster, MonsterCategory from ..strings.performance_names import Performance -from ..strings.region_names import Region, SVERegion, DeepWoodsRegion, BoardingHouseRegion +from ..strings.region_names import Region, SVERegion, DeepWoodsRegion @dataclass(frozen=True) @@ -134,13 +134,6 @@ def register_monster_modification(mod_name: str, monster: StardewMonster, modifi register_monster_modification(ModNames.deepwoods, cave_fly, update_monster_locations(cave_fly, (DeepWoodsRegion.floor_10,) )) register_monster_modification(ModNames.deepwoods, green_slime, update_monster_locations(green_slime, (DeepWoodsRegion.floor_10,) )) -register_monster_modification(ModNames.boarding_house, shadow_brute, - update_monster_locations(shadow_brute, (BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,) )) -register_monster_modification(ModNames.boarding_house, pepper_rex, - update_monster_locations(pepper_rex, (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,) )) - - def all_monsters_by_name(mods: Set[str]) -> Dict[str, StardewMonster]: monsters_by_name = {} for monster in all_monsters: diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index ddb09f97f183..69ddb92af34c 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -22,7 +22,7 @@ from ...strings.monster_drop_names import Loot from ...strings.monster_names import Monster from ...strings.quest_names import Quest, ModQuest -from ...strings.region_names import Region, SVERegion, BoardingHouseRegion +from ...strings.region_names import Region, SVERegion from ...strings.season_names import Season from ...strings.villager_names import ModNPC, NPC from ...strings.wallet_item_names import Wallet From dcd41a126c12545e0778e713f6876f6e112eeea2 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 5 Jan 2024 16:53:00 -0600 Subject: [PATCH 429/482] Fix from Rebase --- worlds/stardew_valley/data/monster_data.py | 1 + worlds/stardew_valley/logic/monster_logic.py | 2 +- worlds/stardew_valley/mods/logic/quests_logic.py | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index e93a33fb6011..65e6e2af4615 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -134,6 +134,7 @@ def register_monster_modification(mod_name: str, monster: StardewMonster, modifi register_monster_modification(ModNames.deepwoods, cave_fly, update_monster_locations(cave_fly, (DeepWoodsRegion.floor_10,) )) register_monster_modification(ModNames.deepwoods, green_slime, update_monster_locations(green_slime, (DeepWoodsRegion.floor_10,) )) + def all_monsters_by_name(mods: Set[str]) -> Dict[str, StardewMonster]: monsters_by_name = {} for monster in all_monsters: diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index b57a68fc5498..f0ecbef178af 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -52,7 +52,7 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern] for category in monster_data.all_monsters_by_category(self.options.mods.value): if exclude_island and all(all(location in island_regions for location in monster.locations) - for monster in monster_data.all_monsters_by_category[category]): + for monster in monster_data.all_monsters_by_category(self.options.mods.value)[category]): continue rules.append(self.logic.monster.can_kill_any(monster_data.all_monsters_by_category(self.options.mods.value)[category])) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 69ddb92af34c..c00bebc6df83 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -75,18 +75,18 @@ def _get_sve_quest_rules(self): return {} return { - ModQuest.RailroadBoulder: self.logic.received(Wallet.skull_key) & self.logic.has((Ore.iridium, Material.coal)) & + ModQuest.RailroadBoulder: self.logic.received(Wallet.skull_key) & self.logic.has_all(*(Ore.iridium, Material.coal)) & self.logic.region.can_reach(Region.blacksmith) & self.logic.region.can_reach(Region.railroad), - ModQuest.GrandpasShed: self.logic.has((Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & + ModQuest.GrandpasShed: self.logic.has_all(*(Material.hardwood, MetalBar.iron, ArtisanGood.battery_pack, Material.stone)) & self.logic.region.can_reach(SVERegion.grandpas_shed), - ModQuest.MarlonsBoat: self.logic.has((Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & + ModQuest.MarlonsBoat: self.logic.has_all(*(Loot.void_essence, Loot.solar_essence, Loot.slime, Loot.bat_wing, Loot.bug_meat)) & self.logic.relationship.can_meet(ModNPC.lance) & self.logic.region.can_reach(SVERegion.guild_summit), ModQuest.AuroraVineyard: self.logic.has(Fruit.starfruit) & self.logic.region.can_reach(SVERegion.aurora_vineyard), - ModQuest.MonsterCrops: self.logic.has((SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), + ModQuest.MonsterCrops: self.logic.has_all(*(SVEVegetable.monster_mushroom, SVEFruit.slime_berry, SVEFruit.monster_fruit, SVEVegetable.void_root)), ModQuest.VoidSoul: self.logic.has(SVEForage.void_soul) & self.logic.region.can_reach(Region.farm) & self.logic.season.has_any_not_winter() & self.logic.region.can_reach(SVERegion.badlands_entrance) & self.logic.relationship.has_hearts(NPC.krobus, 10) & self.logic.quest.can_complete_quest(ModQuest.MonsterCrops) & - self.logic.monster.can_kill_any([Monster.shadow_brute, Monster.shadow_shaman, Monster.shadow_sniper]), + self.logic.monster.can_kill_any((Monster.shadow_brute, Monster.shadow_shaman, Monster.shadow_sniper)), } def _get_distant_lands_quest_rules(self): From 9817f4901d5b2b8b6d3d4a8b2e3ac87cade7373b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 14 Jan 2024 17:36:08 -0600 Subject: [PATCH 430/482] Fix monsters --- worlds/stardew_valley/data/monster_data.py | 43 +++++++++++-------- worlds/stardew_valley/logic/logic.py | 3 +- worlds/stardew_valley/logic/monster_logic.py | 18 ++++++-- .../mods/mod_monster_locations.py | 27 ++++++++++++ worlds/stardew_valley/rules.py | 22 ++++------ 5 files changed, 75 insertions(+), 38 deletions(-) create mode 100644 worlds/stardew_valley/mods/mod_monster_locations.py diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 65e6e2af4615..b78bb1314229 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -5,7 +5,9 @@ from ..mods.mod_data import ModNames from ..strings.monster_names import Monster, MonsterCategory from ..strings.performance_names import Performance -from ..strings.region_names import Region, SVERegion, DeepWoodsRegion +from ..strings.region_names import Region + +from ..mods.mod_monster_locations import modded_monsters_locations @dataclass(frozen=True) @@ -46,9 +48,10 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu return monster -def update_monster_locations(monster: StardewMonster, locations: Tuple[str, ...]): - new_locations = monster.locations + locations - return StardewMonster(monster.name, monster.category, new_locations, monster.difficulty) +def update_monster_locations(mod_name: str, monster: StardewMonster): + new_locations = modded_monsters_locations[mod_name][monster.name] + total_locations = monster.locations + new_locations + return StardewMonster(monster.name, monster.category, total_locations, monster.difficulty) def register_monster_modification(mod_name: str, monster: StardewMonster, modification_function): @@ -121,40 +124,42 @@ def register_monster_modification(mod_name: str, monster: StardewMonster, modifi magma_sprite = create_monster(Monster.magma_sprite, MonsterCategory.magma_sprites, volcano, Performance.galaxy) magma_sparker = create_monster(Monster.magma_sparker, MonsterCategory.magma_sprites, volcano_high, Performance.galaxy) -register_monster_modification(ModNames.sve, shadow_brute_dangerous, update_monster_locations(shadow_brute_dangerous, (SVERegion.highlands_cavern,) )) -register_monster_modification(ModNames.sve, shadow_sniper, update_monster_locations(shadow_sniper, (SVERegion.highlands_cavern,) )) -register_monster_modification(ModNames.sve, shadow_shaman_dangerous, update_monster_locations(shadow_shaman_dangerous, (SVERegion.highlands_cavern,) )) -register_monster_modification(ModNames.sve, mummy_dangerous, update_monster_locations(mummy_dangerous, (SVERegion.crimson_badlands,) )) -register_monster_modification(ModNames.sve, royal_serpent, update_monster_locations(royal_serpent, (SVERegion.crimson_badlands,) )) -register_monster_modification(ModNames.sve, skeleton_dangerous, update_monster_locations(skeleton_dangerous, (SVERegion.crimson_badlands,) )) -register_monster_modification(ModNames.sve, skeleton_mage, update_monster_locations(skeleton_mage, (SVERegion.crimson_badlands,) )) -register_monster_modification(ModNames.sve, dust_sprite_dangerous, update_monster_locations(dust_sprite_dangerous, (SVERegion.highlands_outside,) )) +register_monster_modification(ModNames.sve, shadow_brute_dangerous, update_monster_locations) +register_monster_modification(ModNames.sve, shadow_sniper, update_monster_locations) +register_monster_modification(ModNames.sve, shadow_shaman_dangerous, update_monster_locations) +register_monster_modification(ModNames.sve, mummy_dangerous, update_monster_locations) +register_monster_modification(ModNames.sve, royal_serpent, update_monster_locations) +register_monster_modification(ModNames.sve, skeleton_dangerous, update_monster_locations) +register_monster_modification(ModNames.sve, skeleton_mage, update_monster_locations) +register_monster_modification(ModNames.sve, dust_sprite_dangerous, update_monster_locations) -register_monster_modification(ModNames.deepwoods, shadow_brute, update_monster_locations(shadow_brute, (DeepWoodsRegion.floor_10,) )) -register_monster_modification(ModNames.deepwoods, cave_fly, update_monster_locations(cave_fly, (DeepWoodsRegion.floor_10,) )) -register_monster_modification(ModNames.deepwoods, green_slime, update_monster_locations(green_slime, (DeepWoodsRegion.floor_10,) )) +register_monster_modification(ModNames.deepwoods, shadow_brute, update_monster_locations) +register_monster_modification(ModNames.deepwoods, cave_fly, update_monster_locations) +register_monster_modification(ModNames.deepwoods, green_slime, update_monster_locations) -def all_monsters_by_name(mods: Set[str]) -> Dict[str, StardewMonster]: +def all_monsters_by_name_given_mods(mods: Set[str]) -> Dict[str, StardewMonster]: monsters_by_name = {} for monster in all_monsters: current_monster = monster for mod in monster_modifications_by_mod: if mod not in mods or monster.name not in monster_modifications_by_mod[mod]: continue - current_monster = monster_modifications_by_mod[mod][monster.name] + modification_function = monster_modifications_by_mod[mod][monster.name] + current_monster = modification_function(mod, current_monster) monsters_by_name[monster.name] = current_monster return monsters_by_name -def all_monsters_by_category(mods: Set[str]) -> Dict[str, Tuple[StardewMonster,...]]: +def all_monsters_by_category_given_mods(mods: Set[str]) -> Dict[str, Tuple[StardewMonster,...]]: monsters_by_category = {} for monster in all_monsters: current_monster = monster for mod in monster_modifications_by_mod: if mod not in mods or monster.name not in monster_modifications_by_mod[mod]: continue - current_monster = monster_modifications_by_mod[mod][monster.name] + modification_function = monster_modifications_by_mod[mod][monster.name] + current_monster = modification_function(mod, current_monster) if current_monster.category not in monsters_by_category: monsters_by_category[monster.category] = () monsters_by_category[current_monster.category] = monsters_by_category[current_monster.category] + (current_monster,) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index 9cdf58ad71e0..df1bb2645dc5 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -41,7 +41,6 @@ from ..data.craftable_data import all_crafting_recipes from ..data.crops_data import crops_by_name from ..data.fish_data import get_fish_for_mods -from ..data.monster_data import all_monsters_by_name from ..data.museum_data import all_museum_items from ..data.recipe_data import all_cooking_recipes from ..mods.logic.magic_logic import MagicLogicMixin @@ -254,7 +253,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Fish.periwinkle: self.skill.can_crab_pot_at(Region.town), Fish.shrimp: self.skill.can_crab_pot_at(Region.beach), Fish.snail: self.skill.can_crab_pot_at(Region.town), - Fishing.curiosity_lure: self.monster.can_kill(all_monsters_by_name(self.options.mods)[Monster.mummy]), + Fishing.curiosity_lure: self.monster.can_kill(self.monster.all_monsters_by_name[Monster.mummy]), Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200), Forageable.blackberry: self.tool.can_forage(Season.fall) | self.has_fruit_bats(), Forageable.cactus_fruit: self.tool.can_forage(Generic.any, Region.desert), diff --git a/worlds/stardew_valley/logic/monster_logic.py b/worlds/stardew_valley/logic/monster_logic.py index f0ecbef178af..790f492347e6 100644 --- a/worlds/stardew_valley/logic/monster_logic.py +++ b/worlds/stardew_valley/logic/monster_logic.py @@ -1,3 +1,4 @@ +from functools import cached_property from typing import Iterable, Union, Hashable from Utils import cache_self1 @@ -18,9 +19,18 @@ def __init__(self, *args, **kwargs): class MonsterLogic(BaseLogic[Union[MonsterLogicMixin, RegionLogicMixin, CombatLogicMixin, TimeLogicMixin]]): + + @cached_property + def all_monsters_by_name(self): + return monster_data.all_monsters_by_name_given_mods(self.options.mods.value) + + @cached_property + def all_monsters_by_category(self): + return monster_data.all_monsters_by_category_given_mods(self.options.mods.value) + def can_kill(self, monster: Union[str, monster_data.StardewMonster], amount_tier: int = 0) -> StardewRule: if isinstance(monster, str): - monster = monster_data.all_monsters_by_name(self.options.mods.value)[monster] + monster = self.all_monsters_by_name[monster] region_rule = self.logic.region.can_reach_any(monster.locations) combat_rule = self.logic.combat.can_fight_at_level(monster.difficulty) if amount_tier <= 0: @@ -50,10 +60,10 @@ def can_complete_all_monster_slaying_goals(self) -> StardewRule: rules = [self.logic.time.has_lived_max_months] exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern] - for category in monster_data.all_monsters_by_category(self.options.mods.value): + for category in self.all_monsters_by_category: if exclude_island and all(all(location in island_regions for location in monster.locations) - for monster in monster_data.all_monsters_by_category(self.options.mods.value)[category]): + for monster in self.all_monsters_by_category[category]): continue - rules.append(self.logic.monster.can_kill_any(monster_data.all_monsters_by_category(self.options.mods.value)[category])) + rules.append(self.logic.monster.can_kill_any(self.all_monsters_by_category[category])) return And(*rules) diff --git a/worlds/stardew_valley/mods/mod_monster_locations.py b/worlds/stardew_valley/mods/mod_monster_locations.py new file mode 100644 index 000000000000..d775818cd8be --- /dev/null +++ b/worlds/stardew_valley/mods/mod_monster_locations.py @@ -0,0 +1,27 @@ +from typing import Dict, Tuple + +from .mod_data import ModNames +from ..strings.monster_names import Monster +from ..strings.region_names import SVERegion, DeepWoodsRegion + +sve_monsters_locations: Dict[str, Tuple[str, ...]] = { + Monster.shadow_brute_dangerous: (SVERegion.highlands_cavern,), + Monster.shadow_sniper: (SVERegion.highlands_cavern,), + Monster.shadow_shaman_dangerous: (SVERegion.highlands_cavern,), + Monster.mummy_dangerous: (SVERegion.crimson_badlands,), + Monster.royal_serpent: (SVERegion.crimson_badlands,), + Monster.skeleton_dangerous: (SVERegion.crimson_badlands,), + Monster.skeleton_mage: (SVERegion.crimson_badlands,), + Monster.dust_sprite_dangerous: (SVERegion.highlands_outside,), +} + +deepwoods_monsters_locations: Dict[str, Tuple[str, ...]] = { + Monster.shadow_brute: (DeepWoodsRegion.floor_10,), + Monster.cave_fly: (DeepWoodsRegion.floor_10,), + Monster.green_slime: (DeepWoodsRegion.floor_10,), +} + +modded_monsters_locations: Dict[str, Dict[str, Tuple[str, ...]]] = { + ModNames.sve: sve_monsters_locations, + ModNames.deepwoods: deepwoods_monsters_locations +} diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 90c93c555201..7c5afd3451ab 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -6,7 +6,6 @@ from . import locations from .bundles.bundle_room import BundleRoom from .data.craftable_data import all_crafting_recipes_by_name -from .data.monster_data import all_monsters_by_category, all_monsters_by_name from .data.museum_data import all_museum_items, dwarf_scrolls, skeleton_front, skeleton_middle, skeleton_back, all_museum_items_by_name, all_museum_minerals, \ all_museum_artifacts, Artifact from .data.recipe_data import all_cooking_recipes_by_name @@ -635,21 +634,20 @@ def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - monsters_by_name = all_monsters_by_name(world_options.mods.value) - for monster_name in monsters_by_name: + for monster_name in logic.monster.all_monsters_by_name: location_name = f"{monster_eradication_prefix}{monster_name}" if location_name not in all_location_names: continue location = multiworld.get_location(location_name, player) if world_options.monstersanity == Monstersanity.option_split_goals: - rule = logic.monster.can_kill_many(monsters_by_name[monster_name]) + rule = logic.monster.can_kill_many(logic.monster.all_monsters_by_name[monster_name]) else: - rule = logic.monster.can_kill(monsters_by_name[monster_name]) + rule = logic.monster.can_kill(logic.monster.all_monsters_by_name[monster_name]) MultiWorldRules.set_rule(location, rule) def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - for monster_category in all_monsters_by_category(world_options.mods.value): + for monster_category in logic.monster.all_monsters_by_category: set_monstersanity_progressive_single_category_rules(all_location_names, logic, multiworld, player, monster_category, world_options) @@ -668,12 +666,11 @@ def set_monstersanity_progressive_category_rule(all_location_names: List[str], l monster_category: str, location_name: str, world_options: StardewValleyOptions, goal_index): if location_name not in all_location_names: return - monsters_by_category = all_monsters_by_category(world_options.mods.value) location = multiworld.get_location(location_name, player) if goal_index < 3: - rule = logic.monster.can_kill_any(monsters_by_category[monster_category], goal_index + 1) + rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category], goal_index + 1) else: - rule = logic.monster.can_kill_all(monsters_by_category[monster_category], goal_index * 2) + rule = logic.monster.can_kill_all(logic.monster.all_monsters_by_category[monster_category], goal_index * 2) MultiWorldRules.set_rule(location, rule) @@ -686,16 +683,15 @@ def get_monster_eradication_number(location_name, monster_category) -> int: def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - monsters_by_category = all_monsters_by_category(world_options.mods.value) - for monster_category in monsters_by_category: + for monster_category in logic.monster.all_monsters_by_category: location_name = f"{monster_eradication_prefix}{monster_category}" if location_name not in all_location_names: continue location = multiworld.get_location(location_name, player) if world_options.monstersanity == Monstersanity.option_one_per_category: - rule = logic.monster.can_kill_any(monsters_by_category[monster_category]) + rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category]) else: - rule = logic.monster.can_kill_all(monsters_by_category[monster_category], 4) + rule = logic.monster.can_kill_all(logic.monster.all_monsters_by_category[monster_category], 4) MultiWorldRules.set_rule(location, rule) From 45c04d85bbb674fdc324fdaed306a711852aa5e9 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 14 Jan 2024 19:09:41 -0600 Subject: [PATCH 431/482] Add gunther bedroom --- worlds/stardew_valley/mods/mod_regions.py | 3 +++ worlds/stardew_valley/rules.py | 2 ++ worlds/stardew_valley/strings/region_names.py | 1 + 3 files changed, 6 insertions(+) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index ee9559c5cd0e..2f92680a0122 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -165,6 +165,8 @@ RegionData(SVERegion.jenkins_cellar), RegionData(SVERegion.unclaimed_plot, [SVEEntrance.plot_to_bridge]), RegionData(SVERegion.shearwater), + RegionData(Region.museum, [SVEEntrance.museum_to_gunther_bedroom]), + RegionData(SVERegion.gunther_bedroom), RegionData(Region.fish_shop, [SVEEntrance.fish_shop_to_willy_bedroom]), RegionData(SVERegion.willy_bedroom), RegionData(Region.mountain, [SVEEntrance.mountain_to_guild_summit]), @@ -270,6 +272,7 @@ ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.fish_shop_to_willy_bedroom, SVERegion.willy_bedroom, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.museum_to_gunther_bedroom, SVERegion.gunther_bedroom, flag=RandomizationFlag.BUILDINGS), ] alecto_regions = [ diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 7c5afd3451ab..80e8da62c3a0 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -929,6 +929,8 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl (logic.mod.sve.can_buy_bear_recipe())) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.railroad_to_grampleton_station, player), logic.received(SVEQuestItem.scarlett_job_offer)) + MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.museum_to_gunther_bedroom, player), + logic.relationship.has_hearts(ModNPC.gunther, 2)) logic.mod.sve.initialize_rules() for location in logic.registry.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 84ae358f414d..9e165ee56c77 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -272,6 +272,7 @@ class SVERegion: first_slash_spare_room = "First Slash Spare Room" sprite_spring_cave = "Sprite Spring Cave" willy_bedroom = "Willy's Bedroom" + gunther_bedroom = "Gunther's Bedroom" class AlectoRegion: From d0c2f48948de82c42c4c81aac707fb77e877d9ef Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 14 Jan 2024 19:27:57 -0600 Subject: [PATCH 432/482] Fix Fancy Blanket logic --- worlds/stardew_valley/mods/logic/quests_logic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index c00bebc6df83..9d873aa1cc4d 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -103,6 +103,7 @@ def _get_distant_lands_quest_rules(self): self.logic.region.can_reach(Region.blacksmith) & self.logic.has(MetalBar.iron) & self.logic.relationship.has_hearts(ModNPC.goblin, 6), ModQuest.FancyBlanketTask: self.logic.region.can_reach(Region.haley_house) & self.logic.has(AnimalProduct.wool) & - self.logic.has(ArtisanGood.cloth) & self.logic.relationship.has_hearts(ModNPC.goblin, 10) + self.logic.has(ArtisanGood.cloth) & self.logic.relationship.has_hearts(ModNPC.goblin, 10) & + self.logic.relationship.has_hearts(NPC.emily, 8) & self.logic.season.has(Season.winter) } From 3250e98881f8e2341b46a12626932d51e3fc4da7 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 16 Jan 2024 17:26:46 -0600 Subject: [PATCH 433/482] Add Jasper special orders. --- worlds/stardew_valley/data/locations.csv | 2 ++ .../stardew_valley/mods/logic/special_orders_logic.py | 10 +++++++++- worlds/stardew_valley/strings/special_order_names.py | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index f9cb203a5dc5..76871440895f 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2565,6 +2565,8 @@ id,region,name,tags,mod_name 7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul 7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul 7523,Boarding House - First Floor,Pumpkin Soup,"MANDATORY,STORY_QUEST",Boarding House and Bus Stop Extension +7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas +7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas 7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index 6ee61f6e4fb4..082ae9719786 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -19,7 +19,7 @@ from ...strings.food_names import Meal from ...strings.geode_names import Geode from ...strings.material_names import Material -from ...strings.metal_names import MetalBar +from ...strings.metal_names import MetalBar, Artifact from ...strings.monster_drop_names import Loot from ...strings.region_names import Region, SVERegion from ...strings.special_order_names import SpecialOrder, ModSpecialOrder @@ -63,4 +63,12 @@ def get_modded_special_orders_rules(self): self.logic.region.can_reach(SVERegion.susans_house) # quest requires you make the fertilizer }) + if ModNames.jasper in self.options.mods: + special_orders.update({ + ModSpecialOrder.dwarf_scroll: self.logic.has_all(*(Artifact.dwarf_scroll_i, Artifact.dwarf_scroll_ii, Artifact.dwarf_scroll_iii, + Artifact.dwarf_scroll_iv,)), + ModSpecialOrder.geode_order: self.logic.has_all(*(Geode.geode, Geode.frozen, Geode.magma, Geode.omni,)) & + self.logic.relationship.has_hearts(ModNPC.jasper, 8) + }) + return special_orders diff --git a/worlds/stardew_valley/strings/special_order_names.py b/worlds/stardew_valley/strings/special_order_names.py index 76cd9634e3d8..9802c01532c1 100644 --- a/worlds/stardew_valley/strings/special_order_names.py +++ b/worlds/stardew_valley/strings/special_order_names.py @@ -36,3 +36,5 @@ class ModSpecialOrder: an_elegant_reception = "An Elegant Reception" fairy_garden = "Fairy Garden" homemade_fertilizer = "Homemade Fertilizer" + geode_order = "Geode Order" + dwarf_scroll = "Dwarven Scrolls" From c76dc534fe6a79bf1dc33da7dc53981634abba11 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 19:12:06 -0600 Subject: [PATCH 434/482] Remove Resource Pack from 1 item filler --- worlds/stardew_valley/data/items.csv | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 33a9ff114e2b..bfc183996b34 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -837,10 +837,10 @@ id,name,classification,groups,mod_name 10707,Resource Pack: 5 Wooden Display,filler,RESOURCE_PACK,Archaeology 10708,Grinder,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology 10709,Ancient Battery Production Station,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10710,Resource Pack: Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded -10711,Resource Pack: Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10712,Resource Pack: Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10713,Resource Pack: Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10714,Resource Pack: Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10715,Resource Pack: Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10716,Resource Pack: Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10710,Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded +10711,Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10712,Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10713,Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10714,Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10715,Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10716,Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded From 57af35a3a1dda4923d3d7bfe0a6d438eb72db44e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 19:15:41 -0600 Subject: [PATCH 435/482] remove dupes --- worlds/stardew_valley/data/monster_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index b78bb1314229..9be3a3bc0ce2 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -50,7 +50,7 @@ def create_monster(name: str, category: str, locations: Tuple[str, ...], difficu def update_monster_locations(mod_name: str, monster: StardewMonster): new_locations = modded_monsters_locations[mod_name][monster.name] - total_locations = monster.locations + new_locations + total_locations = tuple(set(monster.locations + new_locations)) return StardewMonster(monster.name, monster.category, total_locations, monster.difficulty) From 4295507c86a593cefae8fa0ff273fe0510afec8f Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 20:14:39 -0600 Subject: [PATCH 436/482] rely more on get_villagers_by_mod --- worlds/stardew_valley/data/villagers_data.py | 8 +++---- .../logic/relationship_logic.py | 22 ++++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 0a8b1089222d..53582f69fb4e 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -3,7 +3,7 @@ from ..strings.food_names import Beverage from ..strings.region_names import Region, SVERegion, AlectoRegion -from ..mods.mod_data import ModNames, mods_with_multiple_villager_sources +from ..mods.mod_data import ModNames from ..strings.generic_names import Generic from ..strings.season_names import Season from ..strings.villager_names import NPC, ModNPC @@ -462,6 +462,8 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu def villager_included_for_any_mod(npc: Villager, mods: Set[str]): + if not npc.mod_name: + return False for mod in npc.mod_name.split(","): if mod in mods: return True @@ -471,9 +473,7 @@ def villager_included_for_any_mod(npc: Villager, mods: Set[str]): def get_villagers_for_mods(mods: Set[str]) -> List[Villager]: villagers_for_current_mods = [] for npc in all_villagers: - if npc.mod_name in mods_with_multiple_villager_sources and not villager_included_for_any_mod(npc, mods): - continue - elif npc.mod_name not in mods_with_multiple_villager_sources and npc.mod_name and npc.mod_name not in mods: + if not villager_included_for_any_mod(npc, mods) and npc.mod_name: continue modified_npc = npc for active_mod in mods: diff --git a/worlds/stardew_valley/logic/relationship_logic.py b/worlds/stardew_valley/logic/relationship_logic.py index 53deb5e9a2d8..fb0267bddb1a 100644 --- a/worlds/stardew_valley/logic/relationship_logic.py +++ b/worlds/stardew_valley/logic/relationship_logic.py @@ -1,5 +1,6 @@ import math -from typing import Union +from functools import cached_property +from typing import Union, List from Utils import cache_self1 from .base_logic import BaseLogic, BaseLogicMixin @@ -10,10 +11,9 @@ from .region_logic import RegionLogicMixin from .season_logic import SeasonLogicMixin from .time_logic import TimeLogicMixin -from ..data.villagers_data import all_villagers_by_name, Villager -from ..mods.mod_data import mods_with_multiple_villager_sources +from ..data.villagers_data import all_villagers_by_name, Villager, get_villagers_for_mods from ..options import Friendsanity -from ..stardew_rule import StardewRule, True_, False_, And, Or, Count +from ..stardew_rule import StardewRule, True_, And, Or from ..strings.ap_names.mods.mod_items import SVEQuestItem from ..strings.crop_names import Fruit from ..strings.generic_names import Generic @@ -41,6 +41,10 @@ def __init__(self, *args, **kwargs): class RelationshipLogic(BaseLogic[Union[ RelationshipLogicMixin, BuildingLogicMixin, SeasonLogicMixin, TimeLogicMixin, GiftLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]): + @cached_property + def all_villagers_given_mods(self) -> List[Villager]: + return get_villagers_for_mods(self.options.mods.value) + def can_date(self, npc: str) -> StardewRule: return self.logic.relationship.has_hearts(npc, 8) & self.logic.has(Gift.bouquet) @@ -178,12 +182,4 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule: @cache_self1 def npc_is_in_current_slot(self, name: str) -> bool: npc = all_villagers_by_name[name] - mod = npc.mod_name - if mod not in mods_with_multiple_villager_sources: - mod_rule_if_exists = mod in self.options.mods - else: - sources = mod.split(",") - mod_rule_if_exists = False_() - for single_mod in sources: - mod_rule_if_exists = mod_rule_if_exists | (single_mod in self.options.mods) - return not mod or mod_rule_if_exists + return npc in self.all_villagers_given_mods From d7a2acf2cb3e6b29125c49a2d8c0e8325014c6e2 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 20:14:56 -0600 Subject: [PATCH 437/482] use isinstance, rename --- worlds/stardew_valley/logic/tool_logic.py | 4 ++-- worlds/stardew_valley/mods/logic/item_logic.py | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index 0ae6a67f5086..c7bb50c1b7dd 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -65,9 +65,9 @@ def has_fishing_rod(self, level: int) -> StardewRule: # Should be cached def can_forage(self, season: str | Iterable[str], region: str = Region.forest, need_hoe: bool = False) -> StardewRule: season_rule = False_() - if type(season) is str: + if isinstance(season, str): season_rule = self.logic.season.has(season) - if type(season) is Iterable[str]: + elif isinstance(season, Iterable): season_rule = self.logic.season.has_any(season) region_rule = self.logic.region.can_reach(region) if need_hoe: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index a8ddeaa10590..fc7d978245b3 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -64,9 +64,9 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: def append_vanilla_item_rules(self, item_rule: Dict[str, StardewRule]): if ModNames.sve in self.options.mods: - item_rule.update(self.append_vanilla_item_rules_for_sve(item_rule)) + item_rule.update(self.get_modified_item_rules_for_sve(item_rule)) if ModNames.deepwoods in self.options.mods: - item_rule.update(self.append_vanilla_item_rules_for_deep_woods(item_rule)) + item_rule.update(self.get_modified_item_rules_for_deep_woods(item_rule)) return item_rule def get_sve_item_rules(self): @@ -125,7 +125,7 @@ def get_sve_item_rules(self): } # @formatter:on - def append_vanilla_item_rules_for_sve(self, items: Dict[str, StardewRule]): + def get_modified_item_rules_for_sve(self, items: Dict[str, StardewRule]): return { Loot.void_essence: items[Loot.void_essence] | self.logic.region.can_reach(SVERegion.highlands_cavern) | self.logic.region.can_reach( SVERegion.crimson_badlands), @@ -158,7 +158,7 @@ def append_vanilla_item_rules_for_sve(self, items: Dict[str, StardewRule]): self.logic.combat.can_fight_at_level(Performance.maximum)), } - def append_vanilla_item_rules_for_deep_woods(self, items: Dict[str, StardewRule]): + def get_modified_item_rules_for_deep_woods(self, items: Dict[str, StardewRule]): return { Fruit.apple: items[Fruit.apple] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), # Deep enough to have seen such a tree at least once Fruit.apricot: items[Fruit.apricot] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), @@ -191,8 +191,7 @@ def get_archaeology_item_rules(self): display_item_rule = self.logic.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.logic.has(item) if "Wooden" in display_type: archaeology_item_rules[location_name] = display_item_rule & preservation_chamber_rule - else: - archaeology_item_rules[location_name] = display_item_rule & hardwood_preservation_chamber_rule + archaeology_item_rules[location_name] = display_item_rule & hardwood_preservation_chamber_rule return archaeology_item_rules def get_distant_lands_item_rules(self): From 68d716cd9d64f3693fa08b3eef45f0d9f28dfac2 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 20:18:50 -0600 Subject: [PATCH 438/482] Remove else --- worlds/stardew_valley/mods/logic/skills_logic.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index 28d1f2de98a0..aecd89f96520 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -94,8 +94,7 @@ def can_earn_archaeology_skill_level(self, level: int) -> StardewRule: return (self.logic.action.can_pan() & self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iron)) & shifter_rule if level >= 3: return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.copper) - else: - return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic) + return self.logic.action.can_pan() | self.logic.tool.has_tool(Tool.hoe, ToolMaterial.basic) def can_earn_cooking_skill_level(self, level: int) -> StardewRule: if level >= 6: From f353b1b7709e910f882baed05a126686bebfc3ea Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 20:21:47 -0600 Subject: [PATCH 439/482] Remove needless set --- worlds/stardew_valley/mods/mod_data.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index 5eef460e5b6c..5fe0a54f9840 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -28,9 +28,6 @@ class ModNames: jasper_sve = jasper + "," + sve -mods_with_multiple_villager_sources = [ModNames.jasper_sve] - - all_mods = frozenset({ModNames.deepwoods, ModNames.tractor, ModNames.big_backpack, ModNames.luck_skill, ModNames.magic, ModNames.socializing_skill, ModNames.archaeology, ModNames.cooking_skill, ModNames.binning_skill, ModNames.juna, From 8bfd6d470a914ff1d8fe3e222e31b51ffa97b7fd Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 21 Jan 2024 20:50:12 -0600 Subject: [PATCH 440/482] Remove world_options plus renaming --- worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/mods/logic/deepwoods_logic.py | 4 ++-- worlds/stardew_valley/mods/logic/item_logic.py | 2 +- worlds/stardew_valley/mods/logic/skills_logic.py | 2 +- worlds/stardew_valley/rules.py | 10 +++++----- .../stardew_valley/strings/ap_names/mods/mod_items.py | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index df1bb2645dc5..f61f13c5659c 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -403,7 +403,7 @@ def __init__(self, player: int, options: StardewValleyOptions): self.registry.item_rules.update(self.registry.crop_rules) self.registry.item_rules.update(self.mod.item.get_modded_item_rules()) - self.mod.item.append_vanilla_item_rules(self.registry.item_rules) # New regions and content means new ways to obtain old items + self.mod.item.modify_vanilla_item_rules_with_mod_additions(self.registry.item_rules) # New regions and content means new ways to obtain old items # For some recipes, the cooked item can be obtained directly, so we either cook it or get it for recipe in self.registry.cooking_rules: diff --git a/worlds/stardew_valley/mods/logic/deepwoods_logic.py b/worlds/stardew_valley/mods/logic/deepwoods_logic.py index 086231997f45..39531ffb3d7d 100644 --- a/worlds/stardew_valley/mods/logic/deepwoods_logic.py +++ b/worlds/stardew_valley/mods/logic/deepwoods_logic.py @@ -11,7 +11,7 @@ from ...options import SkillProgression, ElevatorProgression from ...stardew_rule import StardewRule, True_, And from ...strings.ap_names.transport_names import ModTransportation -from ...strings.ap_names.mods.mod_items import DeepWoodsItem, SkillItem +from ...strings.ap_names.mods.mod_items import DeepWoodsItem, SkillLevel from ...strings.craftable_names import Bomb from ...strings.food_names import Meal from ...strings.performance_names import Performance @@ -58,7 +58,7 @@ def can_pull_sword(self) -> StardewRule: self.logic.received(DeepWoodsItem.pendant_elder), self.logic.skill.has_total_level(40)] if ModNames.luck_skill in self.options.mods: - rules.append(self.logic.received(SkillItem.luck_skill, 7)) + rules.append(self.logic.received(SkillLevel.luck, 7)) else: rules.append(self.logic.has(Meal.magic_rock_candy)) # You need more luck than this, but it'll push the logic down a ways; you can get the rest there. return And(*rules) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index fc7d978245b3..728331b63bc4 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -62,7 +62,7 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: items.update(self.get_distant_lands_item_rules()) return items - def append_vanilla_item_rules(self, item_rule: Dict[str, StardewRule]): + def modify_vanilla_item_rules_with_mod_additions(self, item_rule: Dict[str, StardewRule]): if ModNames.sve in self.options.mods: item_rule.update(self.get_modified_item_rules_for_sve(item_rule)) if ModNames.deepwoods in self.options.mods: diff --git a/worlds/stardew_valley/mods/logic/skills_logic.py b/worlds/stardew_valley/mods/logic/skills_logic.py index aecd89f96520..ce8bebbffef5 100644 --- a/worlds/stardew_valley/mods/logic/skills_logic.py +++ b/worlds/stardew_valley/mods/logic/skills_logic.py @@ -15,7 +15,7 @@ from ...mods.mod_data import ModNames from ...options import SkillProgression from ...stardew_rule import StardewRule, False_, True_ -from ...strings.ap_names.mods.mod_items import SkillItem +from ...strings.ap_names.mods.mod_items import SkillLevel from ...strings.craftable_names import ModCraftable, ModMachine from ...strings.building_names import Building from ...strings.geode_names import Geode diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 80e8da62c3a0..a8b932da96a3 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -630,7 +630,7 @@ def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, set_monstersanity_progressive_category_rules(all_location_names, logic, multiworld, player, world_options) return - set_monstersanity_category_rules(all_location_names, logic, multiworld, player, world_options) + set_monstersanity_category_rules(all_location_names, logic, multiworld, player, monstersanity_option) def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): @@ -659,11 +659,11 @@ def set_monstersanity_progressive_single_category_rules(all_location_names: List location_names = sorted(location_names, key=lambda name: get_monster_eradication_number(name, monster_category)) for i in range(5): location_name = location_names[i] - set_monstersanity_progressive_category_rule(all_location_names, logic, multiworld, player, monster_category, location_name, world_options, i) + set_monstersanity_progressive_category_rule(all_location_names, logic, multiworld, player, monster_category, location_name, i) def set_monstersanity_progressive_category_rule(all_location_names: List[str], logic: StardewLogic, multiworld, player, - monster_category: str, location_name: str, world_options: StardewValleyOptions, goal_index): + monster_category: str, location_name: str, goal_index): if location_name not in all_location_names: return location = multiworld.get_location(location_name, player) @@ -682,13 +682,13 @@ def get_monster_eradication_number(location_name, monster_category) -> int: return 1000 -def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): +def set_monstersanity_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monstersanity_option): for monster_category in logic.monster.all_monsters_by_category: location_name = f"{monster_eradication_prefix}{monster_category}" if location_name not in all_location_names: continue location = multiworld.get_location(location_name, player) - if world_options.monstersanity == Monstersanity.option_one_per_category: + if monstersanity_option == Monstersanity.option_one_per_category: rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category]) else: rule = logic.monster.can_kill_all(logic.monster.all_monsters_by_category[monster_category], 4) diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 6c27f7e63109..2b4423a384af 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -8,9 +8,9 @@ class DeepWoodsItem: obelisk_sigil = "Progressive Woods Obelisk Sigils" -class SkillItem: - luck_skill = "Luck Level" - archaeology_level = "Archaeology Level" +class SkillLevel: + luck = "Luck Level" + archaeology = "Archaeology Level" class SVEQuestItem: From 38fc5668b6d6dbd14ab4a566a3e4b659571fae12 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 15:26:14 -0600 Subject: [PATCH 441/482] Remove more world_options and fix data --- worlds/stardew_valley/data/villagers_data.py | 4 ++-- worlds/stardew_valley/mods/logic/item_logic.py | 3 ++- worlds/stardew_valley/rules.py | 15 +++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 53582f69fb4e..b1775fc079d8 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -463,7 +463,7 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu def villager_included_for_any_mod(npc: Villager, mods: Set[str]): if not npc.mod_name: - return False + return True for mod in npc.mod_name.split(","): if mod in mods: return True @@ -473,7 +473,7 @@ def villager_included_for_any_mod(npc: Villager, mods: Set[str]): def get_villagers_for_mods(mods: Set[str]) -> List[Villager]: villagers_for_current_mods = [] for npc in all_villagers: - if not villager_included_for_any_mod(npc, mods) and npc.mod_name: + if not villager_included_for_any_mod(npc, mods): continue modified_npc = npc for active_mod in mods: diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 728331b63bc4..3f3f9b5ca57c 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -191,7 +191,8 @@ def get_archaeology_item_rules(self): display_item_rule = self.logic.crafting.can_craft(all_crafting_recipes_by_name[display_type]) & self.logic.has(item) if "Wooden" in display_type: archaeology_item_rules[location_name] = display_item_rule & preservation_chamber_rule - archaeology_item_rules[location_name] = display_item_rule & hardwood_preservation_chamber_rule + else: + archaeology_item_rules[location_name] = display_item_rule & hardwood_preservation_chamber_rule return archaeology_item_rules def get_distant_lands_item_rules(self): diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index a8b932da96a3..74aedcd25258 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -623,36 +623,35 @@ def set_monstersanity_rules(all_location_names: List[str], logic: StardewLogic, return if monstersanity_option == Monstersanity.option_one_per_monster or monstersanity_option == Monstersanity.option_split_goals: - set_monstersanity_monster_rules(all_location_names, logic, multiworld, player, world_options) + set_monstersanity_monster_rules(all_location_names, logic, multiworld, player, monstersanity_option) return if monstersanity_option == Monstersanity.option_progressive_goals: - set_monstersanity_progressive_category_rules(all_location_names, logic, multiworld, player, world_options) + set_monstersanity_progressive_category_rules(all_location_names, logic, multiworld, player) return set_monstersanity_category_rules(all_location_names, logic, multiworld, player, monstersanity_option) -def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): +def set_monstersanity_monster_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monstersanity_option): for monster_name in logic.monster.all_monsters_by_name: location_name = f"{monster_eradication_prefix}{monster_name}" if location_name not in all_location_names: continue location = multiworld.get_location(location_name, player) - if world_options.monstersanity == Monstersanity.option_split_goals: + if monstersanity_option == Monstersanity.option_split_goals: rule = logic.monster.can_kill_many(logic.monster.all_monsters_by_name[monster_name]) else: rule = logic.monster.can_kill(logic.monster.all_monsters_by_name[monster_name]) MultiWorldRules.set_rule(location, rule) -def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): +def set_monstersanity_progressive_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player): for monster_category in logic.monster.all_monsters_by_category: - set_monstersanity_progressive_single_category_rules(all_location_names, logic, multiworld, player, monster_category, world_options) + set_monstersanity_progressive_single_category_rules(all_location_names, logic, multiworld, player, monster_category) -def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monster_category: str, - world_options: StardewValleyOptions): +def set_monstersanity_progressive_single_category_rules(all_location_names: List[str], logic: StardewLogic, multiworld, player, monster_category: str): location_names = [name for name in all_location_names if name.startswith(monster_eradication_prefix) and name.endswith(monster_category)] if not location_names: return From cce27d4359216a6aba9ce636942c6f5bc627be17 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Mon, 22 Jan 2024 16:55:28 -0500 Subject: [PATCH 442/482] - Fix Python 3.8 problem --- worlds/stardew_valley/logic/tool_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index c7bb50c1b7dd..def02b35dab6 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -63,7 +63,7 @@ def has_fishing_rod(self, level: int) -> StardewRule: return self.logic.money.can_spend_at(Region.fish_shop, prices[level]) # Should be cached - def can_forage(self, season: str | Iterable[str], region: str = Region.forest, need_hoe: bool = False) -> StardewRule: + def can_forage(self, season: Union[str, Iterable[str]], region: str = Region.forest, need_hoe: bool = False) -> StardewRule: season_rule = False_() if isinstance(season, str): season_rule = self.logic.season.has(season) From 036c16b71aeb2ee309039b308c8ad6237a3186fc Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 21 Dec 2023 22:52:09 -0600 Subject: [PATCH 443/482] Add Hat Mouse Lacey --- worlds/stardew_valley/data/items.csv | 1 + worlds/stardew_valley/data/locations.csv | 14 ++++++++++++++ worlds/stardew_valley/data/villagers_data.py | 4 ++++ worlds/stardew_valley/mods/mod_data.py | 3 ++- worlds/stardew_valley/mods/mod_regions.py | 14 ++++++++++++-- worlds/stardew_valley/options.py | 2 +- worlds/stardew_valley/strings/entrance_names.py | 4 ++++ worlds/stardew_valley/strings/region_names.py | 4 ++++ worlds/stardew_valley/strings/villager_names.py | 1 + 9 files changed, 43 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index bfc183996b34..e53b8cfb46d5 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -784,6 +784,7 @@ id,name,classification,groups,mod_name 10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded 10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch 10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +10128,Lacey <3,progression,FRIENDSANITY,Hat Mouse Lacey 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator 10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 76871440895f..82ccfa2ad5f0 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2491,6 +2491,20 @@ id,region,name,tags,mod_name 6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch 6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch 6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch +6323,Mouse House,Friendsanity: Lacey 1 <3,FRIENDSANITY,Hat Mouse Lacey +6324,Mouse House,Friendsanity: Lacey 2 <3,FRIENDSANITY,Hat Mouse Lacey +6325,Mouse House,Friendsanity: Lacey 3 <3,FRIENDSANITY,Hat Mouse Lacey +6326,Mouse House,Friendsanity: Lacey 4 <3,FRIENDSANITY,Hat Mouse Lacey +6327,Mouse House,Friendsanity: Lacey 5 <3,FRIENDSANITY,Hat Mouse Lacey +6328,Mouse House,Friendsanity: Lacey 6 <3,FRIENDSANITY,Hat Mouse Lacey +6329,Mouse House,Friendsanity: Lacey 7 <3,FRIENDSANITY,Hat Mouse Lacey +6330,Mouse House,Friendsanity: Lacey 8 <3,FRIENDSANITY,Hat Mouse Lacey +6331,Mouse House,Friendsanity: Lacey 9 <3,FRIENDSANITY,Hat Mouse Lacey +6332,Mouse House,Friendsanity: Lacey 10 <3,FRIENDSANITY,Hat Mouse Lacey +6333,Mouse House,Friendsanity: Lacey 11 <3,FRIENDSANITY,Hat Mouse Lacey +6334,Mouse House,Friendsanity: Lacey 12 <3,FRIENDSANITY,Hat Mouse Lacey +6335,Mouse House,Friendsanity: Lacey 13 <3,FRIENDSANITY,Hat Mouse Lacey +6336,Mouse House,Friendsanity: Lacey 14 <3,FRIENDSANITY,Hat Mouse Lacey 7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack 7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod 7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index b1775fc079d8..afaba30b993f 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -58,6 +58,9 @@ def __repr__(self): witch_swamp = (Region.witch_swamp,) witch_attic = (AlectoRegion.witch_attic,) +# Hat Mouse +hat_house = (LaceyRegion.hat_house,) + golden_pumpkin = ("Golden Pumpkin",) # magic_rock_candy = ("Magic Rock Candy",) pearl = ("Pearl",) @@ -424,6 +427,7 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley) zic = villager(ModNPC.goblin, False, witch_swamp, Season.fall, void_mayonnaise, False, ModNames.distant_lands) alecto = villager(ModNPC.alecto, False, witch_attic, Generic.any, universal_loves, False, ModNames.alecto) +lacey = villager(ModNPC.lacey, True, hat_house, Season.spring, universal_loves, True, ModNames.lacey) # SVE Villagers claire = villager(ModNPC.claire, True, town + jojamart, Season.fall, universal_loves + claire_loves, True, ModNames.sve) diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index 5fe0a54f9840..bfa67d460790 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -24,6 +24,7 @@ class ModNames: sve = "Stardew Valley Expanded" alecto = "Alecto the Witch" distant_lands = "Distant Lands - Witch Swamp Overhaul" + lacey = "Hat Mouse Lacey" jasper_sve = jasper + "," + sve @@ -34,4 +35,4 @@ class ModNames: ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.alecto, - ModNames.distant_lands}) + ModNames.distant_lands, ModNames.lacey}) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 2f92680a0122..98c0e5f00389 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -1,7 +1,7 @@ -from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, \ +from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, LaceyEntrance, \ JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance, AlectoEntrance from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, \ - AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion, AlectoRegion + AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion, AlectoRegion, LaceyRegion from ..region_classes import RegionData, ConnectionData, ModificationFlag, RandomizationFlag, ModRegionData from .mod_data import ModNames @@ -284,6 +284,15 @@ ConnectionData(AlectoEntrance.witch_hut_to_witch_attic, AlectoRegion.witch_attic, flag=RandomizationFlag.BUILDINGS) ] +lacey_regions = [ + RegionData(Region.forest, [LaceyEntrance.forest_to_hat_house]), + RegionData(LaceyRegion.hat_house) +] + +lacey_entrances = [ + ConnectionData(LaceyEntrance.forest_to_hat_house, LaceyRegion.hat_house, flag=RandomizationFlag.BUILDINGS) +] + vanilla_connections_to_remove_by_mod = { ModNames.sve: [ConnectionData(Entrance.mountain_to_the_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), @@ -304,4 +313,5 @@ ModNames.riley: ModRegionData(ModNames.riley, riley_regions, riley_entrances), ModNames.sve: ModRegionData(ModNames.sve, stardew_valley_expanded_regions, mandatory_sve_connections), ModNames.alecto: ModRegionData(ModNames.alecto, alecto_regions, alecto_entrances), + ModNames.lacey: ModRegionData(ModNames.lacey, lacey_regions, lacey_entrances), } diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 147eab059702..8174c1de087f 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -686,7 +686,7 @@ class Mods(OptionSet): ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.distant_lands, - ModNames.alecto + ModNames.alecto, ModNames.lacey } diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 8970569f69ae..321e034f2e81 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -331,3 +331,7 @@ class SVEEntrance: class AlectoEntrance: witch_hut_to_witch_attic = "Witch's Hut to Witch's Attic" + +class LaceyEntrance: + forest_to_hat_house = "Forest to Mouse House" + diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 9e165ee56c77..6ad05c55391f 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -277,3 +277,7 @@ class SVERegion: class AlectoRegion: witch_attic = "Witch's Attic" + + +class LaceyRegion: + hat_house = "Mouse House" diff --git a/worlds/stardew_valley/strings/villager_names.py b/worlds/stardew_valley/strings/villager_names.py index b4b363c20942..a97e7110dfd8 100644 --- a/worlds/stardew_valley/strings/villager_names.py +++ b/worlds/stardew_valley/strings/villager_names.py @@ -63,3 +63,4 @@ class ModNPC: susan = "Susan" alecto = "Alecto" goblin = "Zic" + lacey = "Lacey" From e3b79a7b1c5f712167831437b65fb502fcbf808e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Fri, 22 Dec 2023 04:48:48 -0600 Subject: [PATCH 444/482] Boarding House Implementation --- worlds/stardew_valley/data/items.csv | 3 + worlds/stardew_valley/data/locations.csv | 45 ++++++++++++++ worlds/stardew_valley/data/villagers_data.py | 11 +++- worlds/stardew_valley/mods/mod_data.py | 3 +- worlds/stardew_valley/mods/mod_regions.py | 59 ++++++++++++++++++- worlds/stardew_valley/options.py | 2 +- worlds/stardew_valley/rules.py | 18 +++++- .../stardew_valley/strings/entrance_names.py | 21 +++++++ worlds/stardew_valley/strings/region_names.py | 22 +++++++ .../stardew_valley/strings/villager_names.py | 3 + 10 files changed, 179 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index e53b8cfb46d5..2c69ed2e8617 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -785,6 +785,9 @@ id,name,classification,groups,mod_name 10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch 10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul 10128,Lacey <3,progression,FRIENDSANITY,Hat Mouse Lacey +10129,Gregory <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10130,Sheila <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10131,Joel <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension 10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods 10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator 10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 82ccfa2ad5f0..c34656cf2e25 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2505,6 +2505,44 @@ id,region,name,tags,mod_name 6334,Mouse House,Friendsanity: Lacey 12 <3,FRIENDSANITY,Hat Mouse Lacey 6335,Mouse House,Friendsanity: Lacey 13 <3,FRIENDSANITY,Hat Mouse Lacey 6336,Mouse House,Friendsanity: Lacey 14 <3,FRIENDSANITY,Hat Mouse Lacey +6337,Boarding House - First Floor,Friendsanity: Joel 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6338,Boarding House - First Floor,Friendsanity: Joel 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6339,Boarding House - First Floor,Friendsanity: Joel 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6340,Boarding House - First Floor,Friendsanity: Joel 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6341,Boarding House - First Floor,Friendsanity: Joel 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6342,Boarding House - First Floor,Friendsanity: Joel 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6343,Boarding House - First Floor,Friendsanity: Joel 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6344,Boarding House - First Floor,Friendsanity: Joel 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6345,Boarding House - First Floor,Friendsanity: Joel 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6346,Boarding House - First Floor,Friendsanity: Joel 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6347,Boarding House - First Floor,Friendsanity: Sheila 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6348,Boarding House - First Floor,Friendsanity: Sheila 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6349,Boarding House - First Floor,Friendsanity: Sheila 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6350,Boarding House - First Floor,Friendsanity: Sheila 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6351,Boarding House - First Floor,Friendsanity: Sheila 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6352,Boarding House - First Floor,Friendsanity: Sheila 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6353,Boarding House - First Floor,Friendsanity: Sheila 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6354,Boarding House - First Floor,Friendsanity: Sheila 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6355,Boarding House - First Floor,Friendsanity: Sheila 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6356,Boarding House - First Floor,Friendsanity: Sheila 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6357,Boarding House - First Floor,Friendsanity: Sheila 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6358,Boarding House - First Floor,Friendsanity: Sheila 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6359,Boarding House - First Floor,Friendsanity: Sheila 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6360,Boarding House - First Floor,Friendsanity: Sheila 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6361,The Lost Valley,Friendsanity: Gregory 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6362,The Lost Valley,Friendsanity: Gregory 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6363,The Lost Valley,Friendsanity: Gregory 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6364,The Lost Valley,Friendsanity: Gregory 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6365,The Lost Valley,Friendsanity: Gregory 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6366,The Lost Valley,Friendsanity: Gregory 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6367,The Lost Valley,Friendsanity: Gregory 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6368,The Lost Valley,Friendsanity: Gregory 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6369,The Lost Valley,Friendsanity: Gregory 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6370,The Lost Valley,Friendsanity: Gregory 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6371,The Lost Valley,Friendsanity: Gregory 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6372,The Lost Valley,Friendsanity: Gregory 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6373,The Lost Valley,Friendsanity: Gregory 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6374,The Lost Valley,Friendsanity: Gregory 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension 7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack 7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod 7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods @@ -2533,6 +2571,13 @@ id,region,name,tags,mod_name 7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator 7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator 7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods +7051,Abandoned Mines - 1A,Abandoned Treasure - Floor 1A,MANDATORY,Boarding House and Bus Stop Extension +7052,Abandoned Mines - 1B,Abandoned Treasure - Floor 1B,MANDATORY,Boarding House and Bus Stop Extension +7053,Abandoned Mines - 2A,Abandoned Treasure - Floor 2A,MANDATORY,Boarding House and Bus Stop Extension +7054,Abandoned Mines - 2B,Abandoned Treasure - Floor 2B,MANDATORY,Boarding House and Bus Stop Extension +7055,Abandoned Mines - 3,Abandoned Treasure - Floor 3,MANDATORY,Boarding House and Bus Stop Extension +7056,Abandoned Mines - 4,Abandoned Treasure - Floor 4,MANDATORY,Boarding House and Bus Stop Extension +7057,Abandoned Mines - 5,Abandoned Treasure - Floor 5,MANDATORY,Boarding House and Bus Stop Extension 7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic 7402,Farm,Craft Travel Core,CRAFTSANITY,Magic 7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index afaba30b993f..06c659a03b77 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -54,12 +54,12 @@ def __repr__(self): railroad = (Region.railroad,) junimo = (SVERegion.junimo_woods,) -# Witch Swamp Overhaul Location +# Stray Locations witch_swamp = (Region.witch_swamp,) witch_attic = (AlectoRegion.witch_attic,) - -# Hat Mouse hat_house = (LaceyRegion.hat_house,) +the_lost_valley = (BoardingHouseRegion.the_lost_valley,) +boarding_house = (BoardingHouseRegion.boarding_house_first,) golden_pumpkin = ("Golden Pumpkin",) # magic_rock_candy = ("Magic Rock Candy",) @@ -429,6 +429,11 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu alecto = villager(ModNPC.alecto, False, witch_attic, Generic.any, universal_loves, False, ModNames.alecto) lacey = villager(ModNPC.lacey, True, hat_house, Season.spring, universal_loves, True, ModNames.lacey) +# Boarding House Villagers +gregory = villager(ModNPC.gregory, True, the_lost_valley, Season.fall, universal_loves, False, ModNames.boarding_house) +sheila = villager(ModNPC.sheila, True, boarding_house, Season.spring, universal_loves, True, ModNames.boarding_house) +joel = villager(ModNPC.joel, False, boarding_house, Season.winter, universal_loves, True, ModNames.boarding_house) + # SVE Villagers claire = villager(ModNPC.claire, True, town + jojamart, Season.fall, universal_loves + claire_loves, True, ModNames.sve) lance = villager(ModNPC.lance, True, adventurer + highlands + island, Season.spring, lance_loves, False, ModNames.sve) diff --git a/worlds/stardew_valley/mods/mod_data.py b/worlds/stardew_valley/mods/mod_data.py index bfa67d460790..a4d3b9828aa6 100644 --- a/worlds/stardew_valley/mods/mod_data.py +++ b/worlds/stardew_valley/mods/mod_data.py @@ -25,6 +25,7 @@ class ModNames: alecto = "Alecto the Witch" distant_lands = "Distant Lands - Witch Swamp Overhaul" lacey = "Hat Mouse Lacey" + boarding_house = "Boarding House and Bus Stop Extension" jasper_sve = jasper + "," + sve @@ -35,4 +36,4 @@ class ModNames: ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.alecto, - ModNames.distant_lands, ModNames.lacey}) + ModNames.distant_lands, ModNames.lacey, ModNames.boarding_house}) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 98c0e5f00389..5270fbb8f3fc 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -1,6 +1,6 @@ -from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, LaceyEntrance, \ +from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, LaceyEntrance, BoardingHouseEntrance, \ JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance, AlectoEntrance -from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, \ +from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, BoardingHouseRegion, \ AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion, AlectoRegion, LaceyRegion from ..region_classes import RegionData, ConnectionData, ModificationFlag, RandomizationFlag, ModRegionData from .mod_data import ModNames @@ -293,6 +293,60 @@ ConnectionData(LaceyEntrance.forest_to_hat_house, LaceyRegion.hat_house, flag=RandomizationFlag.BUILDINGS) ] +boarding_house_regions = [ + RegionData(Region.bus_stop, [BoardingHouseEntrance.bus_stop_to_boarding_house_plateau]), + RegionData(BoardingHouseRegion.boarding_house_plateau, [BoardingHouseEntrance.boarding_house_plateau_to_boarding_house_first, + BoardingHouseEntrance.boarding_house_plateau_to_buffalo_ranch, + BoardingHouseEntrance.boarding_house_plateau_to_abandoned_mines_entrance]), + RegionData(BoardingHouseRegion.boarding_house_first, [BoardingHouseEntrance.boarding_house_first_to_boarding_house_second]), + RegionData(BoardingHouseRegion.boarding_house_second), + RegionData(BoardingHouseRegion.buffalo_ranch), + RegionData(BoardingHouseRegion.abandoned_mines_entrance, [BoardingHouseEntrance.abandoned_mines_entrance_to_abandoned_mines_1a, + BoardingHouseEntrance.abandoned_mines_entrance_to_the_lost_valley]), + RegionData(BoardingHouseRegion.abandoned_mines_1a, [BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b]), + RegionData(BoardingHouseRegion.abandoned_mines_1b, [BoardingHouseEntrance.abandoned_mines_1b_to_abandoned_mines_2a]), + RegionData(BoardingHouseRegion.abandoned_mines_2a, [BoardingHouseEntrance.abandoned_mines_2a_to_abandoned_mines_2b]), + RegionData(BoardingHouseRegion.abandoned_mines_2b, [BoardingHouseEntrance.abandoned_mines_2b_to_abandoned_mines_3]), + RegionData(BoardingHouseRegion.abandoned_mines_3, [BoardingHouseEntrance.abandoned_mines_3_to_abandoned_mines_4]), + RegionData(BoardingHouseRegion.abandoned_mines_4, [BoardingHouseEntrance.abandoned_mines_4_to_abandoned_mines_5]), + RegionData(BoardingHouseRegion.abandoned_mines_5, [BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley]), + RegionData(BoardingHouseRegion.the_lost_valley, [BoardingHouseEntrance.the_lost_valley_to_gregory_tent, + BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins]), + RegionData(BoardingHouseRegion.gregory_tent), + RegionData(BoardingHouseRegion.lost_valley_ruins, [BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1, + BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2]), + RegionData(BoardingHouseRegion.lost_valley_house_1), + RegionData(BoardingHouseRegion.lost_valley_house_2) +] + +boarding_house_entrances = [ + ConnectionData(BoardingHouseEntrance.bus_stop_to_boarding_house_plateau, BoardingHouseRegion.boarding_house_plateau), + ConnectionData(BoardingHouseEntrance.boarding_house_plateau_to_boarding_house_first, BoardingHouseRegion.boarding_house_first, + flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(BoardingHouseEntrance.boarding_house_first_to_boarding_house_second, BoardingHouseRegion.boarding_house_second, + flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.boarding_house_plateau_to_buffalo_ranch, BoardingHouseRegion.buffalo_ranch, + flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(BoardingHouseEntrance.boarding_house_plateau_to_abandoned_mines_entrance, BoardingHouseRegion.abandoned_mines_entrance, + flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), + ConnectionData(BoardingHouseEntrance.abandoned_mines_entrance_to_the_lost_valley, BoardingHouseRegion.the_lost_valley, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_entrance_to_abandoned_mines_1a, BoardingHouseRegion.abandoned_mines_1a, + flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b, BoardingHouseRegion.abandoned_mines_1b, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_1b_to_abandoned_mines_2a, BoardingHouseRegion.abandoned_mines_2a, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_2a_to_abandoned_mines_2b, BoardingHouseRegion.abandoned_mines_2b, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_2b_to_abandoned_mines_3, BoardingHouseRegion.abandoned_mines_3, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_3_to_abandoned_mines_4, BoardingHouseRegion.abandoned_mines_4, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_4_to_abandoned_mines_5, BoardingHouseRegion.abandoned_mines_5, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley, BoardingHouseRegion.the_lost_valley, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.the_lost_valley_to_gregory_tent, BoardingHouseRegion.gregory_tent, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, BoardingHouseRegion.lost_valley_ruins), + ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1, BoardingHouseRegion.lost_valley_house_1, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2, BoardingHouseRegion.lost_valley_house_2, flag=RandomizationFlag.BUILDINGS) + + +] + vanilla_connections_to_remove_by_mod = { ModNames.sve: [ConnectionData(Entrance.mountain_to_the_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), @@ -314,4 +368,5 @@ ModNames.sve: ModRegionData(ModNames.sve, stardew_valley_expanded_regions, mandatory_sve_connections), ModNames.alecto: ModRegionData(ModNames.alecto, alecto_regions, alecto_entrances), ModNames.lacey: ModRegionData(ModNames.lacey, lacey_regions, lacey_entrances), + ModNames.boarding_house: ModRegionData(ModNames.boarding_house, boarding_house_regions, boarding_house_entrances), } diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 8174c1de087f..07e7ca3fa2b4 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -686,7 +686,7 @@ class Mods(OptionSet): ModNames.jasper, ModNames.alec, ModNames.yoba, ModNames.eugene, ModNames.wellwick, ModNames.ginger, ModNames.shiko, ModNames.delores, ModNames.ayeisha, ModNames.riley, ModNames.skull_cavern_elevator, ModNames.sve, ModNames.distant_lands, - ModNames.alecto, ModNames.lacey + ModNames.alecto, ModNames.lacey, ModNames.boarding_house } diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 74aedcd25258..cb88afc4e7a1 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -28,7 +28,7 @@ from .strings.craftable_names import Bomb from .strings.crop_names import Fruit from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance, \ - SVEEntrance + SVEEntrance, LaceyEntrance, BoardingHouseEntrance from .strings.generic_names import Generic from .strings.material_names import Material from .strings.metal_names import MetalBar @@ -271,6 +271,9 @@ def set_bedroom_entrance_rules(logic, multiworld, player, world_options: Stardew if ModNames.alec in world_options.mods: MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink())) + if ModNames.lacey in world_options.mods: + MultiWorldRules.set_rule(multiworld.get_entrance(LaceyEntrance.forest_to_hat_house, player), + logic.relationship.has_hearts(ModNPC.lacey, 2)) def set_mines_floor_entrance_rules(logic, multiworld, player): @@ -948,3 +951,16 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla logic.quest.can_complete_quest(ModQuest.MonsterCrops) & logic.region.can_reach(SVERegion.lances_house)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) + + +def set_boarding_house_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): + if ModNames.boarding_house not in world_options.mods: + return + MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b, player), + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.abandoned_mines_2b_to_abandoned_mines_3, player), + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley, player), + logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + MultiWorldRules.set_rule(MultiWorld.get_entrance(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, player), + logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) \ No newline at end of file diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index 321e034f2e81..d0d39b614a4a 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -335,3 +335,24 @@ class AlectoEntrance: class LaceyEntrance: forest_to_hat_house = "Forest to Mouse House" + +class BoardingHouseEntrance: + bus_stop_to_boarding_house_plateau = "Bus Stop to Boarding House Outside" + boarding_house_plateau_to_boarding_house_first = "Boarding House Outside to Boarding House - First Floor" + boarding_house_first_to_boarding_house_second = "Boarding House - First Floor to Boarding House - Second Floor" + boarding_house_plateau_to_abandoned_mines_entrance = "Boarding House Outside to Abandoned Mines Entrance" + abandoned_mines_entrance_to_abandoned_mines_1a = "Abandoned Mines Entrance to Abandoned Mines - 1A" + abandoned_mines_1a_to_abandoned_mines_1b = "Abandoned Mines - 1A to Abandoned Mines - 1B" + abandoned_mines_1b_to_abandoned_mines_2a = "Abandoned Mines - 1B to Abandoned Mines - 2A" + abandoned_mines_2a_to_abandoned_mines_2b = "Abandoned Mines - 2A to Abandoned Mines - 2B" + abandoned_mines_2b_to_abandoned_mines_3 = "Abandoned Mines - 2B to Abandoned Mines - 3" + abandoned_mines_3_to_abandoned_mines_4 = "Abandoned Mines - 3 to Abandoned Mines - 4" + abandoned_mines_4_to_abandoned_mines_5 = "Abandoned Mines - 4 to Abandoned Mines - 5" + abandoned_mines_5_to_the_lost_valley = "Abandoned Mines - 5 to The Lost Valley" + abandoned_mines_entrance_to_the_lost_valley = "Abandoned Mines Entrance to The Lost Valley" + the_lost_valley_to_gregory_tent = "The Lost Valley to Gregory's Tent" + the_lost_valley_to_lost_valley_ruins = "The Lost Valley to Lost Valley Ruins" + lost_valley_ruins_to_lost_valley_house_1 = "Lost Valley Ruins to Lost Valley Ruins - First House" + lost_valley_ruins_to_lost_valley_house_2 = "Lost Valley Ruins to Lost Valley Ruins - Second House" + boarding_house_plateau_to_buffalo_ranch = "Boarding House Outside to Buffalo's Ranch" + diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 6ad05c55391f..0008a18abe16 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -281,3 +281,25 @@ class AlectoRegion: class LaceyRegion: hat_house = "Mouse House" + + +class BoardingHouseRegion: + boarding_house_plateau = "Boarding House Outside" + boarding_house_first = "Boarding House - First Floor" + boarding_house_second = "Boarding House - Second Floor" + abandoned_mines_entrance = "Abandoned Mines Entrance" + abandoned_mines_1a = "Abandoned Mines - 1A" + abandoned_mines_1b = "Abandoned Mines - 1B" + abandoned_mines_2a = "Abandoned Mines - 2A" + abandoned_mines_2b = "Abandoned Mines - 2B" + abandoned_mines_3 = "Abandoned Mines - 3" + abandoned_mines_4 = "Abandoned Mines - 4" + abandoned_mines_5 = "Abandoned Mines - 5" + the_lost_valley = "The Lost Valley" + gregory_tent = "Gregory's Tent" + lost_valley_ruins = "Lost Valley Ruins" + lost_valley_house_1 = "Lost Valley Ruins - First House" + lost_valley_house_2 = "Lost Valley Ruins - Second House" + buffalo_ranch = "Buffalo's Ranch" + + diff --git a/worlds/stardew_valley/strings/villager_names.py b/worlds/stardew_valley/strings/villager_names.py index a97e7110dfd8..7e87be64f1ea 100644 --- a/worlds/stardew_valley/strings/villager_names.py +++ b/worlds/stardew_valley/strings/villager_names.py @@ -64,3 +64,6 @@ class ModNPC: alecto = "Alecto" goblin = "Zic" lacey = "Lacey" + gregory = "Gregory" + sheila = "Sheila" + joel = "Joel" From a3f09079b0eeb76e7c1ea4453009cee1c88a1ad8 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 16 Jan 2024 18:05:12 -0600 Subject: [PATCH 445/482] Finish up Lacey + BH support --- worlds/stardew_valley/data/locations.csv | 1 + worlds/stardew_valley/data/monster_data.py | 5 +++- .../stardew_valley/mods/logic/quests_logic.py | 23 +++++++++++++++++-- .../mods/mod_monster_locations.py | 10 ++++++-- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index c34656cf2e25..74fa5f511823 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2626,6 +2626,7 @@ id,region,name,tags,mod_name 7523,Boarding House - First Floor,Pumpkin Soup,"MANDATORY,STORY_QUEST",Boarding House and Bus Stop Extension 7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas 7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas +7526,Mouse House,Hats for the Hat Mouse,"MANDATORY,STORY_QUEST",Hat Mouse Lacey 7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 9be3a3bc0ce2..7d50ce0ac1f3 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -137,6 +137,9 @@ def register_monster_modification(mod_name: str, monster: StardewMonster, modifi register_monster_modification(ModNames.deepwoods, cave_fly, update_monster_locations) register_monster_modification(ModNames.deepwoods, green_slime, update_monster_locations) +register_monster_modification(ModNames.boarding_house, pepper_rex, update_monster_locations) +register_monster_modification(ModNames.boarding_house, shadow_brute, update_monster_locations) + def all_monsters_by_name_given_mods(mods: Set[str]) -> Dict[str, StardewMonster]: monsters_by_name = {} @@ -151,7 +154,7 @@ def all_monsters_by_name_given_mods(mods: Set[str]) -> Dict[str, StardewMonster] return monsters_by_name -def all_monsters_by_category_given_mods(mods: Set[str]) -> Dict[str, Tuple[StardewMonster,...]]: +def all_monsters_by_category_given_mods(mods: Set[str]) -> Dict[str, Tuple[StardewMonster, ...]]: monsters_by_category = {} for monster in all_monsters: current_monster = monster diff --git a/worlds/stardew_valley/mods/logic/quests_logic.py b/worlds/stardew_valley/mods/logic/quests_logic.py index 9d873aa1cc4d..40b5545ee39f 100644 --- a/worlds/stardew_valley/mods/logic/quests_logic.py +++ b/worlds/stardew_valley/mods/logic/quests_logic.py @@ -22,7 +22,7 @@ from ...strings.monster_drop_names import Loot from ...strings.monster_names import Monster from ...strings.quest_names import Quest, ModQuest -from ...strings.region_names import Region, SVERegion +from ...strings.region_names import Region, SVERegion, BoardingHouseRegion from ...strings.season_names import Season from ...strings.villager_names import ModNPC, NPC from ...strings.wallet_item_names import Wallet @@ -34,7 +34,8 @@ def __init__(self, *args, **kwargs): self.quest = ModQuestLogic(*args, **kwargs) -class ModQuestLogic(BaseLogic[Union[HasLogicMixin, QuestLogicMixin, ReceivedLogicMixin, RegionLogicMixin, TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MonsterLogicMixin]]): +class ModQuestLogic(BaseLogic[Union[HasLogicMixin, QuestLogicMixin, ReceivedLogicMixin, RegionLogicMixin, + TimeLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MonsterLogicMixin]]): def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests = dict() quests.update(self._get_juna_quest_rules()) @@ -42,6 +43,8 @@ def get_modded_quest_rules(self) -> Dict[str, StardewRule]: quests.update(self._get_ayeisha_quest_rules()) quests.update(self._get_sve_quest_rules()) quests.update(self._get_distant_lands_quest_rules()) + quests.update(self._get_boarding_house_quest_rules()) + quests.update((self._get_hat_mouse_quest_rules())) return quests def _get_juna_quest_rules(self): @@ -107,3 +110,19 @@ def _get_distant_lands_quest_rules(self): self.logic.relationship.has_hearts(NPC.emily, 8) & self.logic.season.has(Season.winter) } + + def _get_boarding_house_quest_rules(self): + if ModNames.boarding_house not in self.options.mods: + return {} + + return { + ModQuest.PumpkinSoup: self.logic.region.can_reach(BoardingHouseRegion.boarding_house_first) & self.logic.has(Vegetable.pumpkin) + } + + def _get_hat_mouse_quest_rules(self): + if ModNames.lacey not in self.options.mods: + return {} + + return { + ModQuest.HatMouseHat: self.logic.relationship.has_hearts(ModNPC.lacey, 2) & self.logic.time.has_lived_months(4) + } diff --git a/worlds/stardew_valley/mods/mod_monster_locations.py b/worlds/stardew_valley/mods/mod_monster_locations.py index d775818cd8be..4838caf1ff5f 100644 --- a/worlds/stardew_valley/mods/mod_monster_locations.py +++ b/worlds/stardew_valley/mods/mod_monster_locations.py @@ -2,7 +2,7 @@ from .mod_data import ModNames from ..strings.monster_names import Monster -from ..strings.region_names import SVERegion, DeepWoodsRegion +from ..strings.region_names import SVERegion, DeepWoodsRegion, BoardingHouseRegion sve_monsters_locations: Dict[str, Tuple[str, ...]] = { Monster.shadow_brute_dangerous: (SVERegion.highlands_cavern,), @@ -21,7 +21,13 @@ Monster.green_slime: (DeepWoodsRegion.floor_10,), } +boardinghouse_monsters_locations: Dict[str, Tuple[str, ...]] = { + Monster.shadow_brute: (BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), + Monster.pepper_rex: (BoardingHouseRegion.lost_valley_ruins,) +} + modded_monsters_locations: Dict[str, Dict[str, Tuple[str, ...]]] = { ModNames.sve: sve_monsters_locations, - ModNames.deepwoods: deepwoods_monsters_locations + ModNames.deepwoods: deepwoods_monsters_locations, + ModNames.boarding_house: boardinghouse_monsters_locations } From feb938c0c659dded65e7ede8bf356cbf522dc9fb Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 18 Jan 2024 02:54:07 -0600 Subject: [PATCH 446/482] Add names for Boarding House --- .../strings/artisan_good_names.py | 4 ++ .../stardew_valley/strings/craftable_names.py | 7 ++++ worlds/stardew_valley/strings/food_names.py | 4 ++ worlds/stardew_valley/strings/metal_names.py | 39 +++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/worlds/stardew_valley/strings/artisan_good_names.py b/worlds/stardew_valley/strings/artisan_good_names.py index 469644d95fd3..a017cff1f9dd 100644 --- a/worlds/stardew_valley/strings/artisan_good_names.py +++ b/worlds/stardew_valley/strings/artisan_good_names.py @@ -21,3 +21,7 @@ class ArtisanGood: caviar = "Caviar" green_tea = "Green Tea" mead = "Mead" + + +class ModArtisanGood: + pterodactyl_egg = "Pterodactyl Egg" diff --git a/worlds/stardew_valley/strings/craftable_names.py b/worlds/stardew_valley/strings/craftable_names.py index dedc69166eb9..74a77a8e9467 100644 --- a/worlds/stardew_valley/strings/craftable_names.py +++ b/worlds/stardew_valley/strings/craftable_names.py @@ -157,6 +157,13 @@ class ModCraftable: glass_fence = "Glass Fence" wooden_display = "Wooden Display" hardwood_display = "Hardwood Display" + neanderthal_skeleton = "Neanderthal Skeleton" + pterodactyl_skeleton_l = "Pterodactyl Skeleton L" + pterodactyl_skeleton_m = "Pterodactyl Skeleton M" + pterodactyl_skeleton_r = "Pterodactyl Skeleton R" + trex_skeleton_l = "T-Rex Skeleton L" + trex_skeleton_m = "T-Rex Skeleton M" + trex_skeleton_r = "T-Rex Skeleton R" class ModMachine: diff --git a/worlds/stardew_valley/strings/food_names.py b/worlds/stardew_valley/strings/food_names.py index b0a187b0154d..6e2f98fd581b 100644 --- a/worlds/stardew_valley/strings/food_names.py +++ b/worlds/stardew_valley/strings/food_names.py @@ -112,3 +112,7 @@ class DistantLandsMeal: crayfish_soup = "Crayfish Soup" pemmican = "Pemmican" void_mint_tea = "Void Mint Tea" + + +class BoardingHouseMeal: + special_pumpkin_soup = "Special Pumpkin Soup" diff --git a/worlds/stardew_valley/strings/metal_names.py b/worlds/stardew_valley/strings/metal_names.py index 59e23ac4d32d..bf15b9d01c8e 100644 --- a/worlds/stardew_valley/strings/metal_names.py +++ b/worlds/stardew_valley/strings/metal_names.py @@ -104,3 +104,42 @@ class Fossil: snake_skull = fossil("Snake Skull") snake_vertebrae = fossil("Snake Vertebrae") trilobite = fossil("Trilobite") + + +class ModArtifact: + ancient_hilt = "Ancient Hilt" + ancient_blade = "Ancient Blade" + mask_piece_1 = "Mask Piece 1" + mask_piece_2 = "Mask Piece 2" + mask_piece_3 = "Mask Piece 3" + ancient_doll_body = "Ancient Doll Body" + ancient_doll_legs = "Ancient Doll Legs" + prismatic_shard_piece_1 = "Prismatic Shard Piece 1" + prismatic_shard_piece_2 = "Prismatic Shard Piece 2" + prismatic_shard_piece_3 = "Prismatic Shard Piece 3" + prismatic_shard_piece_4 = "Prismatic Shard Piece 4" + chipped_amphora_piece_1 = "Chipped Amphora Piece 1" + chipped_amphora_piece_2 = "Chipped Amphora Piece 2" + + +class ModFossil: + neanderthal_limb_bones = "Neanderthal Limb Bones" + neanderthal_ribs = "Neanderthal Ribs" + neanderthal_skull = "Neanderthal Skull" + neanderthal_pelvis = "Neanderthal Pelvis" + dinosaur_tooth = "Dinosaur Tooth" + dinosaur_skull = "Dinosaur Skull" + dinosaur_claw = "Dinosaur Claw" + dinosaur_femur = "Dinosaur Femur" + dinosaur_ribs = "Dinosaur Ribs" + dinosaur_pelvis = "Dinosaur Pelvis" + dinosaur_vertebra = "Dinosaur Vertebra" + pterodactyl_ribs = "Pterodactyl Ribs" + pterodactyl_skull = "Pterodactyl Skull" + pterodactyl_r_wing_bone = "Pterodactyl R Wing Bone" + pterodactyl_l_wing_bone = "Pterodactyl L Wing Bone" + pterodactyl_phalange = "Pterodactyl Phalange" + pterodactyl_vertebra = "Pterodactyl Vertebra" + pterodactyl_claw = "Pterodactyl Claw" + + From 5ff415b6a46cfb3ce99202ffc33044bbb06aa343 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 18 Jan 2024 02:54:31 -0600 Subject: [PATCH 447/482] Add recipes and craft data for BH --- worlds/stardew_valley/data/craftable_data.py | 24 +++++++++++++++++++- worlds/stardew_valley/data/recipe_data.py | 5 +++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 77d37cb6addd..7715789c8322 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -16,7 +16,7 @@ from ..strings.ingredient_names import Ingredient from ..strings.machine_names import Machine from ..strings.material_names import Material -from ..strings.metal_names import Ore, MetalBar, Fossil, Artifact, Mineral +from ..strings.metal_names import Ore, MetalBar, Fossil, Artifact, Mineral, ModFossil from ..strings.monster_drop_names import Loot from ..strings.quest_names import Quest from ..strings.region_names import Region, SVERegion @@ -289,4 +289,26 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, ginger_tincture = friendship_recipe(ModConsumable.ginger_tincture, ModNPC.goblin, 4, {DistantLandsForageable.brown_amanita: 1, Forageable.ginger: 5, Material.cinder_shard: 1, DistantLandsForageable.swamp_herb: 1}, ModNames.distant_lands) +neanderthal_skeleton = shop_recipe(ModCraftable.neanderthal_skeleton, Region.mines_dwarf_shop, 5000, + {ModFossil.neanderthal_skull: 1, ModFossil.neanderthal_ribs: 1, ModFossil.neanderthal_pelvis: 1, ModFossil.neanderthal_limb_bones: 1, + MetalBar.iron: 5, Material.hardwood: 10}, ModNames.boarding_house) +pterodactyl_skeleton_l = shop_recipe(ModCraftable.pterodactyl_skeleton_l, Region.mines_dwarf_shop, 5000, + {ModFossil.pterodactyl_phalange: 1, ModFossil.pterodactyl_skull: 1, ModFossil.pterodactyl_l_wing_bone: 1, + MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house) +pterodactyl_skeleton_m = shop_recipe(ModCraftable.pterodactyl_skeleton_m, Region.mines_dwarf_shop, 5000, + {ModFossil.pterodactyl_phalange: 1, ModFossil.pterodactyl_vertebra: 1, ModFossil.pterodactyl_ribs: 1, + MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house) +pterodactyl_skeleton_r = shop_recipe(ModCraftable.pterodactyl_skeleton_r, Region.mines_dwarf_shop, 5000, + {ModFossil.pterodactyl_phalange: 1, ModFossil.pterodactyl_claw: 1, ModFossil.pterodactyl_r_wing_bone: 1, + MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house) +trex_skeleton_l = shop_recipe(ModCraftable.trex_skeleton_l, Region.mines_dwarf_shop, 5000, + {ModFossil.dinosaur_vertebra: 1, ModFossil.dinosaur_tooth: 1, ModFossil.dinosaur_skull: 1, + MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house) +trex_skeleton_m = shop_recipe(ModCraftable.trex_skeleton_m, Region.mines_dwarf_shop, 5000, + {ModFossil.dinosaur_vertebra: 1, ModFossil.dinosaur_ribs: 1, ModFossil.dinosaur_claw: 1, + MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house) +trex_skeleton_r = shop_recipe(ModCraftable.trex_skeleton_r, Region.mines_dwarf_shop, 5000, + {ModFossil.dinosaur_vertebra: 1, ModFossil.dinosaur_femur: 1, ModFossil.dinosaur_pelvis: 1, + MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house) + all_crafting_recipes_by_name = {recipe.item: recipe for recipe in all_crafting_recipes} diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 8ecfbe85a64d..3b5af8c9e13f 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -8,7 +8,7 @@ from ..strings.flower_names import Flower from ..strings.forageable_names import Forageable, SVEForage, DistantLandsForageable from ..strings.ingredient_names import Ingredient -from ..strings.food_names import Meal, SVEMeal, Beverage, DistantLandsMeal +from ..strings.food_names import Meal, SVEMeal, Beverage, DistantLandsMeal, BoardingHouseMeal from ..strings.material_names import Material from ..strings.metal_names import Fossil from ..strings.monster_drop_names import Loot @@ -203,5 +203,8 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, pemmican = friendship_recipe(DistantLandsMeal.pemmican, ModNPC.goblin, 8, {Loot.bug_meat: 1, Fish.any: 1, Forageable.salmonberry: 3, Material.stone: 2}, ModNames.distant_lands) +special_pumpkin_soup = friendship_recipe(BoardingHouseMeal.special_pumpkin_soup, ModNPC.joel, 6, {Vegetable.pumpkin: 2, AnimalProduct.large_goat_milk: 1, + Vegetable.garlic: 1}, ModNames.boarding_house) + all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes} \ No newline at end of file From 4f8b1dae482dc45bb7a50bddd8ea7b958f61bb85 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 18 Jan 2024 02:54:43 -0600 Subject: [PATCH 448/482] Add BH logic and items --- worlds/stardew_valley/data/items.csv | 8 ++ worlds/stardew_valley/data/locations.csv | 42 ++++++++- worlds/stardew_valley/logic/tool_logic.py | 3 + .../stardew_valley/mods/logic/item_logic.py | 89 +++++++++++++++++-- 4 files changed, 134 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 2c69ed2e8617..572a7b0bf362 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -805,6 +805,7 @@ id,name,classification,groups,mod_name 10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +10416,Special Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension 10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul 10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded @@ -832,6 +833,13 @@ id,name,classification,groups,mod_name 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10606,Neanderthal Skeleton Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10607,Pterodactyl Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10608,Pterodactyl Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10609,Pterodactyl Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10610,T-Rex Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10611,T-Rex Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10612,T-Rex Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension 10701,Resource Pack: 3 Magic Elixir,filler,RESOURCE_PACK,Magic 10702,Resource Pack: 3 Travel Core,filler,RESOURCE_PACK,Magic 10703,Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 74fa5f511823..4404f269f9ea 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2655,6 +2655,14 @@ id,region,name,tags,mod_name 7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7615,Boarding House - First Floor,Special Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension +7616,Mines Dwarf Shop,Neanderthal Skeleton Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7617,Mines Dwarf Shop,Pterodactyl Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7618,Mines Dwarf Shop,Pterodactyl Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7619,Mines Dwarf Shop,Pterodactyl Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7620,Mines Dwarf Shop,T-Rex Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7621,Mines Dwarf Shop,T-Rex Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7622,Mines Dwarf Shop,T-Rex Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension 7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded 7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded @@ -2725,7 +2733,6 @@ id,region,name,tags,mod_name 8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded 8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded 8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8028,Shipping,Shipsanity: Galdoran Gem,SHIPSANITY,Stardew Valley Expanded 8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded 8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY",Stardew Valley Expanded 8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded @@ -2906,3 +2913,36 @@ id,region,name,tags,mod_name 8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +8219,Shipping,Shipsanity: Ancient Hilt,SHIPSANITY,Boarding House and Bus Stop Extension +8220,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension +8221,Shipping,Shipsanity: Ancient Blade,SHIPSANITY,Boarding House and Bus Stop Extension +8222,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8223,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension +8224,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +8225,Shipping,Shipsanity: Ancient Doll Legs,SHIPSANITY,Boarding House and Bus Stop Extension +8226,Shipping,Shipsanity: Mask Piece 2,SHIPSANITY,Boarding House and Bus Stop Extension +8227,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8228,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension +8229,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension +8230,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8231,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8232,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8233,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8234,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8235,Shipping,Shipsanity: Prismatic Shard Piece 1,SHIPSANITY,Boarding House and Bus Stop Extension +8236,Shipping,Shipsanity: Prismatic Shard Piece 3,SHIPSANITY,Boarding House and Bus Stop Extension +8237,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension +8238,Shipping,Shipsanity: Ancient Doll Body,SHIPSANITY,Boarding House and Bus Stop Extension +8239,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8240,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8241,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8242,Shipping,Shipsanity: Prismatic Shard Piece 2,SHIPSANITY,Boarding House and Bus Stop Extension +8243,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension +8244,Shipping,Shipsanity: Chipped Amphora Piece 2,SHIPSANITY,Boarding House and Bus Stop Extension +8245,Shipping,Shipsanity: Mask Piece 1,SHIPSANITY,Boarding House and Bus Stop Extension +8246,Shipping,Shipsanity: Prismatic Shard Piece 4,SHIPSANITY,Boarding House and Bus Stop Extension +8247,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8248,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8249,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +8250,Shipping,Shipsanity: Mask Piece 3,SHIPSANITY,Boarding House and Bus Stop Extension +8251,Shipping,Shipsanity: Chipped Amphora Piece 1,SHIPSANITY,Boarding House and Bus Stop Extension diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index def02b35dab6..dc6ac0ec328f 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -79,3 +79,6 @@ def can_water(self, level: int) -> StardewRule: tool_rule = self.logic.tool.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) spell_rule = self.logic.received(MagicSpell.water) & self.logic.magic.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, level) return tool_rule | spell_rule + + def has_any_tool(self) -> StardewRule: + return self.has_tool(Tool.axe) | self.has_tool(Tool.pickaxe) | self.has_tool(Tool.scythe) | self.has_tool(Tool.hoe) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 3f3f9b5ca57c..341418d30639 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -20,6 +20,7 @@ from ...logic.tool_logic import ToolLogicMixin from ...options import Cropsanity from ...stardew_rule import StardewRule, True_ +from ...strings.artisan_good_names import ModArtisanGood from ...strings.craftable_names import ModCraftable, ModEdible, ModMachine from ...strings.crop_names import SVEVegetable, SVEFruit, DistantLandsCrop, Fruit from ...strings.fish_names import DistantLandsFish, WaterItem, Fish @@ -29,10 +30,10 @@ from ...strings.gift_names import SVEGift from ...strings.ingredient_names import Ingredient from ...strings.material_names import Material -from ...strings.metal_names import all_fossils, all_artifacts, Ore +from ...strings.metal_names import all_fossils, all_artifacts, Ore, ModFossil, ModArtifact from ...strings.monster_drop_names import ModLoot, Loot from ...strings.performance_names import Performance -from ...strings.region_names import Region, SVERegion, DeepWoodsRegion +from ...strings.region_names import Region, SVERegion, DeepWoodsRegion, BoardingHouseRegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed, DistantLandsSeed from ...strings.skill_names import Skill @@ -60,6 +61,8 @@ def get_modded_item_rules(self) -> Dict[str, StardewRule]: items.update(self.get_archaeology_item_rules()) if ModNames.distant_lands in self.options.mods: items.update(self.get_distant_lands_item_rules()) + if ModNames.boarding_house in self.options.mods: + items.update(self.get_boarding_house_item_rules()) return items def modify_vanilla_item_rules_with_mod_additions(self, item_rule: Dict[str, StardewRule]): @@ -106,7 +109,6 @@ def get_sve_item_rules(self): SVEForage.dewdrop_berry: self.logic.region.can_reach(SVERegion.enchanted_grove), SVEForage.dried_sand_dollar: self.logic.region.can_reach(SVERegion.fable_reef) | (self.logic.region.can_reach(Region.beach) & self.logic.season.has_any([Season.summer, Season.fall])), - "Galdoran Gem": self.logic.museum.can_complete_museum() & self.logic.relationship.has_hearts(ModNPC.marlon, 8), SVEForage.golden_ocean_flower: self.logic.region.can_reach(SVERegion.fable_reef), SVEMeal.grampleton_orange_chicken: self.logic.money.can_spend_at(Region.saloon, 650) & self.logic.relationship.has_hearts(ModNPC.sophia, 6), ModEdible.hero_elixir: self.logic.money.can_spend_at(SVERegion.isaac_shop, 8000), @@ -138,8 +140,9 @@ def get_modified_item_rules_for_sve(self, items: Dict[str, StardewRule]): Fruit.ancient_fruit: items[Fruit.ancient_fruit] | ( self.logic.tool.can_forage((Season.spring, Season.summer, Season.fall), SVERegion.sprite_spring) & self.logic.time.has_year_three) | self.logic.region.can_reach(SVERegion.sprite_spring_cave), - Fruit.sweet_gem_berry: items[Fruit.sweet_gem_berry] | (self.logic.tool.can_forage((Season.spring, Season.summer, Season.fall), SVERegion.sprite_spring) & - self.logic.time.has_year_three), + Fruit.sweet_gem_berry: items[Fruit.sweet_gem_berry] | ( + self.logic.tool.can_forage((Season.spring, Season.summer, Season.fall), SVERegion.sprite_spring) & + self.logic.time.has_year_three), WaterItem.coral: items[WaterItem.coral] | self.logic.region.can_reach(SVERegion.fable_reef), Forageable.rainbow_shell: items[Forageable.rainbow_shell] | self.logic.region.can_reach(SVERegion.fable_reef), WaterItem.sea_urchin: items[WaterItem.sea_urchin] | self.logic.region.can_reach(SVERegion.fable_reef), @@ -174,8 +177,10 @@ def get_modified_item_rules_for_deep_woods(self, items: Dict[str, StardewRule]): Flower.fairy_rose: items[Flower.fairy_rose] | self.logic.region.can_reach(DeepWoodsRegion.floor_10), Material.hardwood: items[Material.hardwood] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.iron, DeepWoodsRegion.floor_10), Ore.iridium: items[Ore.iridium] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.iridium, DeepWoodsRegion.floor_50), # Iridium Tree - Ingredient.sugar: items[Ingredient.sugar] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.gold, DeepWoodsRegion.floor_50), # Gingerbread House - Ingredient.wheat_flour: items[Ingredient.wheat_flour] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.gold, DeepWoodsRegion.floor_50), # Gingerbread House + Ingredient.sugar: items[Ingredient.sugar] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.gold, DeepWoodsRegion.floor_50), + # Gingerbread House + Ingredient.wheat_flour: items[Ingredient.wheat_flour] | self.logic.tool.can_use_tool_at(Tool.axe, ToolMaterial.gold, DeepWoodsRegion.floor_50), + # Gingerbread House } def get_archaeology_item_rules(self): @@ -205,6 +210,76 @@ def get_distant_lands_item_rules(self): DistantLandsCrop.vile_ancient_fruit: self.logic.season.has_any_not_winter() & self.logic.has(DistantLandsSeed.vile_ancient_fruit), } + def get_boarding_house_item_rules(self): + return { + # Mob Drops from lost valley enemies + ModArtisanGood.pterodactyl_egg: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_claw: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_vertebra: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_skull: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_phalange: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_l_wing_bone: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.pterodactyl_r_wing_bone: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_skull: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_tooth: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_femur: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_pelvis: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_vertebra: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.dinosaur_claw: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + ModFossil.neanderthal_skull: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), + ModFossil.neanderthal_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), + ModFossil.neanderthal_pelvis: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), + ModFossil.neanderthal_limb_bones: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), + # Items only obtainable in the abandoned mines via digging or breaking boxes + ModArtifact.ancient_hilt: self.logic.region.can_reach_any((BoardingHouseRegion.abandoned_mines_2a, BoardingHouseRegion.abandoned_mines_2b)) & + self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.ancient_blade: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_3) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.ancient_doll_body: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_3) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.ancient_doll_legs: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_1b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.chipped_amphora_piece_1: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_1b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.chipped_amphora_piece_2: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_2b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.prismatic_shard_piece_1: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_4) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.prismatic_shard_piece_2: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_4) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.prismatic_shard_piece_3: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_5) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.prismatic_shard_piece_4: self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_1b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), + ModArtifact.mask_piece_1: (self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_3) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent)), + ModArtifact.mask_piece_2: (self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_4) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent)), + ModArtifact.mask_piece_3: (self.logic.region.can_reach( + BoardingHouseRegion.abandoned_mines_2b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent)), + } + def has_seed_unlocked(self, seed_name: str): if self.options.cropsanity == Cropsanity.option_disabled: return True_() From 683a56b38e1fd77cab208f3e1ac6950965b5cd78 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 09:52:22 -0600 Subject: [PATCH 449/482] Fix Elixir and remove some BH items --- worlds/stardew_valley/data/craftable_data.py | 1 - worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 57 +++++++--------- worlds/stardew_valley/data/recipe_data.py | 3 + worlds/stardew_valley/logic/tool_logic.py | 3 - .../stardew_valley/mods/logic/item_logic.py | 65 ++++++------------- 6 files changed, 45 insertions(+), 86 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 7715789c8322..0fa041551c2f 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -262,7 +262,6 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1}) cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 9, {Material.wood: 15, Material.fiber: 10, Material.coal: 3}) -magic_elixir = shop_recipe(ModEdible.magic_elixir, Region.adventurer_guild, 3000, {Edible.life_elixir: 1, Forageable.purple_mushroom: 1}, ModNames.magic) travel_charm = shop_recipe(ModCraftable.travel_core, Region.adventurer_guild, 250, {Loot.solar_essence: 1, Loot.void_essence: 1}, ModNames.magic) preservation_chamber = skill_recipe(ModMachine.preservation_chamber, ModSkill.archaeology, 2, {MetalBar.copper: 1, Material.wood: 15, ArtisanGood.oak_resin: 30}, ModNames.archaeology) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 572a7b0bf362..f1c1b630ffaf 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -828,7 +828,7 @@ id,name,classification,groups,mod_name 10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded 10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded 10520,Morgan's Schooling,progression,,Stardew Valley Expanded -10601,Magic Elixir Recipe,progression,CRAFTSANITY,Magic +10601,Magic Elixir Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic 10602,Travel Core Recipe,progression,CRAFTSANITY,Magic 10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded 10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 4404f269f9ea..0d1b78d95246 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2578,7 +2578,7 @@ id,region,name,tags,mod_name 7055,Abandoned Mines - 3,Abandoned Treasure - Floor 3,MANDATORY,Boarding House and Bus Stop Extension 7056,Abandoned Mines - 4,Abandoned Treasure - Floor 4,MANDATORY,Boarding House and Bus Stop Extension 7057,Abandoned Mines - 5,Abandoned Treasure - Floor 5,MANDATORY,Boarding House and Bus Stop Extension -7401,Farm,Craft Magic Elixir,CRAFTSANITY,Magic +7401,Farm,Cook Magic Elixir,COOKSANITY,Magic 7402,Farm,Craft Travel Core,CRAFTSANITY,Magic 7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded 7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded @@ -2596,7 +2596,7 @@ id,region,name,tags,mod_name 7416,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology 7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology 7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology -7451,Adventurer's Guild,Magic Elixir Recipe,CRAFTSANITY,Magic +7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded @@ -2913,36 +2913,23 @@ id,region,name,tags,mod_name 8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul 8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -8219,Shipping,Shipsanity: Ancient Hilt,SHIPSANITY,Boarding House and Bus Stop Extension -8220,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension -8221,Shipping,Shipsanity: Ancient Blade,SHIPSANITY,Boarding House and Bus Stop Extension -8222,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension -8223,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension -8224,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension -8225,Shipping,Shipsanity: Ancient Doll Legs,SHIPSANITY,Boarding House and Bus Stop Extension -8226,Shipping,Shipsanity: Mask Piece 2,SHIPSANITY,Boarding House and Bus Stop Extension -8227,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8228,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension -8229,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension -8230,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8231,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension -8232,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8233,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension -8234,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8235,Shipping,Shipsanity: Prismatic Shard Piece 1,SHIPSANITY,Boarding House and Bus Stop Extension -8236,Shipping,Shipsanity: Prismatic Shard Piece 3,SHIPSANITY,Boarding House and Bus Stop Extension -8237,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension -8238,Shipping,Shipsanity: Ancient Doll Body,SHIPSANITY,Boarding House and Bus Stop Extension -8239,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension -8240,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension -8241,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8242,Shipping,Shipsanity: Prismatic Shard Piece 2,SHIPSANITY,Boarding House and Bus Stop Extension -8243,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension -8244,Shipping,Shipsanity: Chipped Amphora Piece 2,SHIPSANITY,Boarding House and Bus Stop Extension -8245,Shipping,Shipsanity: Mask Piece 1,SHIPSANITY,Boarding House and Bus Stop Extension -8246,Shipping,Shipsanity: Prismatic Shard Piece 4,SHIPSANITY,Boarding House and Bus Stop Extension -8247,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension -8248,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8249,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension -8250,Shipping,Shipsanity: Mask Piece 3,SHIPSANITY,Boarding House and Bus Stop Extension -8251,Shipping,Shipsanity: Chipped Amphora Piece 1,SHIPSANITY,Boarding House and Bus Stop Extension +8218,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension +8219,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8220,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension +8221,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +8222,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8223,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension +8224,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension +8225,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8226,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8227,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8228,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8229,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8230,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension +8231,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8232,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8233,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8234,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension +8235,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8236,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8237,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension diff --git a/worlds/stardew_valley/data/recipe_data.py b/worlds/stardew_valley/data/recipe_data.py index 3b5af8c9e13f..62dcd8709c64 100644 --- a/worlds/stardew_valley/data/recipe_data.py +++ b/worlds/stardew_valley/data/recipe_data.py @@ -3,6 +3,7 @@ from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource, ShopFriendshipSource from ..strings.animal_product_names import AnimalProduct from ..strings.artisan_good_names import ArtisanGood +from ..strings.craftable_names import ModEdible, Edible from ..strings.crop_names import Fruit, Vegetable, SVEFruit, DistantLandsCrop from ..strings.fish_names import Fish, SVEFish, WaterItem, DistantLandsFish from ..strings.flower_names import Flower @@ -174,6 +175,8 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, trout_soup = queen_of_sauce_recipe(Meal.trout_soup, 1, Season.fall, 14, {Fish.rainbow_trout: 1, WaterItem.green_algae: 1}) vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Vegetable.tomato: 1, Vegetable.beet: 1}) +magic_elixir = shop_recipe(ModEdible.magic_elixir, Region.adventurer_guild, 3000, {Edible.life_elixir: 1, Forageable.purple_mushroom: 1}, ModNames.magic) + baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 0, {Forageable.salmonberry: 15, Forageable.blackberry: 15, Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve) big_bark_burger = friendship_and_shop_recipe(SVEMeal.big_bark_burger, NPC.gus, 5, Region.saloon, 5500, diff --git a/worlds/stardew_valley/logic/tool_logic.py b/worlds/stardew_valley/logic/tool_logic.py index dc6ac0ec328f..def02b35dab6 100644 --- a/worlds/stardew_valley/logic/tool_logic.py +++ b/worlds/stardew_valley/logic/tool_logic.py @@ -79,6 +79,3 @@ def can_water(self, level: int) -> StardewRule: tool_rule = self.logic.tool.has_tool(Tool.watering_can, ToolMaterial.tiers[level]) spell_rule = self.logic.received(MagicSpell.water) & self.logic.magic.can_use_altar() & self.logic.received(ModSkillLevel.magic_level, level) return tool_rule | spell_rule - - def has_any_tool(self) -> StardewRule: - return self.has_tool(Tool.axe) | self.has_tool(Tool.pickaxe) | self.has_tool(Tool.scythe) | self.has_tool(Tool.hoe) diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index 341418d30639..c418dc1e40f8 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -214,70 +214,43 @@ def get_boarding_house_item_rules(self): return { # Mob Drops from lost valley enemies ModArtisanGood.pterodactyl_egg: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_claw: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_vertebra: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_skull: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_phalange: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_l_wing_bone: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.pterodactyl_r_wing_bone: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_skull: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_tooth: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_femur: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_pelvis: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_vertebra: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.dinosaur_claw: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.good), ModFossil.neanderthal_skull: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), - ModFossil.neanderthal_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), + ModFossil.neanderthal_ribs: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), ModFossil.neanderthal_pelvis: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), ModFossil.neanderthal_limb_bones: self.logic.region.can_reach_any((BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, - BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), - # Items only obtainable in the abandoned mines via digging or breaking boxes - ModArtifact.ancient_hilt: self.logic.region.can_reach_any((BoardingHouseRegion.abandoned_mines_2a, BoardingHouseRegion.abandoned_mines_2b)) & - self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.ancient_blade: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_3) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.ancient_doll_body: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_3) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.ancient_doll_legs: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_1b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.chipped_amphora_piece_1: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_1b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.chipped_amphora_piece_2: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_2b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.prismatic_shard_piece_1: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_4) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.prismatic_shard_piece_2: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_4) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.prismatic_shard_piece_3: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_5) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.prismatic_shard_piece_4: self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_1b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent), - ModArtifact.mask_piece_1: (self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_3) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent)), - ModArtifact.mask_piece_2: (self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_4) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent)), - ModArtifact.mask_piece_3: (self.logic.region.can_reach( - BoardingHouseRegion.abandoned_mines_2b) & self.logic.tool.has_any_tool() & self.logic.combat.can_fight_at_level(Performance.decent)), + BoardingHouseRegion.lost_valley_house_2,)) & self.logic.combat.can_fight_at_level(Performance.great), } def has_seed_unlocked(self, seed_name: str): From 7462b71b665e11ea2d01d0e13ee805bda754a448 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 16:10:12 -0600 Subject: [PATCH 450/482] Fix some rebase errors --- worlds/stardew_valley/__init__.py | 2 +- worlds/stardew_valley/data/villagers_data.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index ab4bae5345f3..24419d9dd3f4 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -334,7 +334,7 @@ def fill_slot_data(self) -> Dict[str, Any]: for i, item in enumerate(bundle.items): bundles[room.name][bundle.name][i] = f"{item.item_name}|{item.amount}|{item.quality}" - excluded_options = [BundleRandomization, BundlePrice, NumberOfMovementBuffs, NumberOfLuckBuffs] + excluded_options = [BundleRandomization, NumberOfMovementBuffs, NumberOfLuckBuffs] excluded_option_names = [option.internal_name for option in excluded_options] generic_option_names = [option_name for option_name in PerGameCommonOptions.type_hints] excluded_option_names.extend(generic_option_names) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 06c659a03b77..6c8943abb67e 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -2,7 +2,7 @@ from typing import List, Tuple, Optional, Dict, Callable, Set from ..strings.food_names import Beverage -from ..strings.region_names import Region, SVERegion, AlectoRegion +from ..strings.region_names import Region, SVERegion, AlectoRegion, BoardingHouseRegion, LaceyRegion from ..mods.mod_data import ModNames from ..strings.generic_names import Generic from ..strings.season_names import Season From b7f04371a20e0616a805c9afea5be014da8da492 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 18:59:00 -0600 Subject: [PATCH 451/482] Add minecart entrance to fix ER bug --- worlds/stardew_valley/mods/mod_regions.py | 7 +++++-- worlds/stardew_valley/strings/entrance_names.py | 1 + worlds/stardew_valley/strings/region_names.py | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 5270fbb8f3fc..7d99d663fc6a 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -311,10 +311,12 @@ RegionData(BoardingHouseRegion.abandoned_mines_4, [BoardingHouseEntrance.abandoned_mines_4_to_abandoned_mines_5]), RegionData(BoardingHouseRegion.abandoned_mines_5, [BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley]), RegionData(BoardingHouseRegion.the_lost_valley, [BoardingHouseEntrance.the_lost_valley_to_gregory_tent, + BoardingHouseEntrance.lost_valley_to_lost_valley_minecart, BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins]), RegionData(BoardingHouseRegion.gregory_tent), RegionData(BoardingHouseRegion.lost_valley_ruins, [BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1, BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2]), + RegionData(BoardingHouseRegion.lost_valley_minecart), RegionData(BoardingHouseRegion.lost_valley_house_1), RegionData(BoardingHouseRegion.lost_valley_house_2) ] @@ -329,7 +331,7 @@ flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(BoardingHouseEntrance.boarding_house_plateau_to_abandoned_mines_entrance, BoardingHouseRegion.abandoned_mines_entrance, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(BoardingHouseEntrance.abandoned_mines_entrance_to_the_lost_valley, BoardingHouseRegion.the_lost_valley, flag=RandomizationFlag.BUILDINGS), + ConnectionData(BoardingHouseEntrance.abandoned_mines_entrance_to_the_lost_valley, BoardingHouseRegion.lost_valley_minecart, flag=RandomizationFlag.BUILDINGS), ConnectionData(BoardingHouseEntrance.abandoned_mines_entrance_to_abandoned_mines_1a, BoardingHouseRegion.abandoned_mines_1a, flag=RandomizationFlag.BUILDINGS), ConnectionData(BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b, BoardingHouseRegion.abandoned_mines_1b, flag=RandomizationFlag.BUILDINGS), @@ -340,7 +342,8 @@ ConnectionData(BoardingHouseEntrance.abandoned_mines_4_to_abandoned_mines_5, BoardingHouseRegion.abandoned_mines_5, flag=RandomizationFlag.BUILDINGS), ConnectionData(BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley, BoardingHouseRegion.the_lost_valley, flag=RandomizationFlag.BUILDINGS), ConnectionData(BoardingHouseEntrance.the_lost_valley_to_gregory_tent, BoardingHouseRegion.gregory_tent, flag=RandomizationFlag.BUILDINGS), - ConnectionData(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, BoardingHouseRegion.lost_valley_ruins), + ConnectionData(BoardingHouseEntrance.lost_valley_to_lost_valley_minecart, BoardingHouseRegion.lost_valley_minecart), + ConnectionData(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, BoardingHouseRegion.lost_valley_ruins, flag=RandomizationFlag.BUILDINGS), ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1, BoardingHouseRegion.lost_valley_house_1, flag=RandomizationFlag.BUILDINGS), ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2, BoardingHouseRegion.lost_valley_house_2, flag=RandomizationFlag.BUILDINGS) diff --git a/worlds/stardew_valley/strings/entrance_names.py b/worlds/stardew_valley/strings/entrance_names.py index d0d39b614a4a..00823d62ea07 100644 --- a/worlds/stardew_valley/strings/entrance_names.py +++ b/worlds/stardew_valley/strings/entrance_names.py @@ -349,6 +349,7 @@ class BoardingHouseEntrance: abandoned_mines_3_to_abandoned_mines_4 = "Abandoned Mines - 3 to Abandoned Mines - 4" abandoned_mines_4_to_abandoned_mines_5 = "Abandoned Mines - 4 to Abandoned Mines - 5" abandoned_mines_5_to_the_lost_valley = "Abandoned Mines - 5 to The Lost Valley" + lost_valley_to_lost_valley_minecart = "The Lost Valley to Lost Valley Minecart" abandoned_mines_entrance_to_the_lost_valley = "Abandoned Mines Entrance to The Lost Valley" the_lost_valley_to_gregory_tent = "The Lost Valley to Gregory's Tent" the_lost_valley_to_lost_valley_ruins = "The Lost Valley to Lost Valley Ruins" diff --git a/worlds/stardew_valley/strings/region_names.py b/worlds/stardew_valley/strings/region_names.py index 0008a18abe16..0fdab64fef68 100644 --- a/worlds/stardew_valley/strings/region_names.py +++ b/worlds/stardew_valley/strings/region_names.py @@ -298,6 +298,7 @@ class BoardingHouseRegion: the_lost_valley = "The Lost Valley" gregory_tent = "Gregory's Tent" lost_valley_ruins = "Lost Valley Ruins" + lost_valley_minecart = "Lost Valley Minecart" lost_valley_house_1 = "Lost Valley Ruins - First House" lost_valley_house_2 = "Lost Valley Ruins - Second House" buffalo_ranch = "Buffalo's Ranch" From eb95af8de545cb35cc66c53548d09d46531c8665 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 23:04:38 -0600 Subject: [PATCH 452/482] Deprecate DL seed items --- worlds/stardew_valley/data/items.csv | 1716 ++++++++--------- .../stardew_valley/mods/logic/item_logic.py | 8 +- 2 files changed, 863 insertions(+), 861 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index f1c1b630ffaf..7507ba38291b 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -1,858 +1,858 @@ -id,name,classification,groups,mod_name -0,Joja Cola,filler,TRASH, -15,Rusty Key,progression,, -16,Dwarvish Translation Guide,progression,, -17,Bridge Repair,progression,COMMUNITY_REWARD, -18,Greenhouse,progression,COMMUNITY_REWARD, -19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, -20,Minecarts Repair,useful,COMMUNITY_REWARD, -21,Bus Repair,progression,COMMUNITY_REWARD, -22,Progressive Movie Theater,progression,COMMUNITY_REWARD, -23,Stardrop,progression,, -24,Progressive Backpack,progression,, -25,Rusty Sword,filler,"WEAPON,DEPRECATED", -26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", -27,Work Boots,filler,"FOOTWEAR,DEPRECATED", -28,Wooden Blade,filler,"WEAPON,DEPRECATED", -29,Iron Dirk,filler,"WEAPON,DEPRECATED", -30,Wind Spire,filler,"WEAPON,DEPRECATED", -31,Femur,filler,"WEAPON,DEPRECATED", -32,Steel Smallsword,filler,"WEAPON,DEPRECATED", -33,Wood Club,filler,"WEAPON,DEPRECATED", -34,Elf Blade,filler,"WEAPON,DEPRECATED", -37,Slingshot,filler,"WEAPON,DEPRECATED", -38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", -39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", -40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", -41,Silver Saber,filler,"WEAPON,DEPRECATED", -42,Pirate's Sword,filler,"WEAPON,DEPRECATED", -43,Crystal Dagger,filler,"WEAPON,DEPRECATED", -44,Cutlass,filler,"WEAPON,DEPRECATED", -45,Iron Edge,filler,"WEAPON,DEPRECATED", -46,Burglar's Shank,filler,"WEAPON,DEPRECATED", -47,Wood Mallet,filler,"WEAPON,DEPRECATED", -48,Master Slingshot,filler,"WEAPON,DEPRECATED", -49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", -50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", -51,Claymore,filler,"WEAPON,DEPRECATED", -52,Templar's Blade,filler,"WEAPON,DEPRECATED", -53,Kudgel,filler,"WEAPON,DEPRECATED", -54,Shadow Dagger,filler,"WEAPON,DEPRECATED", -55,Obsidian Edge,filler,"WEAPON,DEPRECATED", -56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", -57,Wicked Kris,filler,"WEAPON,DEPRECATED", -58,Bone Sword,filler,"WEAPON,DEPRECATED", -59,Ossified Blade,filler,"WEAPON,DEPRECATED", -60,Space Boots,filler,"FOOTWEAR,DEPRECATED", -61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", -62,Steel Falchion,filler,"WEAPON,DEPRECATED", -63,The Slammer,filler,"WEAPON,DEPRECATED", -64,Skull Key,progression,, -65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, -66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, -67,Progressive Axe,progression,PROGRESSIVE_TOOLS, -68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, -69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, -70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, -71,Golden Scythe,useful,, -72,Progressive Mine Elevator,progression,, -73,Farming Level,progression,SKILL_LEVEL_UP, -74,Fishing Level,progression,SKILL_LEVEL_UP, -75,Foraging Level,progression,SKILL_LEVEL_UP, -76,Mining Level,progression,SKILL_LEVEL_UP, -77,Combat Level,progression,SKILL_LEVEL_UP, -78,Earth Obelisk,progression,WIZARD_BUILDING, -79,Water Obelisk,progression,WIZARD_BUILDING, -80,Desert Obelisk,progression,WIZARD_BUILDING, -81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", -82,Junimo Hut,useful,WIZARD_BUILDING, -83,Gold Clock,progression,WIZARD_BUILDING, -84,Progressive Coop,progression,BUILDING, -85,Progressive Barn,progression,BUILDING, -86,Well,useful,BUILDING, -87,Silo,progression,BUILDING, -88,Mill,progression,BUILDING, -89,Progressive Shed,progression,BUILDING, -90,Fish Pond,progression,BUILDING, -91,Stable,useful,BUILDING, -92,Slime Hutch,progression,BUILDING, -93,Shipping Bin,progression,BUILDING, -94,Beach Bridge,progression,, -95,Adventurer's Guild,progression,DEPRECATED, -96,Club Card,progression,, -97,Magnifying Glass,progression,, -98,Bear's Knowledge,progression,, -99,Iridium Snake Milk,useful,, -100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, -101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, -102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, -103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, -104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, -105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, -106,Galaxy Sword,filler,"WEAPON,DEPRECATED", -107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", -108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", -109,Movement Speed Bonus,progression,, -110,Luck Bonus,progression,, -111,Lava Katana,filler,"WEAPON,DEPRECATED", -112,Progressive House,progression,, -113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, -114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, -115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, -116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, -117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, -118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, -119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, -120,Traveling Merchant Stock Size,useful,, -121,Traveling Merchant Discount,useful,, -122,Return Scepter,useful,, -123,Progressive Season,progression,, -124,Spring,progression,SEASON, -125,Summer,progression,SEASON, -126,Fall,progression,SEASON, -127,Winter,progression,SEASON, -128,Amaranth Seeds,progression,CROPSANITY, -129,Artichoke Seeds,progression,CROPSANITY, -130,Beet Seeds,progression,CROPSANITY, -131,Jazz Seeds,progression,CROPSANITY, -132,Blueberry Seeds,progression,CROPSANITY, -133,Bok Choy Seeds,progression,CROPSANITY, -134,Cauliflower Seeds,progression,CROPSANITY, -135,Corn Seeds,progression,CROPSANITY, -136,Cranberry Seeds,progression,CROPSANITY, -137,Eggplant Seeds,progression,CROPSANITY, -138,Fairy Seeds,progression,CROPSANITY, -139,Garlic Seeds,progression,CROPSANITY, -140,Grape Starter,progression,CROPSANITY, -141,Bean Starter,progression,CROPSANITY, -142,Hops Starter,progression,CROPSANITY, -143,Pepper Seeds,progression,CROPSANITY, -144,Kale Seeds,progression,CROPSANITY, -145,Melon Seeds,progression,CROPSANITY, -146,Parsnip Seeds,progression,CROPSANITY, -147,Poppy Seeds,progression,CROPSANITY, -148,Potato Seeds,progression,CROPSANITY, -149,Pumpkin Seeds,progression,CROPSANITY, -150,Radish Seeds,progression,CROPSANITY, -151,Red Cabbage Seeds,progression,CROPSANITY, -152,Rhubarb Seeds,progression,CROPSANITY, -153,Starfruit Seeds,progression,CROPSANITY, -154,Strawberry Seeds,progression,CROPSANITY, -155,Spangle Seeds,progression,CROPSANITY, -156,Sunflower Seeds,progression,CROPSANITY, -157,Tomato Seeds,progression,CROPSANITY, -158,Tulip Bulb,progression,CROPSANITY, -159,Rice Shoot,progression,CROPSANITY, -160,Wheat Seeds,progression,CROPSANITY, -161,Yam Seeds,progression,CROPSANITY, -162,Cactus Seeds,progression,CROPSANITY, -163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -164,Ancient Seeds Recipe,progression,MUSEUM, -165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -166,Traveling Merchant Metal Detector,progression,MUSEUM, -167,Alex <3,progression,FRIENDSANITY, -168,Elliott <3,progression,FRIENDSANITY, -169,Harvey <3,progression,FRIENDSANITY, -170,Sam <3,progression,FRIENDSANITY, -171,Sebastian <3,progression,FRIENDSANITY, -172,Shane <3,progression,FRIENDSANITY, -173,Abigail <3,progression,FRIENDSANITY, -174,Emily <3,progression,FRIENDSANITY, -175,Haley <3,progression,FRIENDSANITY, -176,Leah <3,progression,FRIENDSANITY, -177,Maru <3,progression,FRIENDSANITY, -178,Penny <3,progression,FRIENDSANITY, -179,Caroline <3,progression,FRIENDSANITY, -180,Clint <3,progression,FRIENDSANITY, -181,Demetrius <3,progression,FRIENDSANITY, -182,Dwarf <3,progression,FRIENDSANITY, -183,Evelyn <3,progression,FRIENDSANITY, -184,George <3,progression,FRIENDSANITY, -185,Gus <3,progression,FRIENDSANITY, -186,Jas <3,progression,FRIENDSANITY, -187,Jodi <3,progression,FRIENDSANITY, -188,Kent <3,progression,FRIENDSANITY, -189,Krobus <3,progression,FRIENDSANITY, -190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", -191,Lewis <3,progression,FRIENDSANITY, -192,Linus <3,progression,FRIENDSANITY, -193,Marnie <3,progression,FRIENDSANITY, -194,Pam <3,progression,FRIENDSANITY, -195,Pierre <3,progression,FRIENDSANITY, -196,Robin <3,progression,FRIENDSANITY, -197,Sandy <3,progression,FRIENDSANITY, -198,Vincent <3,progression,FRIENDSANITY, -199,Willy <3,progression,FRIENDSANITY, -200,Wizard <3,progression,FRIENDSANITY, -201,Pet <3,progression,FRIENDSANITY, -202,Rarecrow #1,progression,"FESTIVAL,RARECROW", -203,Rarecrow #2,progression,"FESTIVAL,RARECROW", -204,Rarecrow #3,progression,"FESTIVAL,RARECROW", -205,Rarecrow #4,progression,"FESTIVAL,RARECROW", -206,Rarecrow #5,progression,"FESTIVAL,RARECROW", -207,Rarecrow #6,progression,"FESTIVAL,RARECROW", -208,Rarecrow #7,progression,"FESTIVAL,RARECROW", -209,Rarecrow #8,progression,"FESTIVAL,RARECROW", -210,Straw Hat,filler,FESTIVAL, -211,Golden Pumpkin,useful,FESTIVAL, -212,Barbed Hook,useful,FESTIVAL, -213,Dressed Spinner,useful,FESTIVAL, -214,Magnet,useful,FESTIVAL, -215,Sailor's Cap,filler,FESTIVAL, -216,Pearl,useful,FESTIVAL, -217,Cone Hat,filler,FESTIVAL, -218,Iridium Fireplace,filler,FESTIVAL, -219,Lupini: Red Eagle,filler,FESTIVAL, -220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, -221,Lupini: Solar Kingdom,filler,FESTIVAL, -222,Lupini: Clouds,filler,FESTIVAL, -223,Lupini: 1000 Years From Now,filler,FESTIVAL, -224,Lupini: Three Trees,filler,FESTIVAL, -225,Lupini: The Serpent,filler,FESTIVAL, -226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, -227,Lupini: Land Of Clay,filler,FESTIVAL, -228,Special Order Board,progression,SPECIAL_ORDER_BOARD, -229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, -230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, -231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, -232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, -233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, -234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, -235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, -236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, -237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, -239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -260,Boat Repair,progression,GINGER_ISLAND, -261,Open Professor Snail Cave,progression,GINGER_ISLAND, -262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", -271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", -275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", -276,Weather Report,useful,TV_CHANNEL, -277,Fortune Teller,useful,TV_CHANNEL, -278,Livin' Off The Land,useful,TV_CHANNEL, -279,The Queen of Sauce,progression,TV_CHANNEL, -280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, -281,Sinister Signal,filler,TV_CHANNEL, -282,Dark Talisman,progression,, -283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, -284,Cute Baby,progression,BABY, -285,Ugly Baby,progression,BABY, -286,Deluxe Scarecrow Recipe,progression,RARECROW, -287,Treehouse,progression,GINGER_ISLAND, -288,Coffee Bean,progression,CROPSANITY, -289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", -290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", -291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", -292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", -293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -294,Progressive Footwear,useful,FOOTWEAR, -295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -325,Fairy Dust Recipe,progression,, -326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, -329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -331,Jack-O-Lantern Recipe,progression,FESTIVAL, -333,Tub o' Flowers Recipe,progression,FESTIVAL, -335,Moonlight Jellies Banner,filler,FESTIVAL, -336,Starport Decal,filler,FESTIVAL, -337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, -371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", -417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -425,Gate Recipe,progression,CRAFTSANITY, -426,Wood Fence Recipe,progression,CRAFTSANITY, -427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -428,Grass Starter Recipe,progression,CRAFTSANITY, -429,Wood Floor Recipe,progression,CRAFTSANITY, -430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, -431,Straw Floor Recipe,progression,CRAFTSANITY, -432,Weathered Floor Recipe,progression,CRAFTSANITY, -433,Crystal Floor Recipe,progression,CRAFTSANITY, -434,Stone Floor Recipe,progression,CRAFTSANITY, -435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, -436,Brick Floor Recipe,progression,CRAFTSANITY, -437,Wood Path Recipe,progression,CRAFTSANITY, -438,Gravel Path Recipe,progression,CRAFTSANITY, -439,Cobblestone Path Recipe,progression,CRAFTSANITY, -440,Stepping Stone Path Recipe,progression,CRAFTSANITY, -441,Crystal Path Recipe,progression,CRAFTSANITY, -442,Wedding Ring Recipe,progression,CRAFTSANITY, -443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, -444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -445,Torch Recipe,progression,CRAFTSANITY, -446,Campfire Recipe,progression,CRAFTSANITY, -447,Wooden Brazier Recipe,progression,CRAFTSANITY, -448,Stone Brazier Recipe,progression,CRAFTSANITY, -449,Gold Brazier Recipe,progression,CRAFTSANITY, -450,Carved Brazier Recipe,progression,CRAFTSANITY, -451,Stump Brazier Recipe,progression,CRAFTSANITY, -452,Barrel Brazier Recipe,progression,CRAFTSANITY, -453,Skull Brazier Recipe,progression,CRAFTSANITY, -454,Marble Brazier Recipe,progression,CRAFTSANITY, -455,Wood Lamp-post Recipe,progression,CRAFTSANITY, -456,Iron Lamp-post Recipe,progression,CRAFTSANITY, -457,Furnace Recipe,progression,CRAFTSANITY, -458,Wicked Statue Recipe,progression,CRAFTSANITY, -459,Chest Recipe,progression,CRAFTSANITY, -460,Wood Sign Recipe,progression,CRAFTSANITY, -461,Stone Sign Recipe,progression,CRAFTSANITY, -469,Railroad Boulder Removed,progression,, -470,Fruit Bats,progression,, -471,Mushroom Boxes,progression,, -4001,Burnt Trap,trap,TRAP, -4002,Darkness Trap,trap,TRAP, -4003,Frozen Trap,trap,TRAP, -4004,Jinxed Trap,trap,TRAP, -4005,Nauseated Trap,trap,TRAP, -4006,Slimed Trap,trap,TRAP, -4007,Weakness Trap,trap,TRAP, -4008,Taxes Trap,trap,TRAP, -4009,Random Teleport Trap,trap,TRAP, -4010,The Crows Trap,trap,TRAP, -4011,Monsters Trap,trap,TRAP, -4012,Entrance Reshuffle Trap,trap,"TRAP,DEPRECATED", -4013,Debris Trap,trap,TRAP, -4014,Shuffle Trap,trap,TRAP, -4015,Temporary Winter Trap,trap,"TRAP,DEPRECATED", -4016,Pariah Trap,trap,TRAP, -4017,Drought Trap,trap,TRAP, -4018,Time Flies Trap,trap,TRAP, -4019,Babies Trap,trap,TRAP, -4020,Meow Trap,trap,TRAP, -4021,Bark Trap,trap,TRAP, -4022,Depression Trap,trap,"TRAP,DEPRECATED", -4023,Benjamin Budton Trap,trap,TRAP, -4024,Inflation Trap,trap,TRAP, -4025,Bomb Trap,trap,TRAP, -5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", -5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", -5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", -5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", -5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", -5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", -5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", -5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", -5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", -5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", -5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", -5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", -5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", -5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", -5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", -5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", -5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", -5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", -5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", -5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", -5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", -5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", -5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", -5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", -5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", -5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", -5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", -5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", -5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5207,Fiber Seeds,filler,RESOURCE_PACK, -5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5210,Quality Bobber,filler,RESOURCE_PACK, -5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", -5212,Monster Musk,filler,RESOURCE_PACK, -5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5216,Scarecrow,filler,RESOURCE_PACK, -5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", -5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", -5236,Aquatic Sanctuary,filler,RESOURCE_PACK, -5242,Exotic Double Bed,filler,RESOURCE_PACK, -5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", -5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", -5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5262,Slime Incubator,useful,RESOURCE_PACK, -5263,Slime Egg-Press,useful,RESOURCE_PACK, -5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5266,Resource Pack: 5 Staircase,filler,"RESOURCE_PACK", -5267,Auto-Petter,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5268,Auto-Grabber,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill -10002,Magic Level,progression,SKILL_LEVEL_UP,Magic -10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill -10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology -10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill -10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill -10007,Tractor Garage,useful,,Tractor Mod -10008,Woods Obelisk,progression,,DeepWoods -10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic -10010,Spell: Till,useful,MAGIC_SPELL,Magic -10011,Spell: Water,progression,MAGIC_SPELL,Magic -10012,Spell: Blink,progression,MAGIC_SPELL,Magic -10013,Spell: Evac,useful,MAGIC_SPELL,Magic -10014,Spell: Haste,useful,MAGIC_SPELL,Magic -10015,Spell: Heal,progression,MAGIC_SPELL,Magic -10016,Spell: Buff,useful,MAGIC_SPELL,Magic -10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic -10018,Spell: Fireball,progression,MAGIC_SPELL,Magic -10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic -10020,Spell: Teleport,progression,MAGIC_SPELL,Magic -10021,Spell: Lantern,useful,MAGIC_SPELL,Magic -10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic -10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic -10024,Spell: Descend,progression,MAGIC_SPELL,Magic -10025,Spell: Meteor,progression,MAGIC_SPELL,Magic -10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic -10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic -10028,Spell: Spirit,progression,MAGIC_SPELL,Magic -10029,Spell: Rewind,useful,MAGIC_SPELL,Magic -10030,Pendant of Community,progression,,DeepWoods -10031,Pendant of Elders,progression,,DeepWoods -10032,Pendant of Depths,progression,,DeepWoods -10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC -10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas -10103,Alec <3,progression,FRIENDSANITY,Alec Revisited -10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba -10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene -10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick -10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) -10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC -10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC -10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley -10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded -10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded -10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded -10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded -10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded -10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded -10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded -10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded -10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded -10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch -10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -10128,Lacey <3,progression,FRIENDSANITY,Hat Mouse Lacey -10129,Gregory <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension -10130,Sheila <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension -10131,Joel <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension -10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods -10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator -10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -10416,Special Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension -10450,Void Mint Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul -10451,Vile Ancient Fruit Seeds,progression,CROPSANITY,Distant Lands - Witch Swamp Overhaul -10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded -10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10503,Iridium Bomb,progression,,Stardew Valley Expanded -10504,Krobus' Protection,useful,,Stardew Valley Expanded -10505,Kittyfish Spell,progression,,Stardew Valley Expanded -10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded -10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded -10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded -10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded -10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded -10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded -10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded -10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10517,Grandpa's Shed,progression,,Stardew Valley Expanded -10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded -10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded -10520,Morgan's Schooling,progression,,Stardew Valley Expanded -10601,Magic Elixir Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic -10602,Travel Core Recipe,progression,CRAFTSANITY,Magic -10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10606,Neanderthal Skeleton Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10607,Pterodactyl Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10608,Pterodactyl Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10609,Pterodactyl Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10610,T-Rex Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10611,T-Rex Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10612,T-Rex Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10701,Resource Pack: 3 Magic Elixir,filler,RESOURCE_PACK,Magic -10702,Resource Pack: 3 Travel Core,filler,RESOURCE_PACK,Magic -10703,Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10704,Hardwood Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10705,Resource Pack: 3 Water Shifter,filler,RESOURCE_PACK,Archaeology -10706,Resource Pack: 5 Hardwood Display,filler,RESOURCE_PACK,Archaeology -10707,Resource Pack: 5 Wooden Display,filler,RESOURCE_PACK,Archaeology -10708,Grinder,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10709,Ancient Battery Production Station,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10710,Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded -10711,Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10712,Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10713,Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10714,Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10715,Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10716,Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +id,name,classification,groups,mod_name +0,Joja Cola,filler,TRASH, +15,Rusty Key,progression,, +16,Dwarvish Translation Guide,progression,, +17,Bridge Repair,progression,COMMUNITY_REWARD, +18,Greenhouse,progression,COMMUNITY_REWARD, +19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, +20,Minecarts Repair,useful,COMMUNITY_REWARD, +21,Bus Repair,progression,COMMUNITY_REWARD, +22,Progressive Movie Theater,progression,COMMUNITY_REWARD, +23,Stardrop,progression,, +24,Progressive Backpack,progression,, +25,Rusty Sword,filler,"WEAPON,DEPRECATED", +26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", +27,Work Boots,filler,"FOOTWEAR,DEPRECATED", +28,Wooden Blade,filler,"WEAPON,DEPRECATED", +29,Iron Dirk,filler,"WEAPON,DEPRECATED", +30,Wind Spire,filler,"WEAPON,DEPRECATED", +31,Femur,filler,"WEAPON,DEPRECATED", +32,Steel Smallsword,filler,"WEAPON,DEPRECATED", +33,Wood Club,filler,"WEAPON,DEPRECATED", +34,Elf Blade,filler,"WEAPON,DEPRECATED", +37,Slingshot,filler,"WEAPON,DEPRECATED", +38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", +39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", +40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", +41,Silver Saber,filler,"WEAPON,DEPRECATED", +42,Pirate's Sword,filler,"WEAPON,DEPRECATED", +43,Crystal Dagger,filler,"WEAPON,DEPRECATED", +44,Cutlass,filler,"WEAPON,DEPRECATED", +45,Iron Edge,filler,"WEAPON,DEPRECATED", +46,Burglar's Shank,filler,"WEAPON,DEPRECATED", +47,Wood Mallet,filler,"WEAPON,DEPRECATED", +48,Master Slingshot,filler,"WEAPON,DEPRECATED", +49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", +50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", +51,Claymore,filler,"WEAPON,DEPRECATED", +52,Templar's Blade,filler,"WEAPON,DEPRECATED", +53,Kudgel,filler,"WEAPON,DEPRECATED", +54,Shadow Dagger,filler,"WEAPON,DEPRECATED", +55,Obsidian Edge,filler,"WEAPON,DEPRECATED", +56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", +57,Wicked Kris,filler,"WEAPON,DEPRECATED", +58,Bone Sword,filler,"WEAPON,DEPRECATED", +59,Ossified Blade,filler,"WEAPON,DEPRECATED", +60,Space Boots,filler,"FOOTWEAR,DEPRECATED", +61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", +62,Steel Falchion,filler,"WEAPON,DEPRECATED", +63,The Slammer,filler,"WEAPON,DEPRECATED", +64,Skull Key,progression,, +65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, +66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, +67,Progressive Axe,progression,PROGRESSIVE_TOOLS, +68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, +69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, +70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, +71,Golden Scythe,useful,, +72,Progressive Mine Elevator,progression,, +73,Farming Level,progression,SKILL_LEVEL_UP, +74,Fishing Level,progression,SKILL_LEVEL_UP, +75,Foraging Level,progression,SKILL_LEVEL_UP, +76,Mining Level,progression,SKILL_LEVEL_UP, +77,Combat Level,progression,SKILL_LEVEL_UP, +78,Earth Obelisk,progression,WIZARD_BUILDING, +79,Water Obelisk,progression,WIZARD_BUILDING, +80,Desert Obelisk,progression,WIZARD_BUILDING, +81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", +82,Junimo Hut,useful,WIZARD_BUILDING, +83,Gold Clock,progression,WIZARD_BUILDING, +84,Progressive Coop,progression,BUILDING, +85,Progressive Barn,progression,BUILDING, +86,Well,useful,BUILDING, +87,Silo,progression,BUILDING, +88,Mill,progression,BUILDING, +89,Progressive Shed,progression,BUILDING, +90,Fish Pond,progression,BUILDING, +91,Stable,useful,BUILDING, +92,Slime Hutch,progression,BUILDING, +93,Shipping Bin,progression,BUILDING, +94,Beach Bridge,progression,, +95,Adventurer's Guild,progression,DEPRECATED, +96,Club Card,progression,, +97,Magnifying Glass,progression,, +98,Bear's Knowledge,progression,, +99,Iridium Snake Milk,useful,, +100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, +101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, +102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, +103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, +104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, +105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, +106,Galaxy Sword,filler,"WEAPON,DEPRECATED", +107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", +108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", +109,Movement Speed Bonus,progression,, +110,Luck Bonus,progression,, +111,Lava Katana,filler,"WEAPON,DEPRECATED", +112,Progressive House,progression,, +113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, +114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, +115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, +116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, +117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, +118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, +119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, +120,Traveling Merchant Stock Size,useful,, +121,Traveling Merchant Discount,useful,, +122,Return Scepter,useful,, +123,Progressive Season,progression,, +124,Spring,progression,SEASON, +125,Summer,progression,SEASON, +126,Fall,progression,SEASON, +127,Winter,progression,SEASON, +128,Amaranth Seeds,progression,CROPSANITY, +129,Artichoke Seeds,progression,CROPSANITY, +130,Beet Seeds,progression,CROPSANITY, +131,Jazz Seeds,progression,CROPSANITY, +132,Blueberry Seeds,progression,CROPSANITY, +133,Bok Choy Seeds,progression,CROPSANITY, +134,Cauliflower Seeds,progression,CROPSANITY, +135,Corn Seeds,progression,CROPSANITY, +136,Cranberry Seeds,progression,CROPSANITY, +137,Eggplant Seeds,progression,CROPSANITY, +138,Fairy Seeds,progression,CROPSANITY, +139,Garlic Seeds,progression,CROPSANITY, +140,Grape Starter,progression,CROPSANITY, +141,Bean Starter,progression,CROPSANITY, +142,Hops Starter,progression,CROPSANITY, +143,Pepper Seeds,progression,CROPSANITY, +144,Kale Seeds,progression,CROPSANITY, +145,Melon Seeds,progression,CROPSANITY, +146,Parsnip Seeds,progression,CROPSANITY, +147,Poppy Seeds,progression,CROPSANITY, +148,Potato Seeds,progression,CROPSANITY, +149,Pumpkin Seeds,progression,CROPSANITY, +150,Radish Seeds,progression,CROPSANITY, +151,Red Cabbage Seeds,progression,CROPSANITY, +152,Rhubarb Seeds,progression,CROPSANITY, +153,Starfruit Seeds,progression,CROPSANITY, +154,Strawberry Seeds,progression,CROPSANITY, +155,Spangle Seeds,progression,CROPSANITY, +156,Sunflower Seeds,progression,CROPSANITY, +157,Tomato Seeds,progression,CROPSANITY, +158,Tulip Bulb,progression,CROPSANITY, +159,Rice Shoot,progression,CROPSANITY, +160,Wheat Seeds,progression,CROPSANITY, +161,Yam Seeds,progression,CROPSANITY, +162,Cactus Seeds,progression,CROPSANITY, +163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +164,Ancient Seeds Recipe,progression,MUSEUM, +165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +166,Traveling Merchant Metal Detector,progression,MUSEUM, +167,Alex <3,progression,FRIENDSANITY, +168,Elliott <3,progression,FRIENDSANITY, +169,Harvey <3,progression,FRIENDSANITY, +170,Sam <3,progression,FRIENDSANITY, +171,Sebastian <3,progression,FRIENDSANITY, +172,Shane <3,progression,FRIENDSANITY, +173,Abigail <3,progression,FRIENDSANITY, +174,Emily <3,progression,FRIENDSANITY, +175,Haley <3,progression,FRIENDSANITY, +176,Leah <3,progression,FRIENDSANITY, +177,Maru <3,progression,FRIENDSANITY, +178,Penny <3,progression,FRIENDSANITY, +179,Caroline <3,progression,FRIENDSANITY, +180,Clint <3,progression,FRIENDSANITY, +181,Demetrius <3,progression,FRIENDSANITY, +182,Dwarf <3,progression,FRIENDSANITY, +183,Evelyn <3,progression,FRIENDSANITY, +184,George <3,progression,FRIENDSANITY, +185,Gus <3,progression,FRIENDSANITY, +186,Jas <3,progression,FRIENDSANITY, +187,Jodi <3,progression,FRIENDSANITY, +188,Kent <3,progression,FRIENDSANITY, +189,Krobus <3,progression,FRIENDSANITY, +190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", +191,Lewis <3,progression,FRIENDSANITY, +192,Linus <3,progression,FRIENDSANITY, +193,Marnie <3,progression,FRIENDSANITY, +194,Pam <3,progression,FRIENDSANITY, +195,Pierre <3,progression,FRIENDSANITY, +196,Robin <3,progression,FRIENDSANITY, +197,Sandy <3,progression,FRIENDSANITY, +198,Vincent <3,progression,FRIENDSANITY, +199,Willy <3,progression,FRIENDSANITY, +200,Wizard <3,progression,FRIENDSANITY, +201,Pet <3,progression,FRIENDSANITY, +202,Rarecrow #1,progression,"FESTIVAL,RARECROW", +203,Rarecrow #2,progression,"FESTIVAL,RARECROW", +204,Rarecrow #3,progression,"FESTIVAL,RARECROW", +205,Rarecrow #4,progression,"FESTIVAL,RARECROW", +206,Rarecrow #5,progression,"FESTIVAL,RARECROW", +207,Rarecrow #6,progression,"FESTIVAL,RARECROW", +208,Rarecrow #7,progression,"FESTIVAL,RARECROW", +209,Rarecrow #8,progression,"FESTIVAL,RARECROW", +210,Straw Hat,filler,FESTIVAL, +211,Golden Pumpkin,useful,FESTIVAL, +212,Barbed Hook,useful,FESTIVAL, +213,Dressed Spinner,useful,FESTIVAL, +214,Magnet,useful,FESTIVAL, +215,Sailor's Cap,filler,FESTIVAL, +216,Pearl,useful,FESTIVAL, +217,Cone Hat,filler,FESTIVAL, +218,Iridium Fireplace,filler,FESTIVAL, +219,Lupini: Red Eagle,filler,FESTIVAL, +220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, +221,Lupini: Solar Kingdom,filler,FESTIVAL, +222,Lupini: Clouds,filler,FESTIVAL, +223,Lupini: 1000 Years From Now,filler,FESTIVAL, +224,Lupini: Three Trees,filler,FESTIVAL, +225,Lupini: The Serpent,filler,FESTIVAL, +226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, +227,Lupini: Land Of Clay,filler,FESTIVAL, +228,Special Order Board,progression,SPECIAL_ORDER_BOARD, +229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, +230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, +231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, +232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, +233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, +234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, +235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, +236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, +237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, +239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +260,Boat Repair,progression,GINGER_ISLAND, +261,Open Professor Snail Cave,progression,GINGER_ISLAND, +262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", +271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", +275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", +276,Weather Report,useful,TV_CHANNEL, +277,Fortune Teller,useful,TV_CHANNEL, +278,Livin' Off The Land,useful,TV_CHANNEL, +279,The Queen of Sauce,progression,TV_CHANNEL, +280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, +281,Sinister Signal,filler,TV_CHANNEL, +282,Dark Talisman,progression,, +283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, +284,Cute Baby,progression,BABY, +285,Ugly Baby,progression,BABY, +286,Deluxe Scarecrow Recipe,progression,RARECROW, +287,Treehouse,progression,GINGER_ISLAND, +288,Coffee Bean,progression,CROPSANITY, +289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +294,Progressive Footwear,useful,FOOTWEAR, +295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +325,Fairy Dust Recipe,progression,, +326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, +329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +331,Jack-O-Lantern Recipe,progression,FESTIVAL, +333,Tub o' Flowers Recipe,progression,FESTIVAL, +335,Moonlight Jellies Banner,filler,FESTIVAL, +336,Starport Decal,filler,FESTIVAL, +337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, +371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", +417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +425,Gate Recipe,progression,CRAFTSANITY, +426,Wood Fence Recipe,progression,CRAFTSANITY, +427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +428,Grass Starter Recipe,progression,CRAFTSANITY, +429,Wood Floor Recipe,progression,CRAFTSANITY, +430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, +431,Straw Floor Recipe,progression,CRAFTSANITY, +432,Weathered Floor Recipe,progression,CRAFTSANITY, +433,Crystal Floor Recipe,progression,CRAFTSANITY, +434,Stone Floor Recipe,progression,CRAFTSANITY, +435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, +436,Brick Floor Recipe,progression,CRAFTSANITY, +437,Wood Path Recipe,progression,CRAFTSANITY, +438,Gravel Path Recipe,progression,CRAFTSANITY, +439,Cobblestone Path Recipe,progression,CRAFTSANITY, +440,Stepping Stone Path Recipe,progression,CRAFTSANITY, +441,Crystal Path Recipe,progression,CRAFTSANITY, +442,Wedding Ring Recipe,progression,CRAFTSANITY, +443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, +444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +445,Torch Recipe,progression,CRAFTSANITY, +446,Campfire Recipe,progression,CRAFTSANITY, +447,Wooden Brazier Recipe,progression,CRAFTSANITY, +448,Stone Brazier Recipe,progression,CRAFTSANITY, +449,Gold Brazier Recipe,progression,CRAFTSANITY, +450,Carved Brazier Recipe,progression,CRAFTSANITY, +451,Stump Brazier Recipe,progression,CRAFTSANITY, +452,Barrel Brazier Recipe,progression,CRAFTSANITY, +453,Skull Brazier Recipe,progression,CRAFTSANITY, +454,Marble Brazier Recipe,progression,CRAFTSANITY, +455,Wood Lamp-post Recipe,progression,CRAFTSANITY, +456,Iron Lamp-post Recipe,progression,CRAFTSANITY, +457,Furnace Recipe,progression,CRAFTSANITY, +458,Wicked Statue Recipe,progression,CRAFTSANITY, +459,Chest Recipe,progression,CRAFTSANITY, +460,Wood Sign Recipe,progression,CRAFTSANITY, +461,Stone Sign Recipe,progression,CRAFTSANITY, +469,Railroad Boulder Removed,progression,, +470,Fruit Bats,progression,, +471,Mushroom Boxes,progression,, +4001,Burnt Trap,trap,TRAP, +4002,Darkness Trap,trap,TRAP, +4003,Frozen Trap,trap,TRAP, +4004,Jinxed Trap,trap,TRAP, +4005,Nauseated Trap,trap,TRAP, +4006,Slimed Trap,trap,TRAP, +4007,Weakness Trap,trap,TRAP, +4008,Taxes Trap,trap,TRAP, +4009,Random Teleport Trap,trap,TRAP, +4010,The Crows Trap,trap,TRAP, +4011,Monsters Trap,trap,TRAP, +4012,Entrance Reshuffle Trap,trap,"TRAP,DEPRECATED", +4013,Debris Trap,trap,TRAP, +4014,Shuffle Trap,trap,TRAP, +4015,Temporary Winter Trap,trap,"TRAP,DEPRECATED", +4016,Pariah Trap,trap,TRAP, +4017,Drought Trap,trap,TRAP, +4018,Time Flies Trap,trap,TRAP, +4019,Babies Trap,trap,TRAP, +4020,Meow Trap,trap,TRAP, +4021,Bark Trap,trap,TRAP, +4022,Depression Trap,trap,"TRAP,DEPRECATED", +4023,Benjamin Budton Trap,trap,TRAP, +4024,Inflation Trap,trap,TRAP, +4025,Bomb Trap,trap,TRAP, +5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", +5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", +5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", +5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", +5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", +5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", +5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", +5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", +5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", +5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", +5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", +5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", +5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", +5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", +5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", +5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", +5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", +5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", +5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", +5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", +5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", +5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", +5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", +5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", +5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", +5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", +5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", +5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", +5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5207,Fiber Seeds,filler,RESOURCE_PACK, +5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5210,Quality Bobber,filler,RESOURCE_PACK, +5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", +5212,Monster Musk,filler,RESOURCE_PACK, +5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5216,Scarecrow,filler,RESOURCE_PACK, +5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", +5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", +5236,Aquatic Sanctuary,filler,RESOURCE_PACK, +5242,Exotic Double Bed,filler,RESOURCE_PACK, +5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", +5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", +5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5262,Slime Incubator,useful,RESOURCE_PACK, +5263,Slime Egg-Press,useful,RESOURCE_PACK, +5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5266,Resource Pack: 5 Staircase,filler,"RESOURCE_PACK", +5267,Auto-Petter,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5268,Auto-Grabber,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill +10002,Magic Level,progression,SKILL_LEVEL_UP,Magic +10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill +10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology +10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill +10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill +10007,Tractor Garage,useful,,Tractor Mod +10008,Woods Obelisk,progression,,DeepWoods +10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic +10010,Spell: Till,useful,MAGIC_SPELL,Magic +10011,Spell: Water,progression,MAGIC_SPELL,Magic +10012,Spell: Blink,progression,MAGIC_SPELL,Magic +10013,Spell: Evac,useful,MAGIC_SPELL,Magic +10014,Spell: Haste,useful,MAGIC_SPELL,Magic +10015,Spell: Heal,progression,MAGIC_SPELL,Magic +10016,Spell: Buff,useful,MAGIC_SPELL,Magic +10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic +10018,Spell: Fireball,progression,MAGIC_SPELL,Magic +10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic +10020,Spell: Teleport,progression,MAGIC_SPELL,Magic +10021,Spell: Lantern,useful,MAGIC_SPELL,Magic +10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic +10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic +10024,Spell: Descend,progression,MAGIC_SPELL,Magic +10025,Spell: Meteor,progression,MAGIC_SPELL,Magic +10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic +10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic +10028,Spell: Spirit,progression,MAGIC_SPELL,Magic +10029,Spell: Rewind,useful,MAGIC_SPELL,Magic +10030,Pendant of Community,progression,,DeepWoods +10031,Pendant of Elders,progression,,DeepWoods +10032,Pendant of Depths,progression,,DeepWoods +10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC +10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas +10103,Alec <3,progression,FRIENDSANITY,Alec Revisited +10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba +10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene +10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick +10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) +10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC +10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC +10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley +10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded +10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded +10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded +10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded +10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded +10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded +10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded +10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded +10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch +10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +10128,Lacey <3,progression,FRIENDSANITY,Hat Mouse Lacey +10129,Gregory <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10130,Sheila <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10131,Joel <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods +10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator +10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +10416,Special Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension +10450,Void Mint Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul +10451,Vile Ancient Fruit Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul +10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded +10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10503,Iridium Bomb,progression,,Stardew Valley Expanded +10504,Krobus' Protection,useful,,Stardew Valley Expanded +10505,Kittyfish Spell,progression,,Stardew Valley Expanded +10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded +10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded +10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded +10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded +10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded +10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10517,Grandpa's Shed,progression,,Stardew Valley Expanded +10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded +10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded +10520,Morgan's Schooling,progression,,Stardew Valley Expanded +10601,Magic Elixir Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic +10602,Travel Core Recipe,progression,CRAFTSANITY,Magic +10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10606,Neanderthal Skeleton Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10607,Pterodactyl Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10608,Pterodactyl Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10609,Pterodactyl Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10610,T-Rex Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10611,T-Rex Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10612,T-Rex Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10701,Resource Pack: 3 Magic Elixir,filler,RESOURCE_PACK,Magic +10702,Resource Pack: 3 Travel Core,filler,RESOURCE_PACK,Magic +10703,Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10704,Hardwood Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10705,Resource Pack: 3 Water Shifter,filler,RESOURCE_PACK,Archaeology +10706,Resource Pack: 5 Hardwood Display,filler,RESOURCE_PACK,Archaeology +10707,Resource Pack: 5 Wooden Display,filler,RESOURCE_PACK,Archaeology +10708,Grinder,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10709,Ancient Battery Production Station,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10710,Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded +10711,Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10712,Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10713,Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10714,Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10715,Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10716,Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/logic/item_logic.py b/worlds/stardew_valley/mods/logic/item_logic.py index c418dc1e40f8..ffe7169f6e56 100644 --- a/worlds/stardew_valley/mods/logic/item_logic.py +++ b/worlds/stardew_valley/mods/logic/item_logic.py @@ -11,6 +11,7 @@ from ...logic.has_logic import HasLogicMixin from ...logic.money_logic import MoneyLogicMixin from ...logic.museum_logic import MuseumLogicMixin +from ...logic.quest_logic import QuestLogicMixin from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin @@ -33,6 +34,7 @@ from ...strings.metal_names import all_fossils, all_artifacts, Ore, ModFossil, ModArtifact from ...strings.monster_drop_names import ModLoot, Loot from ...strings.performance_names import Performance +from ...strings.quest_names import ModQuest from ...strings.region_names import Region, SVERegion, DeepWoodsRegion, BoardingHouseRegion from ...strings.season_names import Season from ...strings.seed_names import SVESeed, DistantLandsSeed @@ -51,7 +53,7 @@ def __init__(self, *args, **kwargs): class ModItemLogic(BaseLogic[Union[CombatLogicMixin, ReceivedLogicMixin, CropLogicMixin, CookingLogicMixin, FishingLogicMixin, HasLogicMixin, MoneyLogicMixin, -RegionLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin, SkillLogicMixin, TimeLogicMixin]]): +RegionLogicMixin, SeasonLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, ToolLogicMixin, CraftingLogicMixin, SkillLogicMixin, TimeLogicMixin, QuestLogicMixin]]): def get_modded_item_rules(self) -> Dict[str, StardewRule]: items = dict() @@ -204,8 +206,8 @@ def get_distant_lands_item_rules(self): return { DistantLandsForageable.swamp_herb: self.logic.region.can_reach(Region.witch_swamp), DistantLandsForageable.brown_amanita: self.logic.region.can_reach(Region.witch_swamp), - DistantLandsSeed.vile_ancient_fruit: self.logic.money.can_spend_at(Region.oasis, 50) & self.has_seed_unlocked(DistantLandsSeed.vile_ancient_fruit), - DistantLandsSeed.void_mint: self.logic.money.can_spend_at(Region.oasis, 80) & self.has_seed_unlocked(DistantLandsSeed.void_mint), + DistantLandsSeed.vile_ancient_fruit: self.logic.quest.can_complete_quest(ModQuest.WitchOrder) | self.logic.quest.can_complete_quest(ModQuest.CorruptedCropsTask), + DistantLandsSeed.void_mint: self.logic.quest.can_complete_quest(ModQuest.WitchOrder) | self.logic.quest.can_complete_quest(ModQuest.CorruptedCropsTask), DistantLandsCrop.void_mint: self.logic.season.has_any_not_winter() & self.logic.has(DistantLandsSeed.void_mint), DistantLandsCrop.vile_ancient_fruit: self.logic.season.has_any_not_winter() & self.logic.has(DistantLandsSeed.vile_ancient_fruit), } From 78a202af97694ac7ec3609d019cd3dbaf0357148 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 23:05:07 -0600 Subject: [PATCH 453/482] Add BH craft locations --- worlds/stardew_valley/data/locations.csv | 5877 +++++++++++----------- 1 file changed, 2942 insertions(+), 2935 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 0d1b78d95246..dfb2691a752c 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1,2935 +1,2942 @@ -id,region,name,tags,mod_name -1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", -32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", -34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", -35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", -37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", -39,Fish Tank,Deep Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -47,Boiler Room,Paleontologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", -48,Boiler Room,Archaeologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", -49,Pantry,Slime Farmer Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -58,Fish Tank,Trash Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -69,Boiler Room,Recycling Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -73,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -74,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -75,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -76,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -77,Vault,250g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -78,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -79,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -80,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -81,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -82,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -83,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -84,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -85,Vault,"4,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -87,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -88,Vault,"9,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -89,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -90,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -91,Vault,"18,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -92,Vault,"20,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -93,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -94,Vault,"40,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -95,Vault,"45,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -96,Vault,"100,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -97,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -98,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -99,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -100,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -101,Pierre's General Store,Large Pack,BACKPACK, -102,Pierre's General Store,Deluxe Pack,BACKPACK, -103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", -202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", -203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", -204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", -205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", -206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", -207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", -208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", -209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", -210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", -211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", -212,Quarry Mine,Grim Reaper statue,MANDATORY, -213,The Mines,The Mines Entrance Cutscene,MANDATORY, -214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, -215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, -216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, -217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, -218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, -219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, -220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, -221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, -222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, -223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, -224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, -225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, -226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, -227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, -228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, -229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, -230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, -231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, -232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, -233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, -234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, -235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, -236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, -237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, -250,Shipping,Demetrius's Breakthrough,MANDATORY -251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", -301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", -302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", -303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", -304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", -305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", -306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", -307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", -308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", -309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", -310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", -311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", -332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", -333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", -334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", -335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", -336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", -337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", -338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", -339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", -340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", -341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, -402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, -403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, -404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, -405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, -406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, -407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, -408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, -409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, -410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, -411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, -412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, -413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, -414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, -415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, -416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, -417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, -418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, -501,Town,Introductions,"STORY_QUEST", -502,Town,How To Win Friends,"STORY_QUEST", -503,Farm,Getting Started,"STORY_QUEST", -504,Farm,Raising Animals,"STORY_QUEST", -505,Farm,Advancement,"STORY_QUEST", -506,Museum,Archaeology,"STORY_QUEST", -507,Wizard Tower,Meet The Wizard,"STORY_QUEST", -508,The Mines - Floor 5,Forging Ahead,"STORY_QUEST", -509,The Mines - Floor 10,Smelting,"STORY_QUEST", -510,The Mines - Floor 15,Initiation,"STORY_QUEST", -511,Mountain,Robin's Lost Axe,"STORY_QUEST", -512,Town,Jodi's Request,"STORY_QUEST", -513,Town,"Mayor's ""Shorts""","STORY_QUEST", -514,Mountain,Blackberry Basket,"STORY_QUEST", -515,Marnie's Ranch,Marnie's Request,"STORY_QUEST", -516,Town,Pam Is Thirsty,"STORY_QUEST", -517,Wizard Tower,A Dark Reagent,"STORY_QUEST", -518,Forest,Cow's Delight,"STORY_QUEST", -519,Skull Cavern Entrance,The Skull Key,"STORY_QUEST", -520,Mountain,Crop Research,"STORY_QUEST", -521,Alex's House,Knee Therapy,"STORY_QUEST", -522,Mountain,Robin's Request,"STORY_QUEST", -523,Skull Cavern Floor 25,Qi's Challenge,"STORY_QUEST", -524,Desert,The Mysterious Qi,"STORY_QUEST", -525,Town,Carving Pumpkins,"STORY_QUEST", -526,Town,A Winter Mystery,"STORY_QUEST", -527,Secret Woods,Strange Note,"STORY_QUEST", -528,Skull Cavern Floor 100,Cryptic Note,"STORY_QUEST", -529,Town,Fresh Fruit,"STORY_QUEST", -530,Mountain,Aquatic Research,"STORY_QUEST", -531,Town,A Soldier's Star,"STORY_QUEST", -532,Town,Mayor's Need,"STORY_QUEST", -533,Saloon,Wanted: Lobster,"STORY_QUEST", -534,Town,Pam Needs Juice,"STORY_QUEST", -535,Sam's House,Fish Casserole,"STORY_QUEST", -536,Beach,Catch A Squid,"STORY_QUEST", -537,Saloon,Fish Stew,"STORY_QUEST", -538,Pierre's General Store,Pierre's Notice,"STORY_QUEST", -539,Clint's Blacksmith,Clint's Attempt,"STORY_QUEST", -540,Town,A Favor For Clint,"STORY_QUEST", -541,Wizard Tower,Staff Of Power,"STORY_QUEST", -542,Town,Granny's Gift,"STORY_QUEST", -543,Desert,Exotic Spirits,"STORY_QUEST", -544,Fishing,Catch a Lingcod,"STORY_QUEST", -545,Island West,The Pirate's Wife,"GINGER_ISLAND,STORY_QUEST", -546,Mutant Bug Lair,Dark Talisman,"STORY_QUEST", -547,Witch's Swamp,Goblin Problem,"STORY_QUEST", -548,Witch's Hut,Magic Ink,"STORY_QUEST", -601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", -602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", -603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", -604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", -605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", -606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", -607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", -608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", -609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", -610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", -611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", -612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", -613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", -614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", -615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", -616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", -617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", -618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", -619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", -620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", -621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", -701,Secret Woods,Old Master Cannoli,MANDATORY, -702,Beach,Beach Bridge Repair,MANDATORY, -703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,BABY, -705,Farmhouse,Have Another Baby,BABY, -706,Farmhouse,Spouse Stardrop,, -707,Sewer,Krobus Stardrop,MANDATORY, -801,Forest,Help Wanted: Gathering 1,HELP_WANTED, -802,Forest,Help Wanted: Gathering 2,HELP_WANTED, -803,Forest,Help Wanted: Gathering 3,HELP_WANTED, -804,Forest,Help Wanted: Gathering 4,HELP_WANTED, -805,Forest,Help Wanted: Gathering 5,HELP_WANTED, -806,Forest,Help Wanted: Gathering 6,HELP_WANTED, -807,Forest,Help Wanted: Gathering 7,HELP_WANTED, -808,Forest,Help Wanted: Gathering 8,HELP_WANTED, -811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,The Mines - Floor 15,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,The Mines - Floor 25,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,The Mines - Floor 35,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,The Mines - Floor 45,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,The Mines - Floor 55,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,The Mines - Floor 65,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,The Mines - Floor 75,Help Wanted: Slay Monsters 8,HELP_WANTED, -821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, -822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, -823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, -824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, -825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, -826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, -827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, -828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, -841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, -842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, -843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, -844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, -845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, -846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, -847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, -848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, -849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, -850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, -851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, -852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, -853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, -854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, -855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, -856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, -857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, -858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, -859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, -860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, -861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, -862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, -863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, -864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, -865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, -866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, -867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, -868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, -869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, -870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, -871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, -872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, -901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", -902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", -903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", -911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", -912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", -913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", -921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", -942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", -943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", -951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", -952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", -953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", -961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", -962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", -963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", -1001,Fishing,Fishsanity: Carp,FISHSANITY, -1002,Fishing,Fishsanity: Herring,FISHSANITY, -1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, -1004,Fishing,Fishsanity: Anchovy,FISHSANITY, -1005,Fishing,Fishsanity: Sardine,FISHSANITY, -1006,Fishing,Fishsanity: Sunfish,FISHSANITY, -1007,Fishing,Fishsanity: Perch,FISHSANITY, -1008,Fishing,Fishsanity: Chub,FISHSANITY, -1009,Fishing,Fishsanity: Bream,FISHSANITY, -1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, -1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, -1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, -1013,Fishing,Fishsanity: Walleye,FISHSANITY, -1014,Fishing,Fishsanity: Shad,FISHSANITY, -1015,Fishing,Fishsanity: Bullhead,FISHSANITY, -1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, -1017,Fishing,Fishsanity: Salmon,FISHSANITY, -1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, -1019,Fishing,Fishsanity: Tilapia,FISHSANITY, -1020,Fishing,Fishsanity: Woodskip,FISHSANITY, -1021,Fishing,Fishsanity: Flounder,FISHSANITY, -1022,Fishing,Fishsanity: Halibut,FISHSANITY, -1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", -1024,Fishing,Fishsanity: Slimejack,FISHSANITY, -1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, -1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, -1027,Fishing,Fishsanity: Pike,FISHSANITY, -1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, -1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", -1030,Fishing,Fishsanity: Albacore,FISHSANITY, -1031,Fishing,Fishsanity: Sandfish,FISHSANITY, -1032,Fishing,Fishsanity: Stonefish,FISHSANITY, -1033,Fishing,Fishsanity: Tuna,FISHSANITY, -1034,Fishing,Fishsanity: Eel,FISHSANITY, -1035,Fishing,Fishsanity: Catfish,FISHSANITY, -1036,Fishing,Fishsanity: Squid,FISHSANITY, -1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, -1038,Fishing,Fishsanity: Dorado,FISHSANITY, -1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, -1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, -1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, -1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", -1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, -1044,Fishing,Fishsanity: Lingcod,FISHSANITY, -1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, -1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, -1047,Fishing,Fishsanity: Octopus,FISHSANITY, -1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, -1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, -1050,Fishing,Fishsanity: Blobfish,FISHSANITY, -1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, -1052,Fishing,Fishsanity: Angler,FISHSANITY, -1053,Fishing,Fishsanity: Legend,FISHSANITY, -1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, -1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, -1056,Town,Fishsanity: Crayfish,FISHSANITY, -1057,Town,Fishsanity: Snail,FISHSANITY, -1058,Town,Fishsanity: Periwinkle,FISHSANITY, -1059,Beach,Fishsanity: Lobster,FISHSANITY, -1060,Beach,Fishsanity: Clam,FISHSANITY, -1061,Beach,Fishsanity: Crab,FISHSANITY, -1062,Beach,Fishsanity: Cockle,FISHSANITY, -1063,Beach,Fishsanity: Mussel,FISHSANITY, -1064,Beach,Fishsanity: Shrimp,FISHSANITY, -1065,Beach,Fishsanity: Oyster,FISHSANITY, -1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, -1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, -1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, -1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, -1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, -1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, -1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, -1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, -1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, -1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, -1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, -1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, -1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, -1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, -1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, -1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, -1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, -1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, -1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, -1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, -1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, -1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, -1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, -1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, -1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, -1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, -1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, -1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, -1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, -1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, -1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, -1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, -1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, -1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, -1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, -1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, -1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, -1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, -1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, -1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, -1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, -1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, -1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, -1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, -1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, -1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, -1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", -1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, -1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, -1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, -1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, -1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, -1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, -1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, -1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, -1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, -1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, -1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, -1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, -1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, -1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, -1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, -1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, -1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, -1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, -1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, -1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, -1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, -1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, -1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, -1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, -1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, -1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, -1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, -1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, -1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, -1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, -1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, -1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, -1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, -1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, -1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, -1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, -1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, -1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, -1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, -1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, -1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, -1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, -1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, -1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, -1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, -1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, -1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, -1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, -1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, -1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, -1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, -1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, -1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, -1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, -1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, -1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, -1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, -1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, -1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, -1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, -1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, -1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, -1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, -1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, -1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, -1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, -1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, -1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, -1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, -1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, -1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, -1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, -1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, -1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, -1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, -1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, -1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, -1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, -1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, -1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, -1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, -1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, -1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, -1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, -1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, -1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, -1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, -1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, -1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, -1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, -1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, -1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, -1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, -1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, -1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, -1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, -1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, -1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, -1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, -1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, -1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, -1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, -1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, -1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, -1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, -1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, -1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, -1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, -1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, -1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, -1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, -1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, -1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, -1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, -1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, -1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, -1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, -1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, -1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, -1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, -1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, -1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, -1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, -1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, -1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, -1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, -1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, -1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, -1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, -1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, -1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, -1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, -1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, -1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, -1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, -1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, -1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, -1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, -1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, -1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, -1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, -1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, -1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, -1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, -1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, -1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, -1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, -1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, -1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, -1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, -1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, -1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, -1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, -1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, -1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, -1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, -1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, -1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, -1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, -1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, -1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, -1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, -1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, -1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, -1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, -1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, -1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, -1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, -1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, -1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, -1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, -1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, -1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, -1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, -1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, -1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, -1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, -1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, -1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, -1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, -1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, -1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, -1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, -1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, -1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, -1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, -1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, -1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, -1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, -1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, -1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, -1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, -1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, -1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, -1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, -1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, -1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, -1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, -1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, -1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, -1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, -1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, -1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, -1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, -1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, -1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, -1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, -1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, -1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, -1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, -1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, -1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, -1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, -1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, -1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, -1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, -1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, -1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, -1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, -1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, -1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, -1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, -1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, -1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, -1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, -1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, -1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, -1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, -1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, -1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, -1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, -1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, -1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, -1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, -1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, -1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, -1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, -1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, -1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, -1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, -1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, -1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, -1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, -1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, -1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, -1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, -1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, -1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, -1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, -1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, -1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, -1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, -1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, -1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, -1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, -1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, -1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, -1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, -1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, -1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, -1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, -1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, -1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, -1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, -1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, -1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, -1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, -1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, -1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, -1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, -1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, -1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, -1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, -1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, -1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, -1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, -1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, -1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, -1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, -1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, -1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, -1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, -1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, -1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, -1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, -1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, -1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, -1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, -1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, -1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, -1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, -1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, -1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, -1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, -1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, -1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, -1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, -1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, -1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, -1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, -1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, -1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, -1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, -1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, -1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, -1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, -1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, -1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, -1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, -1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, -1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, -1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, -1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, -1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, -1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, -1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, -1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, -1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, -1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, -1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, -1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, -1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, -1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, -1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, -1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, -1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, -1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, -1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, -1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, -1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, -1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, -1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, -1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, -1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, -1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, -1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, -1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, -1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, -1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, -1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, -1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, -1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, -1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, -1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, -1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, -1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, -1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, -1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, -1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, -1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, -1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, -1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, -1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, -1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, -1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", -1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", -1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", -1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", -1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", -1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", -1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", -1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", -1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", -1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", -1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, -1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, -1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, -1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, -1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, -1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, -1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, -1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, -1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, -1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, -1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, -1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, -1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, -1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, -1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, -1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, -1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, -1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, -1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, -1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, -1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, -1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, -1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, -1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, -1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, -1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, -1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, -1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, -1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, -1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, -1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, -1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, -1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, -1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, -1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, -1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, -1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, -1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, -1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, -1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, -1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, -1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, -1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, -1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, -1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, -1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, -1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, -1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, -1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, -1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, -1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, -1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, -1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, -1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, -1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, -1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, -1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, -1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, -1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, -1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, -1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, -1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, -1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, -1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, -1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, -1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, -1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, -1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, -1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, -1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, -1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, -1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, -1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, -1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, -1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, -1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, -1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, -1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, -1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, -1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, -1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, -1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, -1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, -1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, -1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, -1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, -1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, -1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, -1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, -1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, -1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, -1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, -1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, -1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, -1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, -1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, -1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, -1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, -1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, -1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, -1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, -1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, -1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, -1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, -1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, -1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, -1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, -1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, -1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, -1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, -1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, -1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, -1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, -1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, -1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, -1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, -1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, -1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, -1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, -2001,Egg Festival,Egg Hunt Victory,FESTIVAL, -2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, -2003,Flower Dance,Dance with someone,FESTIVAL, -2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, -2005,Luau,Luau Soup,FESTIVAL, -2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, -2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, -2008,Stardew Valley Fair,Grange Display,FESTIVAL, -2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, -2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, -2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, -2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, -2013,Festival of Ice,Win Fishing Competition,FESTIVAL, -2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, -2015,Night Market,Mermaid Pearl,FESTIVAL, -2016,Night Market,Cone Hat,FESTIVAL_HARD, -2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, -2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, -2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, -2020,Night Market,Lupini: Red Eagle,FESTIVAL, -2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, -2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, -2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, -2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, -2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, -2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, -2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, -2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, -2029,Feast of the Winter Star,Secret Santa,FESTIVAL, -2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, -2031,Farm,Collect All Rarecrows,FESTIVAL, -2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, -2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, -2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, -2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, -2036,Casino,Rarecrow #3 (Alien),FESTIVAL, -2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, -2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, -2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, -2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, -2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, -2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, -2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, -2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, -2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, -2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, -2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, -2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, -2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, -2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, -2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, -2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", -2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, -2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, -2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, -2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", -2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", -2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", -2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", -2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", -2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", -2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", -2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", -2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", -2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, -2216,Field Office,Complete Island Field Office,GINGER_ISLAND, -2301,Farming,Harvest Amaranth,CROPSANITY, -2302,Farming,Harvest Artichoke,CROPSANITY, -2303,Farming,Harvest Beet,CROPSANITY, -2304,Farming,Harvest Blue Jazz,CROPSANITY, -2305,Farming,Harvest Blueberry,CROPSANITY, -2306,Farming,Harvest Bok Choy,CROPSANITY, -2307,Farming,Harvest Cauliflower,CROPSANITY, -2308,Farming,Harvest Corn,CROPSANITY, -2309,Farming,Harvest Cranberries,CROPSANITY, -2310,Farming,Harvest Eggplant,CROPSANITY, -2311,Farming,Harvest Fairy Rose,CROPSANITY, -2312,Farming,Harvest Garlic,CROPSANITY, -2313,Farming,Harvest Grape,CROPSANITY, -2314,Farming,Harvest Green Bean,CROPSANITY, -2315,Farming,Harvest Hops,CROPSANITY, -2316,Farming,Harvest Hot Pepper,CROPSANITY, -2317,Farming,Harvest Kale,CROPSANITY, -2318,Farming,Harvest Melon,CROPSANITY, -2319,Farming,Harvest Parsnip,CROPSANITY, -2320,Farming,Harvest Poppy,CROPSANITY, -2321,Farming,Harvest Potato,CROPSANITY, -2322,Farming,Harvest Pumpkin,CROPSANITY, -2323,Farming,Harvest Radish,CROPSANITY, -2324,Farming,Harvest Red Cabbage,CROPSANITY, -2325,Farming,Harvest Rhubarb,CROPSANITY, -2326,Farming,Harvest Starfruit,CROPSANITY, -2327,Farming,Harvest Strawberry,CROPSANITY, -2328,Farming,Harvest Summer Spangle,CROPSANITY, -2329,Farming,Harvest Sunflower,CROPSANITY, -2330,Farming,Harvest Tomato,CROPSANITY, -2331,Farming,Harvest Tulip,CROPSANITY, -2332,Farming,Harvest Unmilled Rice,CROPSANITY, -2333,Farming,Harvest Wheat,CROPSANITY, -2334,Farming,Harvest Yam,CROPSANITY, -2335,Farming,Harvest Cactus Fruit,CROPSANITY, -2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", -2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, -2339,Farming,Harvest Apple,CROPSANITY, -2340,Farming,Harvest Apricot,CROPSANITY, -2341,Farming,Harvest Cherry,CROPSANITY, -2342,Farming,Harvest Orange,CROPSANITY, -2343,Farming,Harvest Pomegranate,CROPSANITY, -2344,Farming,Harvest Peach,CROPSANITY, -2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", -2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farming,Harvest Coffee Bean,CROPSANITY, -2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2416,Shipping,Shipsanity: Anchor,SHIPSANITY, -2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, -2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, -2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, -2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, -2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, -2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, -2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, -2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, -2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, -2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, -2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, -2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, -2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, -2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, -2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, -2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, -2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, -2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, -2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, -2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, -2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, -2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, -2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, -2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, -2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, -2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, -2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, -2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, -2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, -2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, -2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, -2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, -2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2454,Shipping,Shipsanity: Coffee,SHIPSANITY, -2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, -2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, -2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, -2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, -2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, -2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, -2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, -2479,Shipping,Shipsanity: Bread,SHIPSANITY, -2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, -2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, -2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, -2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, -2484,Shipping,Shipsanity: Chowder,SHIPSANITY, -2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, -2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Shipping,Shipsanity: Cookies,SHIPSANITY, -2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, -2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, -2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, -2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, -2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, -2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, -2494,Shipping,Shipsanity: Escargot,SHIPSANITY, -2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, -2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, -2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, -2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, -2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, -2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, -2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, -2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, -2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, -2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, -2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, -2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, -2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, -2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, -2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, -2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, -2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, -2512,Shipping,Shipsanity: Omelet,SHIPSANITY, -2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, -2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, -2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, -2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, -2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, -2518,Shipping,Shipsanity: Pizza,SHIPSANITY, -2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, -2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, -2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, -2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, -2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, -2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, -2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, -2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, -2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, -2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, -2529,Shipping,Shipsanity: Salad,SHIPSANITY, -2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, -2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, -2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, -2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, -2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, -2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, -2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, -2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, -2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, -2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, -2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, -2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, -2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, -2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, -2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, -2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, -2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, -2547,Shipping,Shipsanity: Bait,SHIPSANITY, -2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, -2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, -2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, -2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, -2552,Shipping,Shipsanity: Bomb,SHIPSANITY, -2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, -2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, -2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, -2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, -2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, -2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, -2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, -2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, -2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, -2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, -2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, -2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, -2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, -2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, -2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, -2569,Shipping,Shipsanity: Gate,SHIPSANITY, -2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, -2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, -2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, -2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, -2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, -2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, -2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, -2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, -2578,Shipping,Shipsanity: Magnet,SHIPSANITY, -2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, -2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, -2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, -2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, -2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, -2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, -2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, -2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, -2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, -2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, -2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, -2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, -2591,Shipping,Shipsanity: Spinner,SHIPSANITY, -2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, -2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, -2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, -2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, -2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, -2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, -2598,Shipping,Shipsanity: Torch,SHIPSANITY, -2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, -2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, -2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, -2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, -2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, -2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", -2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, -2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, -2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, -2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, -2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, -2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", -2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", -2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", -2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", -2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", -2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", -2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", -2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", -2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", -2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", -2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", -2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", -2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", -2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", -2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", -2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", -2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", -2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", -2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", -2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", -2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", -2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", -2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", -2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", -2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", -2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", -2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", -2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", -2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", -2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", -2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", -2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", -2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", -2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", -2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", -2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", -2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", -2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", -2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", -2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", -2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", -2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", -2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", -2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", -2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", -2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", -2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", -2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", -2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", -2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", -2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", -2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", -2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", -2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", -2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", -2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, -2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2755,Shipping,Shipsanity: Oil,SHIPSANITY, -2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2757,Shipping,Shipsanity: Rice,SHIPSANITY, -2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2760,Shipping,Shipsanity: Sugar,SHIPSANITY, -2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, -2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, -2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, -2765,Shipping,Shipsanity: Alamite,SHIPSANITY, -2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, -2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, -2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, -2769,Shipping,Shipsanity: Baryte,SHIPSANITY, -2770,Shipping,Shipsanity: Basalt,SHIPSANITY, -2771,Shipping,Shipsanity: Bixite,SHIPSANITY, -2772,Shipping,Shipsanity: Calcite,SHIPSANITY, -2773,Shipping,Shipsanity: Celestine,SHIPSANITY, -2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2776,Shipping,Shipsanity: Diamond,SHIPSANITY, -2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, -2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, -2779,Shipping,Shipsanity: Emerald,SHIPSANITY, -2780,Shipping,Shipsanity: Esperite,SHIPSANITY, -2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, -2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, -2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, -2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, -2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, -2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, -2787,Shipping,Shipsanity: Geminite,SHIPSANITY, -2788,Shipping,Shipsanity: Geode,SHIPSANITY, -2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, -2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2791,Shipping,Shipsanity: Granite,SHIPSANITY, -2792,Shipping,Shipsanity: Helvite,SHIPSANITY, -2793,Shipping,Shipsanity: Hematite,SHIPSANITY, -2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2796,Shipping,Shipsanity: Jade,SHIPSANITY, -2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, -2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, -2799,Shipping,Shipsanity: Jasper,SHIPSANITY, -2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, -2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, -2802,Shipping,Shipsanity: Limestone,SHIPSANITY, -2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, -2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, -2805,Shipping,Shipsanity: Malachite,SHIPSANITY, -2806,Shipping,Shipsanity: Marble,SHIPSANITY, -2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, -2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, -2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, -2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, -2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, -2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, -2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, -2814,Shipping,Shipsanity: Opal,SHIPSANITY, -2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, -2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, -2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, -2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, -2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, -2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, -2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, -2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, -2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, -2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, -2825,Shipping,Shipsanity: Quartz,SHIPSANITY, -2826,Shipping,Shipsanity: Ruby,SHIPSANITY, -2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, -2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, -2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, -2830,Shipping,Shipsanity: Slate,SHIPSANITY, -2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, -2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, -2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, -2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, -2835,Shipping,Shipsanity: Topaz,SHIPSANITY, -2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, -2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, -2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, -2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, -2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, -2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, -2848,Shipping,Shipsanity: Hay,SHIPSANITY, -2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, -2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, -2851,Shipping,Shipsanity: Pearl,SHIPSANITY, -2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, -2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, -2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, -2855,Shipping,Shipsanity: White Algae,SHIPSANITY, -2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, -2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, -2858,Shipping,Shipsanity: Acorn,SHIPSANITY, -2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, -2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, -2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, -2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, -2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, -2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, -2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, -2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, -2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, -2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, -2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, -2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, -2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, -2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, -2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, -2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, -2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, -2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, -2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, -2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, -2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, -2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, -2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, -2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, -2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, -2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, -2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, -2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, -2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, -2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, -2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, -2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, -2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, -2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, -2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, -2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, -2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, -2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, -2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, -2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, -2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, -2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, -2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, -2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, -2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, -2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, -2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, -2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, -2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, -2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, -2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, -2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, -2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, -2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, -2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, -2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, -2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, -2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, -2918,Shipping,Shipsanity: Trash,SHIPSANITY, -2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, -2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", -2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", -2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", -2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", -2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", -2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", -2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", -2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", -2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", -2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", -2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", -2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", -2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", -2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", -2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", -2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", -2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", -2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", -2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", -2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", -2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", -2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Shipping,Shipsanity: Movie Ticket,"SHIPSANITY", -2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", -2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", -2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", -2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", -2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", -3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", -3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", -3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", -3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", -3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", -3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", -3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", -3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", -3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", -3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", -3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3201,Kitchen,Cook Algae Soup,COOKSANITY, -3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", -3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, -3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", -3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", -3206,Kitchen,Cook Bean Hotpot,COOKSANITY, -3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", -3208,Kitchen,Cook Blueberry Tart,COOKSANITY, -3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", -3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", -3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", -3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, -3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", -3214,Kitchen,Cook Chowder,COOKSANITY, -3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", -3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", -3217,Kitchen,Cook Cookies,COOKSANITY, -3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", -3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", -3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, -3221,Kitchen,Cook Crispy Bass,COOKSANITY, -3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, -3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, -3224,Kitchen,Cook Escargot,COOKSANITY, -3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, -3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", -3227,Kitchen,Cook Fish Stew,COOKSANITY, -3228,Kitchen,Cook Fish Taco,COOKSANITY, -3229,Kitchen,Cook Fried Calamari,COOKSANITY, -3230,Kitchen,Cook Fried Eel,COOKSANITY, -3231,Kitchen,Cook Fried Egg,COOKSANITY, -3232,Kitchen,Cook Fried Mushroom,COOKSANITY, -3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", -3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", -3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", -3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", -3237,Kitchen,Cook Ice Cream,COOKSANITY, -3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", -3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", -3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", -3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", -3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", -3243,Kitchen,Cook Miner's Treat,COOKSANITY, -3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", -3245,Kitchen,Cook Pale Broth,COOKSANITY, -3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", -3247,Kitchen,Cook Parsnip Soup,COOKSANITY, -3248,Kitchen,Cook Pepper Poppers,COOKSANITY, -3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", -3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", -3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", -3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", -3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", -3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", -3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, -3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", -3257,Kitchen,Cook Red Plate,COOKSANITY, -3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, -3259,Kitchen,Cook Rice Pudding,COOKSANITY, -3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", -3261,Kitchen,Cook Roots Platter,COOKSANITY, -3262,Kitchen,Cook Salad,COOKSANITY, -3263,Kitchen,Cook Salmon Dinner,COOKSANITY, -3264,Kitchen,Cook Sashimi,COOKSANITY, -3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, -3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", -3267,Kitchen,Cook Spaghetti,COOKSANITY, -3268,Kitchen,Cook Spicy Eel,COOKSANITY, -3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, -3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", -3271,Kitchen,Cook Strange Bun,COOKSANITY, -3272,Kitchen,Cook Stuffing,COOKSANITY, -3273,Kitchen,Cook Super Meal,COOKSANITY, -3274,Kitchen,Cook Survival Burger,COOKSANITY, -3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, -3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", -3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, -3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", -3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", -3280,Kitchen,Cook Vegetable Medley,COOKSANITY, -3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, -3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", -3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3401,Farm,Craft Cherry Bomb,CRAFTSANITY, -3402,Farm,Craft Bomb,CRAFTSANITY, -3403,Farm,Craft Mega Bomb,CRAFTSANITY, -3404,Farm,Craft Gate,CRAFTSANITY, -3405,Farm,Craft Wood Fence,CRAFTSANITY, -3406,Farm,Craft Stone Fence,CRAFTSANITY, -3407,Farm,Craft Iron Fence,CRAFTSANITY, -3408,Farm,Craft Hardwood Fence,CRAFTSANITY, -3409,Farm,Craft Sprinkler,CRAFTSANITY, -3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, -3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, -3412,Farm,Craft Bee House,CRAFTSANITY, -3413,Farm,Craft Cask,CRAFTSANITY, -3414,Farm,Craft Cheese Press,CRAFTSANITY, -3415,Farm,Craft Keg,CRAFTSANITY, -3416,Farm,Craft Loom,CRAFTSANITY, -3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, -3418,Farm,Craft Oil Maker,CRAFTSANITY, -3419,Farm,Craft Preserves Jar,CRAFTSANITY, -3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, -3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, -3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, -3423,Farm,Craft Speed-Gro,CRAFTSANITY, -3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, -3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", -3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, -3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, -3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", -3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, -3430,Farm,Craft Spring Seeds,CRAFTSANITY, -3431,Farm,Craft Summer Seeds,CRAFTSANITY, -3432,Farm,Craft Fall Seeds,CRAFTSANITY, -3433,Farm,Craft Winter Seeds,CRAFTSANITY, -3434,Farm,Craft Ancient Seeds,CRAFTSANITY, -3435,Farm,Craft Grass Starter,CRAFTSANITY, -3436,Farm,Craft Tea Sapling,CRAFTSANITY, -3437,Farm,Craft Fiber Seeds,CRAFTSANITY, -3438,Farm,Craft Wood Floor,CRAFTSANITY, -3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, -3440,Farm,Craft Straw Floor,CRAFTSANITY, -3441,Farm,Craft Weathered Floor,CRAFTSANITY, -3442,Farm,Craft Crystal Floor,CRAFTSANITY, -3443,Farm,Craft Stone Floor,CRAFTSANITY, -3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, -3445,Farm,Craft Brick Floor,CRAFTSANITY, -3446,Farm,Craft Wood Path,CRAFTSANITY, -3447,Farm,Craft Gravel Path,CRAFTSANITY, -3448,Farm,Craft Cobblestone Path,CRAFTSANITY, -3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, -3450,Farm,Craft Crystal Path,CRAFTSANITY, -3451,Farm,Craft Spinner,CRAFTSANITY, -3452,Farm,Craft Trap Bobber,CRAFTSANITY, -3453,Farm,Craft Cork Bobber,CRAFTSANITY, -3454,Farm,Craft Quality Bobber,CRAFTSANITY, -3455,Farm,Craft Treasure Hunter,CRAFTSANITY, -3456,Farm,Craft Dressed Spinner,CRAFTSANITY, -3457,Farm,Craft Barbed Hook,CRAFTSANITY, -3458,Farm,Craft Magnet,CRAFTSANITY, -3459,Farm,Craft Bait,CRAFTSANITY, -3460,Farm,Craft Wild Bait,CRAFTSANITY, -3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", -3462,Farm,Craft Crab Pot,CRAFTSANITY, -3463,Farm,Craft Sturdy Ring,CRAFTSANITY, -3464,Farm,Craft Warrior Ring,CRAFTSANITY, -3465,Farm,Craft Ring of Yoba,CRAFTSANITY, -3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", -3467,Farm,Craft Glowstone Ring,CRAFTSANITY, -3468,Farm,Craft Iridium Band,CRAFTSANITY, -3469,Farm,Craft Wedding Ring,CRAFTSANITY, -3470,Farm,Craft Field Snack,CRAFTSANITY, -3471,Farm,Craft Bug Steak,CRAFTSANITY, -3472,Farm,Craft Life Elixir,CRAFTSANITY, -3473,Farm,Craft Oil of Garlic,CRAFTSANITY, -3474,Farm,Craft Monster Musk,CRAFTSANITY, -3475,Farm,Craft Fairy Dust,CRAFTSANITY, -3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, -3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, -3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, -3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, -3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", -3481,Farm,Craft Rain Totem,CRAFTSANITY, -3482,Farm,Craft Torch,CRAFTSANITY, -3483,Farm,Craft Campfire,CRAFTSANITY, -3484,Farm,Craft Wooden Brazier,CRAFTSANITY, -3485,Farm,Craft Stone Brazier,CRAFTSANITY, -3486,Farm,Craft Gold Brazier,CRAFTSANITY, -3487,Farm,Craft Carved Brazier,CRAFTSANITY, -3488,Farm,Craft Stump Brazier,CRAFTSANITY, -3489,Farm,Craft Barrel Brazier,CRAFTSANITY, -3490,Farm,Craft Skull Brazier,CRAFTSANITY, -3491,Farm,Craft Marble Brazier,CRAFTSANITY, -3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, -3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, -3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, -3495,Farm,Craft Bone Mill,CRAFTSANITY, -3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, -3497,Farm,Craft Crystalarium,CRAFTSANITY, -3498,Farm,Craft Furnace,CRAFTSANITY, -3499,Farm,Craft Geode Crusher,CRAFTSANITY, -3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", -3501,Farm,Craft Lightning Rod,CRAFTSANITY, -3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", -3503,Farm,Craft Recycling Machine,CRAFTSANITY, -3504,Farm,Craft Seed Maker,CRAFTSANITY, -3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, -3506,Farm,Craft Slime Incubator,CRAFTSANITY, -3507,Farm,Craft Solar Panel,CRAFTSANITY, -3508,Farm,Craft Tapper,CRAFTSANITY, -3509,Farm,Craft Worm Bin,CRAFTSANITY, -3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, -3511,Farm,Craft Wicked Statue,CRAFTSANITY, -3512,Farm,Craft Flute Block,CRAFTSANITY, -3513,Farm,Craft Drum Block,CRAFTSANITY, -3514,Farm,Craft Chest,CRAFTSANITY, -3515,Farm,Craft Stone Chest,CRAFTSANITY, -3516,Farm,Craft Wood Sign,CRAFTSANITY, -3517,Farm,Craft Stone Sign,CRAFTSANITY, -3518,Farm,Craft Dark Sign,CRAFTSANITY, -3519,Farm,Craft Garden Pot,CRAFTSANITY, -3520,Farm,Craft Scarecrow,CRAFTSANITY, -3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, -3522,Farm,Craft Staircase,CRAFTSANITY, -3523,Farm,Craft Explosive Ammo,CRAFTSANITY, -3524,Farm,Craft Transmute (Fe),CRAFTSANITY, -3525,Farm,Craft Transmute (Au),CRAFTSANITY, -3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, -3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, -3528,Farm,Craft Farm Computer,CRAFTSANITY, -3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", -3530,Farm,Craft Cookout Kit,CRAFTSANITY, -3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, -3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, -3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, -3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, -3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, -3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, -3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, -3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, -3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, -3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, -3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, -3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, -3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", -3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, -3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, -3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, -3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, -3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, -3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, -3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, -3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, -3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, -3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, -3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, -3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", -3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY,GINGER_ISLAND", -5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic -5502,Magic Altar,Analyze: Till,MANDATORY,Magic -5503,Magic Altar,Analyze: Water,MANDATORY,Magic -5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic -5505,Magic Altar,Analyze: Evac,MANDATORY,Magic -5506,Magic Altar,Analyze: Haste,MANDATORY,Magic -5507,Magic Altar,Analyze: Heal,MANDATORY,Magic -5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic -5509,Magic Altar,Analyze: Descend,MANDATORY,Magic -5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic -5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic -5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic -5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic -5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic -5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic -5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic -5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic -5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic -5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic -5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic -5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic -6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas -6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas -6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas -6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas -6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas -6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas -6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas -6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas -6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas -6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas -6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas -6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas -6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas -6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas -6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba -6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba -6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba -6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba -6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba -6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba -6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba -6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba -6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba -6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba -6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) -6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) -6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) -6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) -6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) -6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) -6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) -6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) -6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) -6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) -6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC -6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC -6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC -6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC -6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC -6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC -6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC -6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC -6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC -6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC -6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC -6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC -6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC -6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC -6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick -6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick -6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick -6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick -6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick -6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick -6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick -6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick -6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick -6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick -6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick -6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick -6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick -6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick -6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC -6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC -6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC -6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC -6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC -6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC -6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC -6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC -6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC -6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC -6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC -6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC -6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC -6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC -6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited -6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited -6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited -6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited -6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited -6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited -6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited -6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited -6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited -6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited -6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited -6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited -6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited -6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited -6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene -6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene -6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene -6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene -6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene -6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene -6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene -6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene -6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene -6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene -6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene -6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene -6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene -6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene -6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC -6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC -6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC -6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC -6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC -6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC -6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC -6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC -6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC -6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC -6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley -6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley -6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley -6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley -6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley -6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley -6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley -6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley -6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley -6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley -6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley -6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley -6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley -6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley -6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded -6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded -6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded -6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded -6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded -6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded -6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded -6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded -6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded -6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded -6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded -6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded -6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded -6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded -6153,Galmoran Outpost,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6154,Galmoran Outpost,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6155,Galmoran Outpost,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6156,Galmoran Outpost,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6157,Galmoran Outpost,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6158,Galmoran Outpost,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6159,Galmoran Outpost,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6160,Galmoran Outpost,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6161,Galmoran Outpost,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6162,Galmoran Outpost,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6163,Galmoran Outpost,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6164,Galmoran Outpost,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6165,Galmoran Outpost,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6166,Galmoran Outpost,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded -6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded -6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded -6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded -6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded -6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded -6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded -6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded -6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded -6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded -6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded -6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded -6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded -6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded -6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded -6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded -6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded -6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded -6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded -6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded -6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded -6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded -6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded -6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded -6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded -6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded -6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded -6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded -6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded -6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded -6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded -6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded -6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded -6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded -6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded -6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded -6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded -6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded -6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded -6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded -6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded -6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded -6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded -6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded -6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded -6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded -6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded -6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded -6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded -6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded -6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded -6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded -6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded -6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded -6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded -6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded -6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded -6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded -6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded -6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded -6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded -6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded -6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded -6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded -6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded -6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded -6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded -6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded -6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6273,Scarlett's House,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded -6274,Scarlett's House,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded -6275,Scarlett's House,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded -6276,Scarlett's House,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded -6277,Scarlett's House,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded -6278,Scarlett's House,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded -6279,Scarlett's House,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded -6280,Scarlett's House,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded -6281,Scarlett's House,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded -6282,Scarlett's House,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded -6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded -6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded -6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded -6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded -6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded -6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded -6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded -6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded -6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded -6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded -6303,Witch's Swamp,Friendsanity: Zic 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6304,Witch's Swamp,Friendsanity: Zic 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6305,Witch's Swamp,Friendsanity: Zic 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6306,Witch's Swamp,Friendsanity: Zic 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6307,Witch's Swamp,Friendsanity: Zic 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6308,Witch's Swamp,Friendsanity: Zic 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6309,Witch's Swamp,Friendsanity: Zic 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6310,Witch's Swamp,Friendsanity: Zic 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6311,Witch's Swamp,Friendsanity: Zic 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6312,Witch's Swamp,Friendsanity: Zic 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch -6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch -6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch -6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch -6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch -6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch -6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch -6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch -6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch -6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch -6323,Mouse House,Friendsanity: Lacey 1 <3,FRIENDSANITY,Hat Mouse Lacey -6324,Mouse House,Friendsanity: Lacey 2 <3,FRIENDSANITY,Hat Mouse Lacey -6325,Mouse House,Friendsanity: Lacey 3 <3,FRIENDSANITY,Hat Mouse Lacey -6326,Mouse House,Friendsanity: Lacey 4 <3,FRIENDSANITY,Hat Mouse Lacey -6327,Mouse House,Friendsanity: Lacey 5 <3,FRIENDSANITY,Hat Mouse Lacey -6328,Mouse House,Friendsanity: Lacey 6 <3,FRIENDSANITY,Hat Mouse Lacey -6329,Mouse House,Friendsanity: Lacey 7 <3,FRIENDSANITY,Hat Mouse Lacey -6330,Mouse House,Friendsanity: Lacey 8 <3,FRIENDSANITY,Hat Mouse Lacey -6331,Mouse House,Friendsanity: Lacey 9 <3,FRIENDSANITY,Hat Mouse Lacey -6332,Mouse House,Friendsanity: Lacey 10 <3,FRIENDSANITY,Hat Mouse Lacey -6333,Mouse House,Friendsanity: Lacey 11 <3,FRIENDSANITY,Hat Mouse Lacey -6334,Mouse House,Friendsanity: Lacey 12 <3,FRIENDSANITY,Hat Mouse Lacey -6335,Mouse House,Friendsanity: Lacey 13 <3,FRIENDSANITY,Hat Mouse Lacey -6336,Mouse House,Friendsanity: Lacey 14 <3,FRIENDSANITY,Hat Mouse Lacey -6337,Boarding House - First Floor,Friendsanity: Joel 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6338,Boarding House - First Floor,Friendsanity: Joel 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6339,Boarding House - First Floor,Friendsanity: Joel 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6340,Boarding House - First Floor,Friendsanity: Joel 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6341,Boarding House - First Floor,Friendsanity: Joel 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6342,Boarding House - First Floor,Friendsanity: Joel 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6343,Boarding House - First Floor,Friendsanity: Joel 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6344,Boarding House - First Floor,Friendsanity: Joel 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6345,Boarding House - First Floor,Friendsanity: Joel 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6346,Boarding House - First Floor,Friendsanity: Joel 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6347,Boarding House - First Floor,Friendsanity: Sheila 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6348,Boarding House - First Floor,Friendsanity: Sheila 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6349,Boarding House - First Floor,Friendsanity: Sheila 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6350,Boarding House - First Floor,Friendsanity: Sheila 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6351,Boarding House - First Floor,Friendsanity: Sheila 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6352,Boarding House - First Floor,Friendsanity: Sheila 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6353,Boarding House - First Floor,Friendsanity: Sheila 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6354,Boarding House - First Floor,Friendsanity: Sheila 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6355,Boarding House - First Floor,Friendsanity: Sheila 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6356,Boarding House - First Floor,Friendsanity: Sheila 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6357,Boarding House - First Floor,Friendsanity: Sheila 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6358,Boarding House - First Floor,Friendsanity: Sheila 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6359,Boarding House - First Floor,Friendsanity: Sheila 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6360,Boarding House - First Floor,Friendsanity: Sheila 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6361,The Lost Valley,Friendsanity: Gregory 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6362,The Lost Valley,Friendsanity: Gregory 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6363,The Lost Valley,Friendsanity: Gregory 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6364,The Lost Valley,Friendsanity: Gregory 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6365,The Lost Valley,Friendsanity: Gregory 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6366,The Lost Valley,Friendsanity: Gregory 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6367,The Lost Valley,Friendsanity: Gregory 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6368,The Lost Valley,Friendsanity: Gregory 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6369,The Lost Valley,Friendsanity: Gregory 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6370,The Lost Valley,Friendsanity: Gregory 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6371,The Lost Valley,Friendsanity: Gregory 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6372,The Lost Valley,Friendsanity: Gregory 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6373,The Lost Valley,Friendsanity: Gregory 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6374,The Lost Valley,Friendsanity: Gregory 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack -7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod -7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods -7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods -7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods -7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods -7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods -7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods -7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods -7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods -7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods -7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods -7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods -7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods -7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods -7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods -7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods -7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods -7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods -7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator -7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator -7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator -7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator -7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator -7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator -7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator -7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods -7051,Abandoned Mines - 1A,Abandoned Treasure - Floor 1A,MANDATORY,Boarding House and Bus Stop Extension -7052,Abandoned Mines - 1B,Abandoned Treasure - Floor 1B,MANDATORY,Boarding House and Bus Stop Extension -7053,Abandoned Mines - 2A,Abandoned Treasure - Floor 2A,MANDATORY,Boarding House and Bus Stop Extension -7054,Abandoned Mines - 2B,Abandoned Treasure - Floor 2B,MANDATORY,Boarding House and Bus Stop Extension -7055,Abandoned Mines - 3,Abandoned Treasure - Floor 3,MANDATORY,Boarding House and Bus Stop Extension -7056,Abandoned Mines - 4,Abandoned Treasure - Floor 4,MANDATORY,Boarding House and Bus Stop Extension -7057,Abandoned Mines - 5,Abandoned Treasure - Floor 5,MANDATORY,Boarding House and Bus Stop Extension -7401,Farm,Cook Magic Elixir,COOKSANITY,Magic -7402,Farm,Craft Travel Core,CRAFTSANITY,Magic -7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded -7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded -7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded -7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -7407,Farm,Craft Glass Path,CRAFTSANITY,Archaeology -7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology -7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology -7410,Farm,Craft Bone Path,CRAFTSANITY,Archaeology -7411,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology -7412,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology -7413,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology -7414,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology -7415,Farm,Craft Grinder,CRAFTSANITY,Archaeology -7416,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology -7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology -7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology -7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic -7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic -7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -7501,Mountain,Missing Envelope,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Forest,Lost Emerald Ring,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) -7503,Forest,Mr.Ginger's request,"STORY_QUEST",Mister Ginger (cat npc) -7504,Forest,Juna's Drink Request,"STORY_QUEST",Juna - Roommate NPC -7505,Forest,Juna's BFF Request,"STORY_QUEST",Juna - Roommate NPC -7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC -7507,Adventurer's Guild,Marlon's Boat,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded -7508,Railroad,The Railroad Boulder,"STORY_QUEST",Stardew Valley Expanded -7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded -7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded -7511,Adventurer's Guild,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded -7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded -7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7520,Witch's Swamp,A New Pot,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul -7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul -7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7523,Boarding House - First Floor,Pumpkin Soup,"MANDATORY,STORY_QUEST",Boarding House and Bus Stop Extension -7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas -7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas -7526,Mouse House,Hats for the Hat Mouse,"MANDATORY,STORY_QUEST",Hat Mouse Lacey -7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded -7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded -7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded -7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded -7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded -7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded -7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded -7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded -7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded -7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded -7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7615,Boarding House - First Floor,Special Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension -7616,Mines Dwarf Shop,Neanderthal Skeleton Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7617,Mines Dwarf Shop,Pterodactyl Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7618,Mines Dwarf Shop,Pterodactyl Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7619,Mines Dwarf Shop,Pterodactyl Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7620,Mines Dwarf Shop,T-Rex Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7621,Mines Dwarf Shop,T-Rex Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7622,Mines Dwarf Shop,T-Rex Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7654,Lance's House Main,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded -7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded -7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded -7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded -7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7706,Highlands Outside,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7708,Highlands Outside,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded -7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded -7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded -7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded -7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded -7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded -7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded -7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded -7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded -7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded -7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded -7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded -7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded -7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7731,Witch's Swamp,Fishsanity: Purple Algae,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded -7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded -7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul -7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul -8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic -8002,Shipping,Shipsanity: Travel Core,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Magic -8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded -8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded -8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded -8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded -8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded -8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded -8013,Shipping,Shipsanity: Big Conch,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8021,Shipping,Shipsanity: Dried Sand Dollar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded -8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded -8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY",Stardew Valley Expanded -8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded -8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded -8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded -8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded -8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded -8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded -8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded -8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded -8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded -8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded -8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded -8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded -8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded -8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded -8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded -8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology -8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology -8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology -8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology -8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology -8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology -8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology -8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology -8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology -8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology -8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology -8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology -8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology -8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology -8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology -8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology -8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology -8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology -8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology -8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology -8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology -8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology -8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology -8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology -8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology -8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology -8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology -8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology -8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology -8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology -8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology -8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology -8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology -8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology -8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology -8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology -8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology -8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology -8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology -8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology -8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology -8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology -8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology -8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology -8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology -8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology -8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology -8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology -8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology -8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology -8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology -8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology -8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology -8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology -8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology -8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology -8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology -8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology -8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology -8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology -8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology -8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology -8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology -8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology -8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology -8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology -8194,Shipping,Shipsanity: Wooden Display: Trilobite Fossil,SHIPSANITY,Archaeology -8195,Shipping,Shipsanity: Hardwood Display: Trilobite Fossil,SHIPSANITY,Archaeology -8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology -8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology -8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology -8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology -8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology -8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology -8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology -8203,Shipping,Shipsanity: Brown Amanita,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -8218,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension -8219,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension -8220,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension -8221,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension -8222,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8223,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension -8224,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension -8225,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8226,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension -8227,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8228,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension -8229,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8230,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension -8231,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension -8232,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension -8233,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8234,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension -8235,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension -8236,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8237,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +id,region,name,tags,mod_name +1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", +32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", +34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", +35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", +37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +39,Fish Tank,Deep Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +47,Boiler Room,Paleontologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", +48,Boiler Room,Archaeologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", +49,Pantry,Slime Farmer Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +58,Fish Tank,Trash Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +69,Boiler Room,Recycling Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +73,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +74,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +75,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +76,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +77,Vault,250g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +78,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +79,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +80,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +81,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +82,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +83,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +84,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +85,Vault,"4,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +87,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +88,Vault,"9,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +89,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +90,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +91,Vault,"18,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,"20,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,"40,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,"45,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +96,Vault,"100,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +97,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +98,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +99,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +100,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +101,Pierre's General Store,Large Pack,BACKPACK, +102,Pierre's General Store,Deluxe Pack,BACKPACK, +103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", +202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", +203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", +204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", +205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", +206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", +207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", +208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", +209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", +210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", +211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", +212,Quarry Mine,Grim Reaper statue,MANDATORY, +213,The Mines,The Mines Entrance Cutscene,MANDATORY, +214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, +215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, +216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, +217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, +218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, +219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, +220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, +221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, +222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, +223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, +224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, +225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, +226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, +227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, +228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, +229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, +230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, +231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, +232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, +233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, +234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, +235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, +236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, +237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, +250,Shipping,Demetrius's Breakthrough,MANDATORY +251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", +301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", +302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", +303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", +304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", +305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", +306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", +307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", +308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", +309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", +310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", +311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", +332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", +333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", +334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", +335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", +336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", +337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", +338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", +339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", +340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", +341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, +402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, +403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, +404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, +405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, +406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, +407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, +408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, +409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, +410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, +411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, +412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, +413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, +414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, +415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, +416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, +417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, +418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, +501,Town,Introductions,"STORY_QUEST", +502,Town,How To Win Friends,"STORY_QUEST", +503,Farm,Getting Started,"STORY_QUEST", +504,Farm,Raising Animals,"STORY_QUEST", +505,Farm,Advancement,"STORY_QUEST", +506,Museum,Archaeology,"STORY_QUEST", +507,Wizard Tower,Meet The Wizard,"STORY_QUEST", +508,The Mines - Floor 5,Forging Ahead,"STORY_QUEST", +509,The Mines - Floor 10,Smelting,"STORY_QUEST", +510,The Mines - Floor 15,Initiation,"STORY_QUEST", +511,Mountain,Robin's Lost Axe,"STORY_QUEST", +512,Town,Jodi's Request,"STORY_QUEST", +513,Town,"Mayor's ""Shorts""","STORY_QUEST", +514,Mountain,Blackberry Basket,"STORY_QUEST", +515,Marnie's Ranch,Marnie's Request,"STORY_QUEST", +516,Town,Pam Is Thirsty,"STORY_QUEST", +517,Wizard Tower,A Dark Reagent,"STORY_QUEST", +518,Forest,Cow's Delight,"STORY_QUEST", +519,Skull Cavern Entrance,The Skull Key,"STORY_QUEST", +520,Mountain,Crop Research,"STORY_QUEST", +521,Alex's House,Knee Therapy,"STORY_QUEST", +522,Mountain,Robin's Request,"STORY_QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"STORY_QUEST", +524,Desert,The Mysterious Qi,"STORY_QUEST", +525,Town,Carving Pumpkins,"STORY_QUEST", +526,Town,A Winter Mystery,"STORY_QUEST", +527,Secret Woods,Strange Note,"STORY_QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"STORY_QUEST", +529,Town,Fresh Fruit,"STORY_QUEST", +530,Mountain,Aquatic Research,"STORY_QUEST", +531,Town,A Soldier's Star,"STORY_QUEST", +532,Town,Mayor's Need,"STORY_QUEST", +533,Saloon,Wanted: Lobster,"STORY_QUEST", +534,Town,Pam Needs Juice,"STORY_QUEST", +535,Sam's House,Fish Casserole,"STORY_QUEST", +536,Beach,Catch A Squid,"STORY_QUEST", +537,Saloon,Fish Stew,"STORY_QUEST", +538,Pierre's General Store,Pierre's Notice,"STORY_QUEST", +539,Clint's Blacksmith,Clint's Attempt,"STORY_QUEST", +540,Town,A Favor For Clint,"STORY_QUEST", +541,Wizard Tower,Staff Of Power,"STORY_QUEST", +542,Town,Granny's Gift,"STORY_QUEST", +543,Desert,Exotic Spirits,"STORY_QUEST", +544,Fishing,Catch a Lingcod,"STORY_QUEST", +545,Island West,The Pirate's Wife,"GINGER_ISLAND,STORY_QUEST", +546,Mutant Bug Lair,Dark Talisman,"STORY_QUEST", +547,Witch's Swamp,Goblin Problem,"STORY_QUEST", +548,Witch's Hut,Magic Ink,"STORY_QUEST", +601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", +602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", +603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", +604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", +605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", +606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", +607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", +608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", +609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", +610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", +611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", +612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", +613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", +614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", +615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", +616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", +617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", +618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", +619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", +620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", +621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", +701,Secret Woods,Old Master Cannoli,MANDATORY, +702,Beach,Beach Bridge Repair,MANDATORY, +703,Desert,Galaxy Sword Shrine,MANDATORY, +704,Farmhouse,Have a Baby,BABY, +705,Farmhouse,Have Another Baby,BABY, +706,Farmhouse,Spouse Stardrop,, +707,Sewer,Krobus Stardrop,MANDATORY, +801,Forest,Help Wanted: Gathering 1,HELP_WANTED, +802,Forest,Help Wanted: Gathering 2,HELP_WANTED, +803,Forest,Help Wanted: Gathering 3,HELP_WANTED, +804,Forest,Help Wanted: Gathering 4,HELP_WANTED, +805,Forest,Help Wanted: Gathering 5,HELP_WANTED, +806,Forest,Help Wanted: Gathering 6,HELP_WANTED, +807,Forest,Help Wanted: Gathering 7,HELP_WANTED, +808,Forest,Help Wanted: Gathering 8,HELP_WANTED, +811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, +812,The Mines - Floor 15,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 25,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 35,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 45,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 55,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 65,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 75,Help Wanted: Slay Monsters 8,HELP_WANTED, +821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, +822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, +823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, +824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, +825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, +826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, +827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, +828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, +841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, +842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, +843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, +844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, +845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, +846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, +847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, +848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, +849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, +850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, +851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, +852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, +853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, +854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, +855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, +856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, +857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, +858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, +859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, +860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, +861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, +862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, +863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, +864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, +865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, +866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, +867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, +868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, +869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, +870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, +871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, +872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, +901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", +902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", +903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", +911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", +912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", +913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", +921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", +942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", +943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", +951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", +952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", +953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", +961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", +962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", +963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", +1001,Fishing,Fishsanity: Carp,FISHSANITY, +1002,Fishing,Fishsanity: Herring,FISHSANITY, +1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, +1004,Fishing,Fishsanity: Anchovy,FISHSANITY, +1005,Fishing,Fishsanity: Sardine,FISHSANITY, +1006,Fishing,Fishsanity: Sunfish,FISHSANITY, +1007,Fishing,Fishsanity: Perch,FISHSANITY, +1008,Fishing,Fishsanity: Chub,FISHSANITY, +1009,Fishing,Fishsanity: Bream,FISHSANITY, +1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, +1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, +1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, +1013,Fishing,Fishsanity: Walleye,FISHSANITY, +1014,Fishing,Fishsanity: Shad,FISHSANITY, +1015,Fishing,Fishsanity: Bullhead,FISHSANITY, +1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, +1017,Fishing,Fishsanity: Salmon,FISHSANITY, +1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, +1019,Fishing,Fishsanity: Tilapia,FISHSANITY, +1020,Fishing,Fishsanity: Woodskip,FISHSANITY, +1021,Fishing,Fishsanity: Flounder,FISHSANITY, +1022,Fishing,Fishsanity: Halibut,FISHSANITY, +1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", +1024,Fishing,Fishsanity: Slimejack,FISHSANITY, +1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, +1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, +1027,Fishing,Fishsanity: Pike,FISHSANITY, +1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, +1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", +1030,Fishing,Fishsanity: Albacore,FISHSANITY, +1031,Fishing,Fishsanity: Sandfish,FISHSANITY, +1032,Fishing,Fishsanity: Stonefish,FISHSANITY, +1033,Fishing,Fishsanity: Tuna,FISHSANITY, +1034,Fishing,Fishsanity: Eel,FISHSANITY, +1035,Fishing,Fishsanity: Catfish,FISHSANITY, +1036,Fishing,Fishsanity: Squid,FISHSANITY, +1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, +1038,Fishing,Fishsanity: Dorado,FISHSANITY, +1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, +1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, +1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, +1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", +1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, +1044,Fishing,Fishsanity: Lingcod,FISHSANITY, +1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, +1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, +1047,Fishing,Fishsanity: Octopus,FISHSANITY, +1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, +1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, +1050,Fishing,Fishsanity: Blobfish,FISHSANITY, +1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, +1052,Fishing,Fishsanity: Angler,FISHSANITY, +1053,Fishing,Fishsanity: Legend,FISHSANITY, +1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, +1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, +1056,Town,Fishsanity: Crayfish,FISHSANITY, +1057,Town,Fishsanity: Snail,FISHSANITY, +1058,Town,Fishsanity: Periwinkle,FISHSANITY, +1059,Beach,Fishsanity: Lobster,FISHSANITY, +1060,Beach,Fishsanity: Clam,FISHSANITY, +1061,Beach,Fishsanity: Crab,FISHSANITY, +1062,Beach,Fishsanity: Cockle,FISHSANITY, +1063,Beach,Fishsanity: Mussel,FISHSANITY, +1064,Beach,Fishsanity: Shrimp,FISHSANITY, +1065,Beach,Fishsanity: Oyster,FISHSANITY, +1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, +1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, +1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, +1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, +1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, +1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, +1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, +1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, +1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, +1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, +1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, +1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, +1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, +1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, +1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, +1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, +1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, +1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, +1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, +1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, +1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, +1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, +1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, +1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, +1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, +1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, +1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, +1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, +1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, +1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, +1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, +1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, +1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, +1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, +1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, +1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, +1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, +1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, +1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, +1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, +1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, +1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, +1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, +1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, +1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, +1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, +1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", +1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, +1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, +1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, +1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, +1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, +1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, +1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, +1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, +1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, +1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, +1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, +1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, +1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, +1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, +1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, +1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, +1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, +1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, +1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, +1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, +1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, +1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, +1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, +1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, +1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, +1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, +1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, +1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, +1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, +1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, +1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, +1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, +1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, +1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, +1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, +1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, +1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, +1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, +1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, +1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, +1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, +1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, +1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, +1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, +1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, +1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, +1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, +1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, +1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, +1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, +1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, +1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, +1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, +1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, +1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, +1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, +1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, +1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, +1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, +1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, +1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, +1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, +1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, +1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, +1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, +1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, +1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, +1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, +1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, +1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, +1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, +1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, +1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, +1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, +1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, +1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, +1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, +1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, +1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, +1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, +1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, +1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, +1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, +1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, +1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, +1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, +1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, +1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, +1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, +1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, +1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, +1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, +1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, +1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, +1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, +1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, +1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, +1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, +1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, +1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, +1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, +1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, +1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, +1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, +1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, +1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, +1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, +1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, +1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, +1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, +1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, +1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, +1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, +1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, +1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, +1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, +1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, +1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, +1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, +1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, +1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, +1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, +1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, +1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, +1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, +1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, +1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, +1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, +1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, +1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, +1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, +1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, +1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, +1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, +1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, +1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, +1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, +1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, +1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, +1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, +1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, +1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, +1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, +1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, +1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, +1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, +1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, +1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, +1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, +1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, +1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, +1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, +1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, +1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, +1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, +1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, +1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, +1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, +1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, +1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, +1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, +1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, +1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, +1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, +1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, +1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, +1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, +1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, +1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, +1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, +1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, +1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, +1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, +1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, +1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, +1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, +1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, +1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, +1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, +1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, +1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, +1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, +1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, +1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, +1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, +1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, +1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, +1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, +1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, +1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, +1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, +1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, +1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, +1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, +1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, +1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, +1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, +1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, +1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, +1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, +1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, +1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, +1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, +1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, +1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, +1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, +1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, +1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, +1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, +1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, +1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, +1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, +1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, +1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, +1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, +1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, +1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, +1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, +1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, +1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, +1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, +1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, +1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, +1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, +1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, +1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, +1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, +1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, +1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, +1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, +1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, +1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, +1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, +1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, +1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, +1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, +1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, +1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, +1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, +1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, +1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, +1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, +1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, +1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, +1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, +1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, +1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, +1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, +1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, +1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, +1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, +1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, +1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, +1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, +1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, +1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, +1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, +1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, +1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, +1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, +1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, +1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, +1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, +1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, +1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, +1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, +1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, +1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, +1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, +1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, +1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, +1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, +1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, +1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, +1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, +1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, +1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, +1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, +1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, +1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, +1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, +1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, +1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, +1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, +1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, +1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, +1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, +1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, +1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, +1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, +1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, +1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, +1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, +1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, +1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, +1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, +1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, +1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, +1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, +1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, +1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, +1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, +1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, +1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, +1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, +1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, +1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, +1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, +1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, +1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, +1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, +1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, +1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, +1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, +1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, +1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, +1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, +1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, +1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, +1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, +1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, +1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, +1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, +1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, +1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, +1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, +1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, +1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, +1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, +1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, +1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, +1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, +1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, +1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, +1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, +1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, +1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, +1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, +1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, +1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, +1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, +1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, +1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, +1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, +1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, +1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, +1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, +1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, +1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, +1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, +1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, +1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, +1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, +1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, +1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, +1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", +1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", +1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", +1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", +1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", +1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", +1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", +1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", +1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", +1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", +1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, +1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, +1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, +1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, +1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, +1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, +1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, +1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, +1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, +1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, +1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, +1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, +1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, +1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, +1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, +1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, +1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, +1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, +1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, +1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, +1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, +1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, +1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, +1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, +1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, +1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, +1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, +1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, +1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, +1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, +1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, +1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, +1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, +1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, +1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, +1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, +1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, +1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, +1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, +1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, +1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, +1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, +1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, +1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, +1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, +1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, +1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, +1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, +1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, +1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, +1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, +1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, +1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, +1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, +1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, +1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, +1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, +1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, +1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, +1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, +1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, +1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, +1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, +1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, +1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, +1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, +1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, +1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, +1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, +1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, +1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, +1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, +1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, +1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, +1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, +1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, +1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, +1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, +1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, +1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, +1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, +1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, +1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, +1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, +1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, +1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, +1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, +1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, +1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, +1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, +1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, +1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, +1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, +1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, +1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, +1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, +1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, +1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, +1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, +1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, +1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, +1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, +1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, +1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, +1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, +1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, +1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, +1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, +1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, +1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, +1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, +1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, +1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, +1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, +1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, +1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, +1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, +1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, +1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, +2001,Egg Festival,Egg Hunt Victory,FESTIVAL, +2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, +2003,Flower Dance,Dance with someone,FESTIVAL, +2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, +2005,Luau,Luau Soup,FESTIVAL, +2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, +2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, +2008,Stardew Valley Fair,Grange Display,FESTIVAL, +2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, +2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, +2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, +2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, +2013,Festival of Ice,Win Fishing Competition,FESTIVAL, +2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, +2015,Night Market,Mermaid Pearl,FESTIVAL, +2016,Night Market,Cone Hat,FESTIVAL_HARD, +2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, +2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, +2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, +2020,Night Market,Lupini: Red Eagle,FESTIVAL, +2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, +2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, +2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, +2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, +2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, +2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, +2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, +2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, +2029,Feast of the Winter Star,Secret Santa,FESTIVAL, +2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, +2031,Farm,Collect All Rarecrows,FESTIVAL, +2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, +2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, +2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, +2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, +2036,Casino,Rarecrow #3 (Alien),FESTIVAL, +2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, +2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, +2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, +2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, +2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, +2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, +2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, +2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, +2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, +2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, +2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, +2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, +2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, +2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, +2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, +2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", +2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, +2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, +2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, +2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", +2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", +2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", +2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", +2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", +2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", +2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", +2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", +2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", +2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, +2216,Field Office,Complete Island Field Office,GINGER_ISLAND, +2301,Farming,Harvest Amaranth,CROPSANITY, +2302,Farming,Harvest Artichoke,CROPSANITY, +2303,Farming,Harvest Beet,CROPSANITY, +2304,Farming,Harvest Blue Jazz,CROPSANITY, +2305,Farming,Harvest Blueberry,CROPSANITY, +2306,Farming,Harvest Bok Choy,CROPSANITY, +2307,Farming,Harvest Cauliflower,CROPSANITY, +2308,Farming,Harvest Corn,CROPSANITY, +2309,Farming,Harvest Cranberries,CROPSANITY, +2310,Farming,Harvest Eggplant,CROPSANITY, +2311,Farming,Harvest Fairy Rose,CROPSANITY, +2312,Farming,Harvest Garlic,CROPSANITY, +2313,Farming,Harvest Grape,CROPSANITY, +2314,Farming,Harvest Green Bean,CROPSANITY, +2315,Farming,Harvest Hops,CROPSANITY, +2316,Farming,Harvest Hot Pepper,CROPSANITY, +2317,Farming,Harvest Kale,CROPSANITY, +2318,Farming,Harvest Melon,CROPSANITY, +2319,Farming,Harvest Parsnip,CROPSANITY, +2320,Farming,Harvest Poppy,CROPSANITY, +2321,Farming,Harvest Potato,CROPSANITY, +2322,Farming,Harvest Pumpkin,CROPSANITY, +2323,Farming,Harvest Radish,CROPSANITY, +2324,Farming,Harvest Red Cabbage,CROPSANITY, +2325,Farming,Harvest Rhubarb,CROPSANITY, +2326,Farming,Harvest Starfruit,CROPSANITY, +2327,Farming,Harvest Strawberry,CROPSANITY, +2328,Farming,Harvest Summer Spangle,CROPSANITY, +2329,Farming,Harvest Sunflower,CROPSANITY, +2330,Farming,Harvest Tomato,CROPSANITY, +2331,Farming,Harvest Tulip,CROPSANITY, +2332,Farming,Harvest Unmilled Rice,CROPSANITY, +2333,Farming,Harvest Wheat,CROPSANITY, +2334,Farming,Harvest Yam,CROPSANITY, +2335,Farming,Harvest Cactus Fruit,CROPSANITY, +2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", +2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", +2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, +2339,Farming,Harvest Apple,CROPSANITY, +2340,Farming,Harvest Apricot,CROPSANITY, +2341,Farming,Harvest Cherry,CROPSANITY, +2342,Farming,Harvest Orange,CROPSANITY, +2343,Farming,Harvest Pomegranate,CROPSANITY, +2344,Farming,Harvest Peach,CROPSANITY, +2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", +2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", +2347,Farming,Harvest Coffee Bean,CROPSANITY, +2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Shipping,Shipsanity: Anchor,SHIPSANITY, +2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, +2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, +2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, +2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, +2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, +2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, +2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, +2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Shipping,Shipsanity: Coffee,SHIPSANITY, +2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, +2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, +2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Shipping,Shipsanity: Bread,SHIPSANITY, +2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, +2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Shipping,Shipsanity: Chowder,SHIPSANITY, +2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, +2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Shipping,Shipsanity: Cookies,SHIPSANITY, +2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Shipping,Shipsanity: Escargot,SHIPSANITY, +2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, +2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, +2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, +2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, +2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, +2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, +2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, +2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Shipping,Shipsanity: Omelet,SHIPSANITY, +2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, +2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, +2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, +2518,Shipping,Shipsanity: Pizza,SHIPSANITY, +2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, +2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, +2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, +2529,Shipping,Shipsanity: Salad,SHIPSANITY, +2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, +2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, +2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, +2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, +2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, +2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, +2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, +2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, +2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, +2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Shipping,Shipsanity: Bait,SHIPSANITY, +2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Shipping,Shipsanity: Bomb,SHIPSANITY, +2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, +2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, +2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, +2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, +2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, +2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, +2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, +2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, +2569,Shipping,Shipsanity: Gate,SHIPSANITY, +2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, +2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, +2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, +2578,Shipping,Shipsanity: Magnet,SHIPSANITY, +2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, +2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, +2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Shipping,Shipsanity: Spinner,SHIPSANITY, +2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, +2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, +2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, +2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, +2598,Shipping,Shipsanity: Torch,SHIPSANITY, +2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", +2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, +2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, +2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, +2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, +2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, +2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, +2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Shipping,Shipsanity: Oil,SHIPSANITY, +2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Shipping,Shipsanity: Rice,SHIPSANITY, +2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Shipping,Shipsanity: Sugar,SHIPSANITY, +2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, +2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, +2765,Shipping,Shipsanity: Alamite,SHIPSANITY, +2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, +2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, +2769,Shipping,Shipsanity: Baryte,SHIPSANITY, +2770,Shipping,Shipsanity: Basalt,SHIPSANITY, +2771,Shipping,Shipsanity: Bixite,SHIPSANITY, +2772,Shipping,Shipsanity: Calcite,SHIPSANITY, +2773,Shipping,Shipsanity: Celestine,SHIPSANITY, +2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Shipping,Shipsanity: Diamond,SHIPSANITY, +2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, +2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Shipping,Shipsanity: Emerald,SHIPSANITY, +2780,Shipping,Shipsanity: Esperite,SHIPSANITY, +2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, +2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Shipping,Shipsanity: Geminite,SHIPSANITY, +2788,Shipping,Shipsanity: Geode,SHIPSANITY, +2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Shipping,Shipsanity: Granite,SHIPSANITY, +2792,Shipping,Shipsanity: Helvite,SHIPSANITY, +2793,Shipping,Shipsanity: Hematite,SHIPSANITY, +2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Shipping,Shipsanity: Jade,SHIPSANITY, +2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, +2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, +2799,Shipping,Shipsanity: Jasper,SHIPSANITY, +2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, +2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Shipping,Shipsanity: Limestone,SHIPSANITY, +2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, +2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, +2805,Shipping,Shipsanity: Malachite,SHIPSANITY, +2806,Shipping,Shipsanity: Marble,SHIPSANITY, +2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, +2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, +2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, +2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, +2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, +2814,Shipping,Shipsanity: Opal,SHIPSANITY, +2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, +2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, +2825,Shipping,Shipsanity: Quartz,SHIPSANITY, +2826,Shipping,Shipsanity: Ruby,SHIPSANITY, +2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, +2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Shipping,Shipsanity: Slate,SHIPSANITY, +2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, +2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, +2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, +2835,Shipping,Shipsanity: Topaz,SHIPSANITY, +2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, +2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, +2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, +2848,Shipping,Shipsanity: Hay,SHIPSANITY, +2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Shipping,Shipsanity: Pearl,SHIPSANITY, +2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, +2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Shipping,Shipsanity: White Algae,SHIPSANITY, +2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, +2858,Shipping,Shipsanity: Acorn,SHIPSANITY, +2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, +2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, +2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, +2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, +2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, +2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, +2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, +2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, +2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, +2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, +2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Shipping,Shipsanity: Trash,SHIPSANITY, +2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, +2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", +2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Shipping,Shipsanity: Movie Ticket,"SHIPSANITY", +2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", +3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", +3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", +3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", +3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", +3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", +3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", +3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", +3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", +3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", +3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3201,Kitchen,Cook Algae Soup,COOKSANITY, +3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", +3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, +3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", +3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", +3206,Kitchen,Cook Bean Hotpot,COOKSANITY, +3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", +3208,Kitchen,Cook Blueberry Tart,COOKSANITY, +3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", +3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", +3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", +3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, +3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", +3214,Kitchen,Cook Chowder,COOKSANITY, +3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", +3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", +3217,Kitchen,Cook Cookies,COOKSANITY, +3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", +3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", +3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, +3221,Kitchen,Cook Crispy Bass,COOKSANITY, +3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, +3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, +3224,Kitchen,Cook Escargot,COOKSANITY, +3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, +3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", +3227,Kitchen,Cook Fish Stew,COOKSANITY, +3228,Kitchen,Cook Fish Taco,COOKSANITY, +3229,Kitchen,Cook Fried Calamari,COOKSANITY, +3230,Kitchen,Cook Fried Eel,COOKSANITY, +3231,Kitchen,Cook Fried Egg,COOKSANITY, +3232,Kitchen,Cook Fried Mushroom,COOKSANITY, +3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", +3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", +3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", +3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", +3237,Kitchen,Cook Ice Cream,COOKSANITY, +3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", +3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", +3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", +3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", +3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", +3243,Kitchen,Cook Miner's Treat,COOKSANITY, +3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", +3245,Kitchen,Cook Pale Broth,COOKSANITY, +3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", +3247,Kitchen,Cook Parsnip Soup,COOKSANITY, +3248,Kitchen,Cook Pepper Poppers,COOKSANITY, +3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", +3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", +3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", +3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", +3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", +3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", +3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, +3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", +3257,Kitchen,Cook Red Plate,COOKSANITY, +3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, +3259,Kitchen,Cook Rice Pudding,COOKSANITY, +3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", +3261,Kitchen,Cook Roots Platter,COOKSANITY, +3262,Kitchen,Cook Salad,COOKSANITY, +3263,Kitchen,Cook Salmon Dinner,COOKSANITY, +3264,Kitchen,Cook Sashimi,COOKSANITY, +3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, +3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", +3267,Kitchen,Cook Spaghetti,COOKSANITY, +3268,Kitchen,Cook Spicy Eel,COOKSANITY, +3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, +3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", +3271,Kitchen,Cook Strange Bun,COOKSANITY, +3272,Kitchen,Cook Stuffing,COOKSANITY, +3273,Kitchen,Cook Super Meal,COOKSANITY, +3274,Kitchen,Cook Survival Burger,COOKSANITY, +3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, +3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", +3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, +3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", +3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", +3280,Kitchen,Cook Vegetable Medley,COOKSANITY, +3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, +3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3401,Farm,Craft Cherry Bomb,CRAFTSANITY, +3402,Farm,Craft Bomb,CRAFTSANITY, +3403,Farm,Craft Mega Bomb,CRAFTSANITY, +3404,Farm,Craft Gate,CRAFTSANITY, +3405,Farm,Craft Wood Fence,CRAFTSANITY, +3406,Farm,Craft Stone Fence,CRAFTSANITY, +3407,Farm,Craft Iron Fence,CRAFTSANITY, +3408,Farm,Craft Hardwood Fence,CRAFTSANITY, +3409,Farm,Craft Sprinkler,CRAFTSANITY, +3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, +3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, +3412,Farm,Craft Bee House,CRAFTSANITY, +3413,Farm,Craft Cask,CRAFTSANITY, +3414,Farm,Craft Cheese Press,CRAFTSANITY, +3415,Farm,Craft Keg,CRAFTSANITY, +3416,Farm,Craft Loom,CRAFTSANITY, +3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, +3418,Farm,Craft Oil Maker,CRAFTSANITY, +3419,Farm,Craft Preserves Jar,CRAFTSANITY, +3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, +3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, +3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, +3423,Farm,Craft Speed-Gro,CRAFTSANITY, +3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, +3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", +3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, +3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, +3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", +3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, +3430,Farm,Craft Spring Seeds,CRAFTSANITY, +3431,Farm,Craft Summer Seeds,CRAFTSANITY, +3432,Farm,Craft Fall Seeds,CRAFTSANITY, +3433,Farm,Craft Winter Seeds,CRAFTSANITY, +3434,Farm,Craft Ancient Seeds,CRAFTSANITY, +3435,Farm,Craft Grass Starter,CRAFTSANITY, +3436,Farm,Craft Tea Sapling,CRAFTSANITY, +3437,Farm,Craft Fiber Seeds,CRAFTSANITY, +3438,Farm,Craft Wood Floor,CRAFTSANITY, +3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, +3440,Farm,Craft Straw Floor,CRAFTSANITY, +3441,Farm,Craft Weathered Floor,CRAFTSANITY, +3442,Farm,Craft Crystal Floor,CRAFTSANITY, +3443,Farm,Craft Stone Floor,CRAFTSANITY, +3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, +3445,Farm,Craft Brick Floor,CRAFTSANITY, +3446,Farm,Craft Wood Path,CRAFTSANITY, +3447,Farm,Craft Gravel Path,CRAFTSANITY, +3448,Farm,Craft Cobblestone Path,CRAFTSANITY, +3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, +3450,Farm,Craft Crystal Path,CRAFTSANITY, +3451,Farm,Craft Spinner,CRAFTSANITY, +3452,Farm,Craft Trap Bobber,CRAFTSANITY, +3453,Farm,Craft Cork Bobber,CRAFTSANITY, +3454,Farm,Craft Quality Bobber,CRAFTSANITY, +3455,Farm,Craft Treasure Hunter,CRAFTSANITY, +3456,Farm,Craft Dressed Spinner,CRAFTSANITY, +3457,Farm,Craft Barbed Hook,CRAFTSANITY, +3458,Farm,Craft Magnet,CRAFTSANITY, +3459,Farm,Craft Bait,CRAFTSANITY, +3460,Farm,Craft Wild Bait,CRAFTSANITY, +3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", +3462,Farm,Craft Crab Pot,CRAFTSANITY, +3463,Farm,Craft Sturdy Ring,CRAFTSANITY, +3464,Farm,Craft Warrior Ring,CRAFTSANITY, +3465,Farm,Craft Ring of Yoba,CRAFTSANITY, +3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", +3467,Farm,Craft Glowstone Ring,CRAFTSANITY, +3468,Farm,Craft Iridium Band,CRAFTSANITY, +3469,Farm,Craft Wedding Ring,CRAFTSANITY, +3470,Farm,Craft Field Snack,CRAFTSANITY, +3471,Farm,Craft Bug Steak,CRAFTSANITY, +3472,Farm,Craft Life Elixir,CRAFTSANITY, +3473,Farm,Craft Oil of Garlic,CRAFTSANITY, +3474,Farm,Craft Monster Musk,CRAFTSANITY, +3475,Farm,Craft Fairy Dust,CRAFTSANITY, +3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, +3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, +3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, +3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, +3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", +3481,Farm,Craft Rain Totem,CRAFTSANITY, +3482,Farm,Craft Torch,CRAFTSANITY, +3483,Farm,Craft Campfire,CRAFTSANITY, +3484,Farm,Craft Wooden Brazier,CRAFTSANITY, +3485,Farm,Craft Stone Brazier,CRAFTSANITY, +3486,Farm,Craft Gold Brazier,CRAFTSANITY, +3487,Farm,Craft Carved Brazier,CRAFTSANITY, +3488,Farm,Craft Stump Brazier,CRAFTSANITY, +3489,Farm,Craft Barrel Brazier,CRAFTSANITY, +3490,Farm,Craft Skull Brazier,CRAFTSANITY, +3491,Farm,Craft Marble Brazier,CRAFTSANITY, +3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, +3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, +3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, +3495,Farm,Craft Bone Mill,CRAFTSANITY, +3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, +3497,Farm,Craft Crystalarium,CRAFTSANITY, +3498,Farm,Craft Furnace,CRAFTSANITY, +3499,Farm,Craft Geode Crusher,CRAFTSANITY, +3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", +3501,Farm,Craft Lightning Rod,CRAFTSANITY, +3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", +3503,Farm,Craft Recycling Machine,CRAFTSANITY, +3504,Farm,Craft Seed Maker,CRAFTSANITY, +3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, +3506,Farm,Craft Slime Incubator,CRAFTSANITY, +3507,Farm,Craft Solar Panel,CRAFTSANITY, +3508,Farm,Craft Tapper,CRAFTSANITY, +3509,Farm,Craft Worm Bin,CRAFTSANITY, +3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, +3511,Farm,Craft Wicked Statue,CRAFTSANITY, +3512,Farm,Craft Flute Block,CRAFTSANITY, +3513,Farm,Craft Drum Block,CRAFTSANITY, +3514,Farm,Craft Chest,CRAFTSANITY, +3515,Farm,Craft Stone Chest,CRAFTSANITY, +3516,Farm,Craft Wood Sign,CRAFTSANITY, +3517,Farm,Craft Stone Sign,CRAFTSANITY, +3518,Farm,Craft Dark Sign,CRAFTSANITY, +3519,Farm,Craft Garden Pot,CRAFTSANITY, +3520,Farm,Craft Scarecrow,CRAFTSANITY, +3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, +3522,Farm,Craft Staircase,CRAFTSANITY, +3523,Farm,Craft Explosive Ammo,CRAFTSANITY, +3524,Farm,Craft Transmute (Fe),CRAFTSANITY, +3525,Farm,Craft Transmute (Au),CRAFTSANITY, +3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, +3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, +3528,Farm,Craft Farm Computer,CRAFTSANITY, +3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", +3530,Farm,Craft Cookout Kit,CRAFTSANITY, +3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, +3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, +3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, +3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, +3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, +3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, +3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, +3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, +3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, +3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, +3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, +3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, +3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", +3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, +3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, +3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, +3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, +3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, +3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, +3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, +3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, +3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, +3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, +3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, +3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", +3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY,GINGER_ISLAND", +5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic +5502,Magic Altar,Analyze: Till,MANDATORY,Magic +5503,Magic Altar,Analyze: Water,MANDATORY,Magic +5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic +5505,Magic Altar,Analyze: Evac,MANDATORY,Magic +5506,Magic Altar,Analyze: Haste,MANDATORY,Magic +5507,Magic Altar,Analyze: Heal,MANDATORY,Magic +5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic +5509,Magic Altar,Analyze: Descend,MANDATORY,Magic +5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic +5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic +5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic +5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic +5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic +5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic +5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic +5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic +5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic +5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic +5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic +6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas +6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas +6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas +6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas +6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas +6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas +6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas +6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas +6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas +6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas +6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas +6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas +6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas +6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas +6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba +6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba +6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba +6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba +6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba +6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba +6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba +6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba +6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba +6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba +6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) +6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) +6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) +6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) +6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) +6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) +6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) +6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) +6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) +6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) +6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC +6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC +6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC +6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC +6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC +6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC +6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC +6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC +6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC +6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC +6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC +6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC +6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC +6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC +6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick +6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick +6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick +6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick +6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick +6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick +6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick +6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick +6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick +6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick +6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick +6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick +6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick +6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick +6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC +6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC +6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC +6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC +6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC +6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC +6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC +6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC +6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC +6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC +6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC +6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC +6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC +6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC +6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited +6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited +6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited +6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited +6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited +6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited +6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited +6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited +6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited +6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited +6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited +6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited +6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited +6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited +6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene +6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene +6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene +6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene +6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene +6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene +6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene +6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene +6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene +6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene +6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene +6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene +6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene +6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene +6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC +6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC +6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC +6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC +6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC +6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC +6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC +6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC +6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC +6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC +6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley +6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley +6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley +6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley +6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley +6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley +6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley +6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley +6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley +6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley +6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley +6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley +6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley +6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded +6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded +6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded +6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded +6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded +6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded +6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded +6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded +6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded +6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded +6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded +6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded +6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded +6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded +6153,Galmoran Outpost,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Galmoran Outpost,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Galmoran Outpost,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Galmoran Outpost,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Galmoran Outpost,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Galmoran Outpost,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Galmoran Outpost,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Galmoran Outpost,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Galmoran Outpost,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Galmoran Outpost,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Galmoran Outpost,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Galmoran Outpost,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Galmoran Outpost,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Galmoran Outpost,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded +6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded +6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded +6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded +6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded +6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded +6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded +6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded +6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded +6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded +6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded +6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded +6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded +6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded +6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded +6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded +6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded +6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded +6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded +6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded +6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded +6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded +6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded +6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded +6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded +6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded +6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded +6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded +6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded +6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded +6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded +6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded +6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded +6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded +6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded +6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded +6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded +6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded +6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded +6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded +6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded +6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded +6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded +6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded +6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded +6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded +6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded +6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded +6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded +6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded +6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded +6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded +6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded +6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded +6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded +6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded +6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded +6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded +6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded +6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded +6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded +6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded +6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded +6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded +6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded +6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded +6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded +6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded +6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6273,Scarlett's House,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded +6274,Scarlett's House,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded +6275,Scarlett's House,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded +6276,Scarlett's House,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded +6277,Scarlett's House,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded +6278,Scarlett's House,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded +6279,Scarlett's House,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded +6280,Scarlett's House,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded +6281,Scarlett's House,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded +6282,Scarlett's House,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded +6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded +6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded +6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded +6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded +6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded +6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded +6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded +6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded +6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded +6303,Witch's Swamp,Friendsanity: Zic 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6304,Witch's Swamp,Friendsanity: Zic 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6305,Witch's Swamp,Friendsanity: Zic 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6306,Witch's Swamp,Friendsanity: Zic 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6307,Witch's Swamp,Friendsanity: Zic 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6308,Witch's Swamp,Friendsanity: Zic 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6309,Witch's Swamp,Friendsanity: Zic 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6310,Witch's Swamp,Friendsanity: Zic 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6311,Witch's Swamp,Friendsanity: Zic 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6312,Witch's Swamp,Friendsanity: Zic 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch +6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch +6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch +6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch +6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch +6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch +6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch +6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch +6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch +6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch +6323,Mouse House,Friendsanity: Lacey 1 <3,FRIENDSANITY,Hat Mouse Lacey +6324,Mouse House,Friendsanity: Lacey 2 <3,FRIENDSANITY,Hat Mouse Lacey +6325,Mouse House,Friendsanity: Lacey 3 <3,FRIENDSANITY,Hat Mouse Lacey +6326,Mouse House,Friendsanity: Lacey 4 <3,FRIENDSANITY,Hat Mouse Lacey +6327,Mouse House,Friendsanity: Lacey 5 <3,FRIENDSANITY,Hat Mouse Lacey +6328,Mouse House,Friendsanity: Lacey 6 <3,FRIENDSANITY,Hat Mouse Lacey +6329,Mouse House,Friendsanity: Lacey 7 <3,FRIENDSANITY,Hat Mouse Lacey +6330,Mouse House,Friendsanity: Lacey 8 <3,FRIENDSANITY,Hat Mouse Lacey +6331,Mouse House,Friendsanity: Lacey 9 <3,FRIENDSANITY,Hat Mouse Lacey +6332,Mouse House,Friendsanity: Lacey 10 <3,FRIENDSANITY,Hat Mouse Lacey +6333,Mouse House,Friendsanity: Lacey 11 <3,FRIENDSANITY,Hat Mouse Lacey +6334,Mouse House,Friendsanity: Lacey 12 <3,FRIENDSANITY,Hat Mouse Lacey +6335,Mouse House,Friendsanity: Lacey 13 <3,FRIENDSANITY,Hat Mouse Lacey +6336,Mouse House,Friendsanity: Lacey 14 <3,FRIENDSANITY,Hat Mouse Lacey +6337,Boarding House - First Floor,Friendsanity: Joel 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6338,Boarding House - First Floor,Friendsanity: Joel 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6339,Boarding House - First Floor,Friendsanity: Joel 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6340,Boarding House - First Floor,Friendsanity: Joel 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6341,Boarding House - First Floor,Friendsanity: Joel 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6342,Boarding House - First Floor,Friendsanity: Joel 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6343,Boarding House - First Floor,Friendsanity: Joel 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6344,Boarding House - First Floor,Friendsanity: Joel 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6345,Boarding House - First Floor,Friendsanity: Joel 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6346,Boarding House - First Floor,Friendsanity: Joel 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6347,Boarding House - First Floor,Friendsanity: Sheila 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6348,Boarding House - First Floor,Friendsanity: Sheila 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6349,Boarding House - First Floor,Friendsanity: Sheila 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6350,Boarding House - First Floor,Friendsanity: Sheila 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6351,Boarding House - First Floor,Friendsanity: Sheila 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6352,Boarding House - First Floor,Friendsanity: Sheila 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6353,Boarding House - First Floor,Friendsanity: Sheila 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6354,Boarding House - First Floor,Friendsanity: Sheila 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6355,Boarding House - First Floor,Friendsanity: Sheila 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6356,Boarding House - First Floor,Friendsanity: Sheila 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6357,Boarding House - First Floor,Friendsanity: Sheila 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6358,Boarding House - First Floor,Friendsanity: Sheila 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6359,Boarding House - First Floor,Friendsanity: Sheila 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6360,Boarding House - First Floor,Friendsanity: Sheila 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6361,The Lost Valley,Friendsanity: Gregory 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6362,The Lost Valley,Friendsanity: Gregory 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6363,The Lost Valley,Friendsanity: Gregory 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6364,The Lost Valley,Friendsanity: Gregory 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6365,The Lost Valley,Friendsanity: Gregory 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6366,The Lost Valley,Friendsanity: Gregory 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6367,The Lost Valley,Friendsanity: Gregory 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6368,The Lost Valley,Friendsanity: Gregory 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6369,The Lost Valley,Friendsanity: Gregory 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6370,The Lost Valley,Friendsanity: Gregory 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6371,The Lost Valley,Friendsanity: Gregory 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6372,The Lost Valley,Friendsanity: Gregory 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6373,The Lost Valley,Friendsanity: Gregory 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6374,The Lost Valley,Friendsanity: Gregory 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack +7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod +7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods +7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods +7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods +7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods +7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods +7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods +7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods +7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods +7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods +7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods +7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods +7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods +7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods +7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods +7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods +7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods +7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods +7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator +7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator +7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator +7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator +7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator +7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator +7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator +7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods +7051,Abandoned Mines - 1A,Abandoned Treasure - Floor 1A,MANDATORY,Boarding House and Bus Stop Extension +7052,Abandoned Mines - 1B,Abandoned Treasure - Floor 1B,MANDATORY,Boarding House and Bus Stop Extension +7053,Abandoned Mines - 2A,Abandoned Treasure - Floor 2A,MANDATORY,Boarding House and Bus Stop Extension +7054,Abandoned Mines - 2B,Abandoned Treasure - Floor 2B,MANDATORY,Boarding House and Bus Stop Extension +7055,Abandoned Mines - 3,Abandoned Treasure - Floor 3,MANDATORY,Boarding House and Bus Stop Extension +7056,Abandoned Mines - 4,Abandoned Treasure - Floor 4,MANDATORY,Boarding House and Bus Stop Extension +7057,Abandoned Mines - 5,Abandoned Treasure - Floor 5,MANDATORY,Boarding House and Bus Stop Extension +7401,Farm,Cook Magic Elixir,COOKSANITY,Magic +7402,Farm,Craft Travel Core,CRAFTSANITY,Magic +7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded +7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded +7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7407,Farm,Craft Glass Path,CRAFTSANITY,Archaeology +7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology +7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology +7410,Farm,Craft Bone Path,CRAFTSANITY,Archaeology +7411,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology +7412,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology +7413,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology +7414,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology +7415,Farm,Craft Grinder,CRAFTSANITY,Archaeology +7416,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology +7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology +7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology +7419,Farm,Craft Neanderthal Skeleton,CRAFTSANITY,Boarding House and Bus Stop Extension +7617,Farm,Craft Pterodactyl Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension +7618,Farm,Craft Pterodactyl Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension +7619,Farm,Craft Pterodactyl Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension +7620,Farm,Craft T-Rex Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension +7621,Farm,Craft T-Rex Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension +7622,Farm,Craft T-Rex Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension +7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic +7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic +7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7501,Mountain,Missing Envelope,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) +7503,Forest,Mr.Ginger's request,"STORY_QUEST",Mister Ginger (cat npc) +7504,Forest,Juna's Drink Request,"STORY_QUEST",Juna - Roommate NPC +7505,Forest,Juna's BFF Request,"STORY_QUEST",Juna - Roommate NPC +7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC +7507,Adventurer's Guild,Marlon's Boat,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7508,Railroad,The Railroad Boulder,"STORY_QUEST",Stardew Valley Expanded +7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded +7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded +7511,Adventurer's Guild,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded +7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded +7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +7520,Witch's Swamp,A New Pot,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul +7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +7523,Boarding House - First Floor,Pumpkin Soup,"MANDATORY,STORY_QUEST",Boarding House and Bus Stop Extension +7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas +7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas +7526,Mouse House,Hats for the Hat Mouse,"MANDATORY,STORY_QUEST",Hat Mouse Lacey +7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded +7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded +7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded +7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded +7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded +7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded +7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded +7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded +7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded +7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded +7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7615,Boarding House - First Floor,Special Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension +7616,Mines Dwarf Shop,Neanderthal Skeleton Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7617,Mines Dwarf Shop,Pterodactyl Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7618,Mines Dwarf Shop,Pterodactyl Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7619,Mines Dwarf Shop,Pterodactyl Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7620,Mines Dwarf Shop,T-Rex Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7621,Mines Dwarf Shop,T-Rex Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7622,Mines Dwarf Shop,T-Rex Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7654,Lance's House Main,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded +7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded +7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded +7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded +7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7706,Highlands Outside,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded +7708,Highlands Outside,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded +7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded +7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded +7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded +7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded +7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded +7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded +7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded +7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded +7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded +7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded +7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7731,Witch's Swamp,Fishsanity: Purple Algae,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded +7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded +7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul +7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul +8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Magic +8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded +8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded +8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded +8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded +8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded +8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded +8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded +8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY",Stardew Valley Expanded +8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded +8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded +8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded +8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded +8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded +8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded +8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded +8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded +8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded +8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded +8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded +8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded +8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded +8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology +8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology +8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology +8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology +8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology +8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology +8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology +8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology +8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology +8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology +8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology +8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology +8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology +8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology +8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology +8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology +8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology +8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology +8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology +8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology +8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology +8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology +8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology +8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology +8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology +8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology +8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology +8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology +8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology +8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology +8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology +8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology +8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology +8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology +8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology +8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology +8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology +8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology +8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology +8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology +8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology +8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology +8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology +8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology +8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology +8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology +8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology +8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology +8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology +8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology +8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology +8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology +8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology +8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology +8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology +8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology +8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology +8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology +8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology +8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology +8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology +8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology +8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology +8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology +8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology +8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite Fossil,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite Fossil,SHIPSANITY,Archaeology +8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology +8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology +8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology +8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology +8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology +8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology +8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology +8203,Shipping,Shipsanity: Brown Amanita,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +8218,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension +8219,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8220,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension +8221,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +8222,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8223,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension +8224,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension +8225,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8226,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8227,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8228,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8229,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8230,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension +8231,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8232,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8233,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8234,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension +8235,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8236,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8237,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension From e827801527db956f99e0d2a52daf87e0cf2bbe24 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 23:36:48 -0600 Subject: [PATCH 454/482] Fix quest double dip and mandatory quests --- worlds/stardew_valley/data/items.csv | 6 +++--- worlds/stardew_valley/data/locations.csv | 19 ++++++++----------- worlds/stardew_valley/items.py | 20 ++++++++++++++++++-- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 7507ba38291b..b4f8da063131 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -801,11 +801,11 @@ id,name,classification,groups,mod_name 10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10412,Crayfish Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10412,Crayfish Soup Recipe,progression,,Distant Lands - Witch Swamp Overhaul 10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10415,Ginger Tincture Recipe,progression,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -10416,Special Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension +10415,Ginger Tincture Recipe,progression,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +10416,Special Pumpkin Soup Recipe,progression,,Boarding House and Bus Stop Extension 10450,Void Mint Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul 10451,Vile Ancient Fruit Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index dfb2691a752c..bd4430ac9a4e 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2608,7 +2608,6 @@ id,region,name,tags,mod_name 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded 7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7456,Witch's Swamp,Ginger Tincture Recipe,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul 7501,Mountain,Missing Envelope,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) 7502,Forest,Lost Emerald Ring,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) 7503,Forest,Mr.Ginger's request,"STORY_QUEST",Mister Ginger (cat npc) @@ -2619,21 +2618,21 @@ id,region,name,tags,mod_name 7508,Railroad,The Railroad Boulder,"STORY_QUEST",Stardew Valley Expanded 7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded 7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded -7511,Adventurer's Guild,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7511,Lance's House Main,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded 7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded 7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded 7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7520,Witch's Swamp,A New Pot,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul -7521,Witch's Swamp,Fancy Blanket Task,"MANDATORY,STORY_QUEST",Distant Lands - Witch Swamp Overhaul -7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7523,Boarding House - First Floor,Pumpkin Soup,"MANDATORY,STORY_QUEST",Boarding House and Bus Stop Extension +7519,Witch's Swamp,Corrupted Crops Task,"STORY_QUEST,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7520,Witch's Swamp,A New Pot,STORY_QUEST,Distant Lands - Witch Swamp Overhaul +7521,Witch's Swamp,Fancy Blanket Task,STORY_QUEST,Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,"STORY_QUEST,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7523,Boarding House - First Floor,Pumpkin Soup,STORY_QUEST,Boarding House and Bus Stop Extension 7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas 7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas -7526,Mouse House,Hats for the Hat Mouse,"MANDATORY,STORY_QUEST",Hat Mouse Lacey +7526,Mouse House,Hats for the Hat Mouse,STORY_QUEST,Hat Mouse Lacey 7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded 7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded 7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded @@ -2648,6 +2647,7 @@ id,region,name,tags,mod_name 7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul 7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul 7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7565,Kitchen,Cook Special Pumpkin Soup,COOKSANITY,Boarding House and Bus Stop Extension 7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded @@ -2659,10 +2659,8 @@ id,region,name,tags,mod_name 7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded 7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded 7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7612,Witch's Swamp,Crayfish Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul 7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7615,Boarding House - First Floor,Special Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Boarding House and Bus Stop Extension 7616,Mines Dwarf Shop,Neanderthal Skeleton Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension 7617,Mines Dwarf Shop,Pterodactyl Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension 7618,Mines Dwarf Shop,Pterodactyl Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension @@ -2673,7 +2671,6 @@ id,region,name,tags,mod_name 7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded 7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded 7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7654,Lance's House Main,Lance's Diamond Wand,"MANDATORY,GINGER_ISLAND",Stardew Valley Expanded 7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded 7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded 7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 6e590ae1ef1b..197ba61d49a7 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -362,8 +362,9 @@ def create_special_quest_rewards(item_factory: StardewItemFactory, options: Star items.append(item_factory(Wallet.iridium_snake_milk)) items.append(item_factory("Fairy Dust Recipe")) items.append(item_factory("Dark Talisman")) - if ModNames.sve in options.mods: - create_special_quest_rewards_sve(item_factory, options, items) + create_special_quest_rewards_sve(item_factory, options, items) + create_distant_lands_quest_rewards(item_factory, options, items) + create_boarding_house_quest_rewards(item_factory, options, items) def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): @@ -615,6 +616,21 @@ def create_special_quest_rewards_sve(item_factory: StardewItemFactory, options: items.extend([item_factory(item) for item in SVEQuestItem.sve_quest_items_ginger_island]) +def create_distant_lands_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if options.quest_locations < 0 or ModNames.distant_lands not in options.mods: + return + items.append(item_factory("Crayfish Soup Recipe")) + if options.exclude_ginger_island == ExcludeGingerIsland.option_true: + return + items.append(item_factory("Ginger Tincture Recipe")) + + +def create_boarding_house_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]): + if options.quest_locations < 0 or ModNames.boarding_house not in options.mods: + return + items.append(item_factory("Special Pumpkin Soup Recipe")) + + def create_unique_filler_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random, available_item_slots: int) -> List[Item]: items = [] From 4ccc1bca36c3236e057bb7aa90fb473cbf893168 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 23:37:04 -0600 Subject: [PATCH 455/482] Remove Lance's Wand rule and test --- worlds/stardew_valley/rules.py | 2 -- worlds/stardew_valley/test/mods/TestMods.py | 18 ------------------ 2 files changed, 20 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index cb88afc4e7a1..5b3d082c9554 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -947,8 +947,6 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla logic.received(SVEQuestItem.marlon_boat_paddle)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), logic.received(SVEQuestItem.fable_reef_portal)) - MultiWorldRules.set_rule(multiworld.get_location(SVELocation.diamond_wand, player), - logic.quest.can_complete_quest(ModQuest.MonsterCrops) & logic.region.can_reach(SVERegion.lances_house)) MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index e5504a8f9ee8..a2a26d8a4ebe 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -57,24 +57,6 @@ class TestBaseLocationDependencies(SVTestBase): SeasonRandomization.internal_name: SeasonRandomization.option_randomized } - def test_lance_chest_requires_quest_thoroughly(self): # the method can be reused for other locations that seem troublesome. - item_list = ["Spring", "Summer", "Fall", "Winter", "Marlon's Boat Paddle"] - item_list.extend(weapon for weapon in ["Progressive Weapon"]*3) - item_list.extend(tool for tool in ["Progressive Axe"]*2) - item_list.extend(tool for tool in ["Progressive Pickaxe"]*2) - missing_items = [] - missing_items.extend(item_list) - rule = self.world.logic.region.can_reach_location("Lance's Diamond Wand") - self.assertFalse(rule(self.multiworld.state), msg="Has No Items") - for item in item_list: - missing_items.remove(item) - created_item = self.world.create_item(item) - self.multiworld.state.collect(created_item, event=False) - if not missing_items: - continue - self.assertFalse(rule(self.multiworld.state), rule.explain(self.multiworld.state)) - self.assertTrue(rule(self.multiworld.state), rule.explain(self.multiworld.state)) - class TestBaseItemGeneration(SVTestBase): options = { From 1c33e53b70f30eadc0bdd6c170f1bff00eb7b75b Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 23:43:06 -0600 Subject: [PATCH 456/482] Fix boarding house rules --- worlds/stardew_valley/rules.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 5b3d082c9554..72d907f42ee7 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -938,6 +938,7 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl MultiWorldRules.set_rule(multiworld.get_location(location, player), logic.registry.sve_location_rules[location]) set_sve_ginger_island_rules(logic, multiworld, player, world_options) + set_boarding_house_rules(logic, multiworld, player, world_options) def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): @@ -954,11 +955,5 @@ def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, pla def set_boarding_house_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.boarding_house not in world_options.mods: return - MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.abandoned_mines_2b_to_abandoned_mines_3, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - MultiWorldRules.set_rule(MultiWorld.get_entrance(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, player), - logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) \ No newline at end of file + MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, player), + logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) From 4db3bd9c37125b2ad491bd57c96e4e12ef714048 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Mon, 22 Jan 2024 23:57:20 -0600 Subject: [PATCH 457/482] Fill out monster location data for BH --- worlds/stardew_valley/data/monster_data.py | 6 ++++++ worlds/stardew_valley/mods/mod_monster_locations.py | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/worlds/stardew_valley/data/monster_data.py b/worlds/stardew_valley/data/monster_data.py index 7d50ce0ac1f3..5a4ebd67d5f5 100644 --- a/worlds/stardew_valley/data/monster_data.py +++ b/worlds/stardew_valley/data/monster_data.py @@ -139,6 +139,12 @@ def register_monster_modification(mod_name: str, monster: StardewMonster, modifi register_monster_modification(ModNames.boarding_house, pepper_rex, update_monster_locations) register_monster_modification(ModNames.boarding_house, shadow_brute, update_monster_locations) +register_monster_modification(ModNames.boarding_house, iridium_bat, update_monster_locations) +register_monster_modification(ModNames.boarding_house, frost_bat, update_monster_locations) +register_monster_modification(ModNames.boarding_house, cave_fly, update_monster_locations) +register_monster_modification(ModNames.boarding_house, bat, update_monster_locations) +register_monster_modification(ModNames.boarding_house, grub, update_monster_locations) +register_monster_modification(ModNames.boarding_house, bug, update_monster_locations) def all_monsters_by_name_given_mods(mods: Set[str]) -> Dict[str, StardewMonster]: diff --git a/worlds/stardew_valley/mods/mod_monster_locations.py b/worlds/stardew_valley/mods/mod_monster_locations.py index 4838caf1ff5f..ac4c1c241714 100644 --- a/worlds/stardew_valley/mods/mod_monster_locations.py +++ b/worlds/stardew_valley/mods/mod_monster_locations.py @@ -22,8 +22,15 @@ } boardinghouse_monsters_locations: Dict[str, Tuple[str, ...]] = { - Monster.shadow_brute: (BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), - Monster.pepper_rex: (BoardingHouseRegion.lost_valley_ruins,) + Monster.shadow_brute: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), + Monster.pepper_rex: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), + Monster.iridium_bat: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), + Monster.grub: (BoardingHouseRegion.abandoned_mines_1a, BoardingHouseRegion.abandoned_mines_1b, BoardingHouseRegion.abandoned_mines_2a, + BoardingHouseRegion.abandoned_mines_2b,), + Monster.bug: (BoardingHouseRegion.abandoned_mines_1a, BoardingHouseRegion.abandoned_mines_1b,), + Monster.bat: (BoardingHouseRegion.abandoned_mines_2a, BoardingHouseRegion.abandoned_mines_2b,), + Monster.cave_fly: (BoardingHouseRegion.abandoned_mines_3, BoardingHouseRegion.abandoned_mines_4, BoardingHouseRegion.abandoned_mines_5,), + Monster.frost_bat: (BoardingHouseRegion.abandoned_mines_3, BoardingHouseRegion.abandoned_mines_4, BoardingHouseRegion.abandoned_mines_5,), } modded_monsters_locations: Dict[str, Dict[str, Tuple[str, ...]]] = { From 8ccecfaa85ffbca1e1843ba626c4f24b42447aac Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 23 Jan 2024 00:10:16 -0600 Subject: [PATCH 458/482] Fix incorrect IDs --- worlds/stardew_valley/data/locations.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index bd4430ac9a4e..752b7e2ecb4b 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2597,12 +2597,12 @@ id,region,name,tags,mod_name 7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology 7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology 7419,Farm,Craft Neanderthal Skeleton,CRAFTSANITY,Boarding House and Bus Stop Extension -7617,Farm,Craft Pterodactyl Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension -7618,Farm,Craft Pterodactyl Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension -7619,Farm,Craft Pterodactyl Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension -7620,Farm,Craft T-Rex Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension -7621,Farm,Craft T-Rex Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension -7622,Farm,Craft T-Rex Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension +7420,Farm,Craft Pterodactyl Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension +7421,Farm,Craft Pterodactyl Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension +7422,Farm,Craft Pterodactyl Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension +7423,Farm,Craft T-Rex Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension +7424,Farm,Craft T-Rex Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension +7425,Farm,Craft T-Rex Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension 7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic 7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic 7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded From 804846c88faa78e88c7c56c428d8948c8a0c42e0 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 23 Jan 2024 01:36:44 -0600 Subject: [PATCH 459/482] Create situational location method --- worlds/stardew_valley/data/locations.csv | 4 ++-- worlds/stardew_valley/locations.py | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 752b7e2ecb4b..19077c3c45d6 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2625,10 +2625,10 @@ id,region,name,tags,mod_name 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded 7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,"STORY_QUEST,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul 7520,Witch's Swamp,A New Pot,STORY_QUEST,Distant Lands - Witch Swamp Overhaul 7521,Witch's Swamp,Fancy Blanket Task,STORY_QUEST,Distant Lands - Witch Swamp Overhaul -7522,Witch's Swamp,Witch's order,"STORY_QUEST,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul 7523,Boarding House - First Floor,Pumpkin Soup,STORY_QUEST,Boarding House and Bus Stop Extension 7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas 7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas diff --git a/worlds/stardew_valley/locations.py b/worlds/stardew_valley/locations.py index 6a8a669c5118..75899559a5f7 100644 --- a/worlds/stardew_valley/locations.py +++ b/worlds/stardew_valley/locations.py @@ -320,13 +320,18 @@ def extend_walnut_purchase_locations(randomized_locations: List[LocationData], o def extend_mandatory_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): mandatory_locations = [location for location in locations_by_tag[LocationTags.MANDATORY]] + filtered_mandatory_locations = filter_disabled_locations(options, mandatory_locations) + randomized_locations.extend(filtered_mandatory_locations) + + +def extend_situational_quest_locations(randomized_locations: List[LocationData], options: StardewValleyOptions): + if options.quest_locations < 0: + return if ModNames.distant_lands in options.mods: if ModNames.alecto in options.mods: - mandatory_locations.append(location_table[ModQuest.WitchOrder]) + randomized_locations.append(location_table[ModQuest.WitchOrder]) else: - mandatory_locations.append(location_table[ModQuest.CorruptedCropsTask]) - filtered_mandatory_locations = filter_disabled_locations(options, mandatory_locations) - randomized_locations.extend(filtered_mandatory_locations) + randomized_locations.append(location_table[ModQuest.CorruptedCropsTask]) def extend_bundle_locations(randomized_locations: List[LocationData], bundle_rooms: List[BundleRoom]): @@ -482,6 +487,7 @@ def create_locations(location_collector: StardewLocationCollector, extend_chefsanity_locations(randomized_locations, options) extend_craftsanity_locations(randomized_locations, options) extend_quests_locations(randomized_locations, options) + extend_situational_quest_locations(randomized_locations, options) for location_data in randomized_locations: location_collector(location_data.name, location_data.code, location_data.region) From 3546efdb578c4dfea7b84a0730ef48cb9d5ab85d Mon Sep 17 00:00:00 2001 From: Witchybun Date: Tue, 23 Jan 2024 01:44:17 -0600 Subject: [PATCH 460/482] No iridium bats in first house --- worlds/stardew_valley/mods/mod_monster_locations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/mod_monster_locations.py b/worlds/stardew_valley/mods/mod_monster_locations.py index ac4c1c241714..96ded1b2fc39 100644 --- a/worlds/stardew_valley/mods/mod_monster_locations.py +++ b/worlds/stardew_valley/mods/mod_monster_locations.py @@ -24,7 +24,7 @@ boardinghouse_monsters_locations: Dict[str, Tuple[str, ...]] = { Monster.shadow_brute: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), Monster.pepper_rex: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), - Monster.iridium_bat: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_1, BoardingHouseRegion.lost_valley_house_2,), + Monster.iridium_bat: (BoardingHouseRegion.lost_valley_ruins, BoardingHouseRegion.lost_valley_house_2,), Monster.grub: (BoardingHouseRegion.abandoned_mines_1a, BoardingHouseRegion.abandoned_mines_1b, BoardingHouseRegion.abandoned_mines_2a, BoardingHouseRegion.abandoned_mines_2b,), Monster.bug: (BoardingHouseRegion.abandoned_mines_1a, BoardingHouseRegion.abandoned_mines_1b,), From f2d62b2cbe6063566ee36d51657c06cb5fa18281 Mon Sep 17 00:00:00 2001 From: Witchybun <96719127+Witchybun@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:33:15 -0600 Subject: [PATCH 461/482] Attempt to fix line endings. --- worlds/stardew_valley/data/items.csv | 1716 +++---- worlds/stardew_valley/data/locations.csv | 5878 +++++++++++----------- 2 files changed, 3797 insertions(+), 3797 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index b4f8da063131..afc45afc5dcb 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -1,858 +1,858 @@ -id,name,classification,groups,mod_name -0,Joja Cola,filler,TRASH, -15,Rusty Key,progression,, -16,Dwarvish Translation Guide,progression,, -17,Bridge Repair,progression,COMMUNITY_REWARD, -18,Greenhouse,progression,COMMUNITY_REWARD, -19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, -20,Minecarts Repair,useful,COMMUNITY_REWARD, -21,Bus Repair,progression,COMMUNITY_REWARD, -22,Progressive Movie Theater,progression,COMMUNITY_REWARD, -23,Stardrop,progression,, -24,Progressive Backpack,progression,, -25,Rusty Sword,filler,"WEAPON,DEPRECATED", -26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", -27,Work Boots,filler,"FOOTWEAR,DEPRECATED", -28,Wooden Blade,filler,"WEAPON,DEPRECATED", -29,Iron Dirk,filler,"WEAPON,DEPRECATED", -30,Wind Spire,filler,"WEAPON,DEPRECATED", -31,Femur,filler,"WEAPON,DEPRECATED", -32,Steel Smallsword,filler,"WEAPON,DEPRECATED", -33,Wood Club,filler,"WEAPON,DEPRECATED", -34,Elf Blade,filler,"WEAPON,DEPRECATED", -37,Slingshot,filler,"WEAPON,DEPRECATED", -38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", -39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", -40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", -41,Silver Saber,filler,"WEAPON,DEPRECATED", -42,Pirate's Sword,filler,"WEAPON,DEPRECATED", -43,Crystal Dagger,filler,"WEAPON,DEPRECATED", -44,Cutlass,filler,"WEAPON,DEPRECATED", -45,Iron Edge,filler,"WEAPON,DEPRECATED", -46,Burglar's Shank,filler,"WEAPON,DEPRECATED", -47,Wood Mallet,filler,"WEAPON,DEPRECATED", -48,Master Slingshot,filler,"WEAPON,DEPRECATED", -49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", -50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", -51,Claymore,filler,"WEAPON,DEPRECATED", -52,Templar's Blade,filler,"WEAPON,DEPRECATED", -53,Kudgel,filler,"WEAPON,DEPRECATED", -54,Shadow Dagger,filler,"WEAPON,DEPRECATED", -55,Obsidian Edge,filler,"WEAPON,DEPRECATED", -56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", -57,Wicked Kris,filler,"WEAPON,DEPRECATED", -58,Bone Sword,filler,"WEAPON,DEPRECATED", -59,Ossified Blade,filler,"WEAPON,DEPRECATED", -60,Space Boots,filler,"FOOTWEAR,DEPRECATED", -61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", -62,Steel Falchion,filler,"WEAPON,DEPRECATED", -63,The Slammer,filler,"WEAPON,DEPRECATED", -64,Skull Key,progression,, -65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, -66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, -67,Progressive Axe,progression,PROGRESSIVE_TOOLS, -68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, -69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, -70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, -71,Golden Scythe,useful,, -72,Progressive Mine Elevator,progression,, -73,Farming Level,progression,SKILL_LEVEL_UP, -74,Fishing Level,progression,SKILL_LEVEL_UP, -75,Foraging Level,progression,SKILL_LEVEL_UP, -76,Mining Level,progression,SKILL_LEVEL_UP, -77,Combat Level,progression,SKILL_LEVEL_UP, -78,Earth Obelisk,progression,WIZARD_BUILDING, -79,Water Obelisk,progression,WIZARD_BUILDING, -80,Desert Obelisk,progression,WIZARD_BUILDING, -81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", -82,Junimo Hut,useful,WIZARD_BUILDING, -83,Gold Clock,progression,WIZARD_BUILDING, -84,Progressive Coop,progression,BUILDING, -85,Progressive Barn,progression,BUILDING, -86,Well,useful,BUILDING, -87,Silo,progression,BUILDING, -88,Mill,progression,BUILDING, -89,Progressive Shed,progression,BUILDING, -90,Fish Pond,progression,BUILDING, -91,Stable,useful,BUILDING, -92,Slime Hutch,progression,BUILDING, -93,Shipping Bin,progression,BUILDING, -94,Beach Bridge,progression,, -95,Adventurer's Guild,progression,DEPRECATED, -96,Club Card,progression,, -97,Magnifying Glass,progression,, -98,Bear's Knowledge,progression,, -99,Iridium Snake Milk,useful,, -100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, -101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, -102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, -103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, -104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, -105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, -106,Galaxy Sword,filler,"WEAPON,DEPRECATED", -107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", -108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", -109,Movement Speed Bonus,progression,, -110,Luck Bonus,progression,, -111,Lava Katana,filler,"WEAPON,DEPRECATED", -112,Progressive House,progression,, -113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, -114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, -115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, -116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, -117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, -118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, -119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, -120,Traveling Merchant Stock Size,useful,, -121,Traveling Merchant Discount,useful,, -122,Return Scepter,useful,, -123,Progressive Season,progression,, -124,Spring,progression,SEASON, -125,Summer,progression,SEASON, -126,Fall,progression,SEASON, -127,Winter,progression,SEASON, -128,Amaranth Seeds,progression,CROPSANITY, -129,Artichoke Seeds,progression,CROPSANITY, -130,Beet Seeds,progression,CROPSANITY, -131,Jazz Seeds,progression,CROPSANITY, -132,Blueberry Seeds,progression,CROPSANITY, -133,Bok Choy Seeds,progression,CROPSANITY, -134,Cauliflower Seeds,progression,CROPSANITY, -135,Corn Seeds,progression,CROPSANITY, -136,Cranberry Seeds,progression,CROPSANITY, -137,Eggplant Seeds,progression,CROPSANITY, -138,Fairy Seeds,progression,CROPSANITY, -139,Garlic Seeds,progression,CROPSANITY, -140,Grape Starter,progression,CROPSANITY, -141,Bean Starter,progression,CROPSANITY, -142,Hops Starter,progression,CROPSANITY, -143,Pepper Seeds,progression,CROPSANITY, -144,Kale Seeds,progression,CROPSANITY, -145,Melon Seeds,progression,CROPSANITY, -146,Parsnip Seeds,progression,CROPSANITY, -147,Poppy Seeds,progression,CROPSANITY, -148,Potato Seeds,progression,CROPSANITY, -149,Pumpkin Seeds,progression,CROPSANITY, -150,Radish Seeds,progression,CROPSANITY, -151,Red Cabbage Seeds,progression,CROPSANITY, -152,Rhubarb Seeds,progression,CROPSANITY, -153,Starfruit Seeds,progression,CROPSANITY, -154,Strawberry Seeds,progression,CROPSANITY, -155,Spangle Seeds,progression,CROPSANITY, -156,Sunflower Seeds,progression,CROPSANITY, -157,Tomato Seeds,progression,CROPSANITY, -158,Tulip Bulb,progression,CROPSANITY, -159,Rice Shoot,progression,CROPSANITY, -160,Wheat Seeds,progression,CROPSANITY, -161,Yam Seeds,progression,CROPSANITY, -162,Cactus Seeds,progression,CROPSANITY, -163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -164,Ancient Seeds Recipe,progression,MUSEUM, -165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -166,Traveling Merchant Metal Detector,progression,MUSEUM, -167,Alex <3,progression,FRIENDSANITY, -168,Elliott <3,progression,FRIENDSANITY, -169,Harvey <3,progression,FRIENDSANITY, -170,Sam <3,progression,FRIENDSANITY, -171,Sebastian <3,progression,FRIENDSANITY, -172,Shane <3,progression,FRIENDSANITY, -173,Abigail <3,progression,FRIENDSANITY, -174,Emily <3,progression,FRIENDSANITY, -175,Haley <3,progression,FRIENDSANITY, -176,Leah <3,progression,FRIENDSANITY, -177,Maru <3,progression,FRIENDSANITY, -178,Penny <3,progression,FRIENDSANITY, -179,Caroline <3,progression,FRIENDSANITY, -180,Clint <3,progression,FRIENDSANITY, -181,Demetrius <3,progression,FRIENDSANITY, -182,Dwarf <3,progression,FRIENDSANITY, -183,Evelyn <3,progression,FRIENDSANITY, -184,George <3,progression,FRIENDSANITY, -185,Gus <3,progression,FRIENDSANITY, -186,Jas <3,progression,FRIENDSANITY, -187,Jodi <3,progression,FRIENDSANITY, -188,Kent <3,progression,FRIENDSANITY, -189,Krobus <3,progression,FRIENDSANITY, -190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", -191,Lewis <3,progression,FRIENDSANITY, -192,Linus <3,progression,FRIENDSANITY, -193,Marnie <3,progression,FRIENDSANITY, -194,Pam <3,progression,FRIENDSANITY, -195,Pierre <3,progression,FRIENDSANITY, -196,Robin <3,progression,FRIENDSANITY, -197,Sandy <3,progression,FRIENDSANITY, -198,Vincent <3,progression,FRIENDSANITY, -199,Willy <3,progression,FRIENDSANITY, -200,Wizard <3,progression,FRIENDSANITY, -201,Pet <3,progression,FRIENDSANITY, -202,Rarecrow #1,progression,"FESTIVAL,RARECROW", -203,Rarecrow #2,progression,"FESTIVAL,RARECROW", -204,Rarecrow #3,progression,"FESTIVAL,RARECROW", -205,Rarecrow #4,progression,"FESTIVAL,RARECROW", -206,Rarecrow #5,progression,"FESTIVAL,RARECROW", -207,Rarecrow #6,progression,"FESTIVAL,RARECROW", -208,Rarecrow #7,progression,"FESTIVAL,RARECROW", -209,Rarecrow #8,progression,"FESTIVAL,RARECROW", -210,Straw Hat,filler,FESTIVAL, -211,Golden Pumpkin,useful,FESTIVAL, -212,Barbed Hook,useful,FESTIVAL, -213,Dressed Spinner,useful,FESTIVAL, -214,Magnet,useful,FESTIVAL, -215,Sailor's Cap,filler,FESTIVAL, -216,Pearl,useful,FESTIVAL, -217,Cone Hat,filler,FESTIVAL, -218,Iridium Fireplace,filler,FESTIVAL, -219,Lupini: Red Eagle,filler,FESTIVAL, -220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, -221,Lupini: Solar Kingdom,filler,FESTIVAL, -222,Lupini: Clouds,filler,FESTIVAL, -223,Lupini: 1000 Years From Now,filler,FESTIVAL, -224,Lupini: Three Trees,filler,FESTIVAL, -225,Lupini: The Serpent,filler,FESTIVAL, -226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, -227,Lupini: Land Of Clay,filler,FESTIVAL, -228,Special Order Board,progression,SPECIAL_ORDER_BOARD, -229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, -230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, -231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, -232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, -233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, -234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, -235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, -236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, -237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, -239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", -244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", -251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", -260,Boat Repair,progression,GINGER_ISLAND, -261,Open Professor Snail Cave,progression,GINGER_ISLAND, -262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", -271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", -274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", -275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", -276,Weather Report,useful,TV_CHANNEL, -277,Fortune Teller,useful,TV_CHANNEL, -278,Livin' Off The Land,useful,TV_CHANNEL, -279,The Queen of Sauce,progression,TV_CHANNEL, -280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, -281,Sinister Signal,filler,TV_CHANNEL, -282,Dark Talisman,progression,, -283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, -284,Cute Baby,progression,BABY, -285,Ugly Baby,progression,BABY, -286,Deluxe Scarecrow Recipe,progression,RARECROW, -287,Treehouse,progression,GINGER_ISLAND, -288,Coffee Bean,progression,CROPSANITY, -289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", -290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", -291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", -292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", -293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", -294,Progressive Footwear,useful,FOOTWEAR, -295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", -308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", -325,Fairy Dust Recipe,progression,, -326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, -329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", -331,Jack-O-Lantern Recipe,progression,FESTIVAL, -333,Tub o' Flowers Recipe,progression,FESTIVAL, -335,Moonlight Jellies Banner,filler,FESTIVAL, -336,Starport Decal,filler,FESTIVAL, -337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, -371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", -414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", -417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", -419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -425,Gate Recipe,progression,CRAFTSANITY, -426,Wood Fence Recipe,progression,CRAFTSANITY, -427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -428,Grass Starter Recipe,progression,CRAFTSANITY, -429,Wood Floor Recipe,progression,CRAFTSANITY, -430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, -431,Straw Floor Recipe,progression,CRAFTSANITY, -432,Weathered Floor Recipe,progression,CRAFTSANITY, -433,Crystal Floor Recipe,progression,CRAFTSANITY, -434,Stone Floor Recipe,progression,CRAFTSANITY, -435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, -436,Brick Floor Recipe,progression,CRAFTSANITY, -437,Wood Path Recipe,progression,CRAFTSANITY, -438,Gravel Path Recipe,progression,CRAFTSANITY, -439,Cobblestone Path Recipe,progression,CRAFTSANITY, -440,Stepping Stone Path Recipe,progression,CRAFTSANITY, -441,Crystal Path Recipe,progression,CRAFTSANITY, -442,Wedding Ring Recipe,progression,CRAFTSANITY, -443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, -444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", -445,Torch Recipe,progression,CRAFTSANITY, -446,Campfire Recipe,progression,CRAFTSANITY, -447,Wooden Brazier Recipe,progression,CRAFTSANITY, -448,Stone Brazier Recipe,progression,CRAFTSANITY, -449,Gold Brazier Recipe,progression,CRAFTSANITY, -450,Carved Brazier Recipe,progression,CRAFTSANITY, -451,Stump Brazier Recipe,progression,CRAFTSANITY, -452,Barrel Brazier Recipe,progression,CRAFTSANITY, -453,Skull Brazier Recipe,progression,CRAFTSANITY, -454,Marble Brazier Recipe,progression,CRAFTSANITY, -455,Wood Lamp-post Recipe,progression,CRAFTSANITY, -456,Iron Lamp-post Recipe,progression,CRAFTSANITY, -457,Furnace Recipe,progression,CRAFTSANITY, -458,Wicked Statue Recipe,progression,CRAFTSANITY, -459,Chest Recipe,progression,CRAFTSANITY, -460,Wood Sign Recipe,progression,CRAFTSANITY, -461,Stone Sign Recipe,progression,CRAFTSANITY, -469,Railroad Boulder Removed,progression,, -470,Fruit Bats,progression,, -471,Mushroom Boxes,progression,, -4001,Burnt Trap,trap,TRAP, -4002,Darkness Trap,trap,TRAP, -4003,Frozen Trap,trap,TRAP, -4004,Jinxed Trap,trap,TRAP, -4005,Nauseated Trap,trap,TRAP, -4006,Slimed Trap,trap,TRAP, -4007,Weakness Trap,trap,TRAP, -4008,Taxes Trap,trap,TRAP, -4009,Random Teleport Trap,trap,TRAP, -4010,The Crows Trap,trap,TRAP, -4011,Monsters Trap,trap,TRAP, -4012,Entrance Reshuffle Trap,trap,"TRAP,DEPRECATED", -4013,Debris Trap,trap,TRAP, -4014,Shuffle Trap,trap,TRAP, -4015,Temporary Winter Trap,trap,"TRAP,DEPRECATED", -4016,Pariah Trap,trap,TRAP, -4017,Drought Trap,trap,TRAP, -4018,Time Flies Trap,trap,TRAP, -4019,Babies Trap,trap,TRAP, -4020,Meow Trap,trap,TRAP, -4021,Bark Trap,trap,TRAP, -4022,Depression Trap,trap,"TRAP,DEPRECATED", -4023,Benjamin Budton Trap,trap,TRAP, -4024,Inflation Trap,trap,TRAP, -4025,Bomb Trap,trap,TRAP, -5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", -5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", -5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", -5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", -5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", -5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", -5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", -5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", -5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", -5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", -5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", -5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", -5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", -5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", -5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", -5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", -5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", -5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", -5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", -5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", -5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", -5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", -5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", -5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", -5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", -5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", -5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", -5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", -5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", -5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", -5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", -5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", -5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", -5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", -5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", -5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", -5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", -5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", -5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", -5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", -5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", -5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", -5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", -5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", -5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", -5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5207,Fiber Seeds,filler,RESOURCE_PACK, -5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5210,Quality Bobber,filler,RESOURCE_PACK, -5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", -5212,Monster Musk,filler,RESOURCE_PACK, -5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5216,Scarecrow,filler,RESOURCE_PACK, -5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", -5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", -5236,Aquatic Sanctuary,filler,RESOURCE_PACK, -5242,Exotic Double Bed,filler,RESOURCE_PACK, -5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", -5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", -5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5262,Slime Incubator,useful,RESOURCE_PACK, -5263,Slime Egg-Press,useful,RESOURCE_PACK, -5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5266,Resource Pack: 5 Staircase,filler,"RESOURCE_PACK", -5267,Auto-Petter,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5268,Auto-Grabber,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", -10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill -10002,Magic Level,progression,SKILL_LEVEL_UP,Magic -10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill -10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology -10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill -10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill -10007,Tractor Garage,useful,,Tractor Mod -10008,Woods Obelisk,progression,,DeepWoods -10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic -10010,Spell: Till,useful,MAGIC_SPELL,Magic -10011,Spell: Water,progression,MAGIC_SPELL,Magic -10012,Spell: Blink,progression,MAGIC_SPELL,Magic -10013,Spell: Evac,useful,MAGIC_SPELL,Magic -10014,Spell: Haste,useful,MAGIC_SPELL,Magic -10015,Spell: Heal,progression,MAGIC_SPELL,Magic -10016,Spell: Buff,useful,MAGIC_SPELL,Magic -10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic -10018,Spell: Fireball,progression,MAGIC_SPELL,Magic -10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic -10020,Spell: Teleport,progression,MAGIC_SPELL,Magic -10021,Spell: Lantern,useful,MAGIC_SPELL,Magic -10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic -10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic -10024,Spell: Descend,progression,MAGIC_SPELL,Magic -10025,Spell: Meteor,progression,MAGIC_SPELL,Magic -10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic -10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic -10028,Spell: Spirit,progression,MAGIC_SPELL,Magic -10029,Spell: Rewind,useful,MAGIC_SPELL,Magic -10030,Pendant of Community,progression,,DeepWoods -10031,Pendant of Elders,progression,,DeepWoods -10032,Pendant of Depths,progression,,DeepWoods -10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC -10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas -10103,Alec <3,progression,FRIENDSANITY,Alec Revisited -10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba -10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene -10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick -10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) -10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC -10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC -10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley -10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded -10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded -10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded -10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded -10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded -10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded -10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded -10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded -10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded -10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded -10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded -10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch -10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -10128,Lacey <3,progression,FRIENDSANITY,Hat Mouse Lacey -10129,Gregory <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension -10130,Sheila <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension -10131,Joel <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension -10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods -10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator -10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10412,Crayfish Soup Recipe,progression,,Distant Lands - Witch Swamp Overhaul -10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -10415,Ginger Tincture Recipe,progression,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -10416,Special Pumpkin Soup Recipe,progression,,Boarding House and Bus Stop Extension -10450,Void Mint Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul -10451,Vile Ancient Fruit Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul -10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded -10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10503,Iridium Bomb,progression,,Stardew Valley Expanded -10504,Krobus' Protection,useful,,Stardew Valley Expanded -10505,Kittyfish Spell,progression,,Stardew Valley Expanded -10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded -10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded -10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded -10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded -10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded -10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded -10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded -10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded -10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded -10517,Grandpa's Shed,progression,,Stardew Valley Expanded -10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded -10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded -10520,Morgan's Schooling,progression,,Stardew Valley Expanded -10601,Magic Elixir Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic -10602,Travel Core Recipe,progression,CRAFTSANITY,Magic -10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded -10606,Neanderthal Skeleton Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10607,Pterodactyl Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10608,Pterodactyl Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10609,Pterodactyl Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10610,T-Rex Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10611,T-Rex Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10612,T-Rex Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension -10701,Resource Pack: 3 Magic Elixir,filler,RESOURCE_PACK,Magic -10702,Resource Pack: 3 Travel Core,filler,RESOURCE_PACK,Magic -10703,Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10704,Hardwood Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10705,Resource Pack: 3 Water Shifter,filler,RESOURCE_PACK,Archaeology -10706,Resource Pack: 5 Hardwood Display,filler,RESOURCE_PACK,Archaeology -10707,Resource Pack: 5 Wooden Display,filler,RESOURCE_PACK,Archaeology -10708,Grinder,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10709,Ancient Battery Production Station,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology -10710,Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded -10711,Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10712,Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10713,Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10714,Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10715,Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded -10716,Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +id,name,classification,groups,mod_name +0,Joja Cola,filler,TRASH, +15,Rusty Key,progression,, +16,Dwarvish Translation Guide,progression,, +17,Bridge Repair,progression,COMMUNITY_REWARD, +18,Greenhouse,progression,COMMUNITY_REWARD, +19,Glittering Boulder Removed,progression,COMMUNITY_REWARD, +20,Minecarts Repair,useful,COMMUNITY_REWARD, +21,Bus Repair,progression,COMMUNITY_REWARD, +22,Progressive Movie Theater,progression,COMMUNITY_REWARD, +23,Stardrop,progression,, +24,Progressive Backpack,progression,, +25,Rusty Sword,filler,"WEAPON,DEPRECATED", +26,Leather Boots,filler,"FOOTWEAR,DEPRECATED", +27,Work Boots,filler,"FOOTWEAR,DEPRECATED", +28,Wooden Blade,filler,"WEAPON,DEPRECATED", +29,Iron Dirk,filler,"WEAPON,DEPRECATED", +30,Wind Spire,filler,"WEAPON,DEPRECATED", +31,Femur,filler,"WEAPON,DEPRECATED", +32,Steel Smallsword,filler,"WEAPON,DEPRECATED", +33,Wood Club,filler,"WEAPON,DEPRECATED", +34,Elf Blade,filler,"WEAPON,DEPRECATED", +37,Slingshot,filler,"WEAPON,DEPRECATED", +38,Tundra Boots,filler,"FOOTWEAR,DEPRECATED", +39,Thermal Boots,filler,"FOOTWEAR,DEPRECATED", +40,Combat Boots,filler,"FOOTWEAR,DEPRECATED", +41,Silver Saber,filler,"WEAPON,DEPRECATED", +42,Pirate's Sword,filler,"WEAPON,DEPRECATED", +43,Crystal Dagger,filler,"WEAPON,DEPRECATED", +44,Cutlass,filler,"WEAPON,DEPRECATED", +45,Iron Edge,filler,"WEAPON,DEPRECATED", +46,Burglar's Shank,filler,"WEAPON,DEPRECATED", +47,Wood Mallet,filler,"WEAPON,DEPRECATED", +48,Master Slingshot,filler,"WEAPON,DEPRECATED", +49,Firewalker Boots,filler,"FOOTWEAR,DEPRECATED", +50,Dark Boots,filler,"FOOTWEAR,DEPRECATED", +51,Claymore,filler,"WEAPON,DEPRECATED", +52,Templar's Blade,filler,"WEAPON,DEPRECATED", +53,Kudgel,filler,"WEAPON,DEPRECATED", +54,Shadow Dagger,filler,"WEAPON,DEPRECATED", +55,Obsidian Edge,filler,"WEAPON,DEPRECATED", +56,Tempered Broadsword,filler,"WEAPON,DEPRECATED", +57,Wicked Kris,filler,"WEAPON,DEPRECATED", +58,Bone Sword,filler,"WEAPON,DEPRECATED", +59,Ossified Blade,filler,"WEAPON,DEPRECATED", +60,Space Boots,filler,"FOOTWEAR,DEPRECATED", +61,Crystal Shoes,filler,"FOOTWEAR,DEPRECATED", +62,Steel Falchion,filler,"WEAPON,DEPRECATED", +63,The Slammer,filler,"WEAPON,DEPRECATED", +64,Skull Key,progression,, +65,Progressive Hoe,progression,PROGRESSIVE_TOOLS, +66,Progressive Pickaxe,progression,PROGRESSIVE_TOOLS, +67,Progressive Axe,progression,PROGRESSIVE_TOOLS, +68,Progressive Watering Can,progression,PROGRESSIVE_TOOLS, +69,Progressive Trash Can,progression,PROGRESSIVE_TOOLS, +70,Progressive Fishing Rod,progression,PROGRESSIVE_TOOLS, +71,Golden Scythe,useful,, +72,Progressive Mine Elevator,progression,, +73,Farming Level,progression,SKILL_LEVEL_UP, +74,Fishing Level,progression,SKILL_LEVEL_UP, +75,Foraging Level,progression,SKILL_LEVEL_UP, +76,Mining Level,progression,SKILL_LEVEL_UP, +77,Combat Level,progression,SKILL_LEVEL_UP, +78,Earth Obelisk,progression,WIZARD_BUILDING, +79,Water Obelisk,progression,WIZARD_BUILDING, +80,Desert Obelisk,progression,WIZARD_BUILDING, +81,Island Obelisk,progression,"WIZARD_BUILDING,GINGER_ISLAND", +82,Junimo Hut,useful,WIZARD_BUILDING, +83,Gold Clock,progression,WIZARD_BUILDING, +84,Progressive Coop,progression,BUILDING, +85,Progressive Barn,progression,BUILDING, +86,Well,useful,BUILDING, +87,Silo,progression,BUILDING, +88,Mill,progression,BUILDING, +89,Progressive Shed,progression,BUILDING, +90,Fish Pond,progression,BUILDING, +91,Stable,useful,BUILDING, +92,Slime Hutch,progression,BUILDING, +93,Shipping Bin,progression,BUILDING, +94,Beach Bridge,progression,, +95,Adventurer's Guild,progression,DEPRECATED, +96,Club Card,progression,, +97,Magnifying Glass,progression,, +98,Bear's Knowledge,progression,, +99,Iridium Snake Milk,useful,, +100,JotPK: Progressive Boots,progression,ARCADE_MACHINE_BUFFS, +101,JotPK: Progressive Gun,progression,ARCADE_MACHINE_BUFFS, +102,JotPK: Progressive Ammo,progression,ARCADE_MACHINE_BUFFS, +103,JotPK: Extra Life,progression,ARCADE_MACHINE_BUFFS, +104,JotPK: Increased Drop Rate,progression,ARCADE_MACHINE_BUFFS, +105,Junimo Kart: Extra Life,progression,ARCADE_MACHINE_BUFFS, +106,Galaxy Sword,filler,"WEAPON,DEPRECATED", +107,Galaxy Dagger,filler,"WEAPON,DEPRECATED", +108,Galaxy Hammer,filler,"WEAPON,DEPRECATED", +109,Movement Speed Bonus,progression,, +110,Luck Bonus,progression,, +111,Lava Katana,filler,"WEAPON,DEPRECATED", +112,Progressive House,progression,, +113,Traveling Merchant: Sunday,progression,TRAVELING_MERCHANT_DAY, +114,Traveling Merchant: Monday,progression,TRAVELING_MERCHANT_DAY, +115,Traveling Merchant: Tuesday,progression,TRAVELING_MERCHANT_DAY, +116,Traveling Merchant: Wednesday,progression,TRAVELING_MERCHANT_DAY, +117,Traveling Merchant: Thursday,progression,TRAVELING_MERCHANT_DAY, +118,Traveling Merchant: Friday,progression,TRAVELING_MERCHANT_DAY, +119,Traveling Merchant: Saturday,progression,TRAVELING_MERCHANT_DAY, +120,Traveling Merchant Stock Size,useful,, +121,Traveling Merchant Discount,useful,, +122,Return Scepter,useful,, +123,Progressive Season,progression,, +124,Spring,progression,SEASON, +125,Summer,progression,SEASON, +126,Fall,progression,SEASON, +127,Winter,progression,SEASON, +128,Amaranth Seeds,progression,CROPSANITY, +129,Artichoke Seeds,progression,CROPSANITY, +130,Beet Seeds,progression,CROPSANITY, +131,Jazz Seeds,progression,CROPSANITY, +132,Blueberry Seeds,progression,CROPSANITY, +133,Bok Choy Seeds,progression,CROPSANITY, +134,Cauliflower Seeds,progression,CROPSANITY, +135,Corn Seeds,progression,CROPSANITY, +136,Cranberry Seeds,progression,CROPSANITY, +137,Eggplant Seeds,progression,CROPSANITY, +138,Fairy Seeds,progression,CROPSANITY, +139,Garlic Seeds,progression,CROPSANITY, +140,Grape Starter,progression,CROPSANITY, +141,Bean Starter,progression,CROPSANITY, +142,Hops Starter,progression,CROPSANITY, +143,Pepper Seeds,progression,CROPSANITY, +144,Kale Seeds,progression,CROPSANITY, +145,Melon Seeds,progression,CROPSANITY, +146,Parsnip Seeds,progression,CROPSANITY, +147,Poppy Seeds,progression,CROPSANITY, +148,Potato Seeds,progression,CROPSANITY, +149,Pumpkin Seeds,progression,CROPSANITY, +150,Radish Seeds,progression,CROPSANITY, +151,Red Cabbage Seeds,progression,CROPSANITY, +152,Rhubarb Seeds,progression,CROPSANITY, +153,Starfruit Seeds,progression,CROPSANITY, +154,Strawberry Seeds,progression,CROPSANITY, +155,Spangle Seeds,progression,CROPSANITY, +156,Sunflower Seeds,progression,CROPSANITY, +157,Tomato Seeds,progression,CROPSANITY, +158,Tulip Bulb,progression,CROPSANITY, +159,Rice Shoot,progression,CROPSANITY, +160,Wheat Seeds,progression,CROPSANITY, +161,Yam Seeds,progression,CROPSANITY, +162,Cactus Seeds,progression,CROPSANITY, +163,Magic Rock Candy,useful,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +164,Ancient Seeds Recipe,progression,MUSEUM, +165,Ancient Seeds,progression,"MUSEUM,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +166,Traveling Merchant Metal Detector,progression,MUSEUM, +167,Alex <3,progression,FRIENDSANITY, +168,Elliott <3,progression,FRIENDSANITY, +169,Harvey <3,progression,FRIENDSANITY, +170,Sam <3,progression,FRIENDSANITY, +171,Sebastian <3,progression,FRIENDSANITY, +172,Shane <3,progression,FRIENDSANITY, +173,Abigail <3,progression,FRIENDSANITY, +174,Emily <3,progression,FRIENDSANITY, +175,Haley <3,progression,FRIENDSANITY, +176,Leah <3,progression,FRIENDSANITY, +177,Maru <3,progression,FRIENDSANITY, +178,Penny <3,progression,FRIENDSANITY, +179,Caroline <3,progression,FRIENDSANITY, +180,Clint <3,progression,FRIENDSANITY, +181,Demetrius <3,progression,FRIENDSANITY, +182,Dwarf <3,progression,FRIENDSANITY, +183,Evelyn <3,progression,FRIENDSANITY, +184,George <3,progression,FRIENDSANITY, +185,Gus <3,progression,FRIENDSANITY, +186,Jas <3,progression,FRIENDSANITY, +187,Jodi <3,progression,FRIENDSANITY, +188,Kent <3,progression,FRIENDSANITY, +189,Krobus <3,progression,FRIENDSANITY, +190,Leo <3,progression,"FRIENDSANITY,GINGER_ISLAND", +191,Lewis <3,progression,FRIENDSANITY, +192,Linus <3,progression,FRIENDSANITY, +193,Marnie <3,progression,FRIENDSANITY, +194,Pam <3,progression,FRIENDSANITY, +195,Pierre <3,progression,FRIENDSANITY, +196,Robin <3,progression,FRIENDSANITY, +197,Sandy <3,progression,FRIENDSANITY, +198,Vincent <3,progression,FRIENDSANITY, +199,Willy <3,progression,FRIENDSANITY, +200,Wizard <3,progression,FRIENDSANITY, +201,Pet <3,progression,FRIENDSANITY, +202,Rarecrow #1,progression,"FESTIVAL,RARECROW", +203,Rarecrow #2,progression,"FESTIVAL,RARECROW", +204,Rarecrow #3,progression,"FESTIVAL,RARECROW", +205,Rarecrow #4,progression,"FESTIVAL,RARECROW", +206,Rarecrow #5,progression,"FESTIVAL,RARECROW", +207,Rarecrow #6,progression,"FESTIVAL,RARECROW", +208,Rarecrow #7,progression,"FESTIVAL,RARECROW", +209,Rarecrow #8,progression,"FESTIVAL,RARECROW", +210,Straw Hat,filler,FESTIVAL, +211,Golden Pumpkin,useful,FESTIVAL, +212,Barbed Hook,useful,FESTIVAL, +213,Dressed Spinner,useful,FESTIVAL, +214,Magnet,useful,FESTIVAL, +215,Sailor's Cap,filler,FESTIVAL, +216,Pearl,useful,FESTIVAL, +217,Cone Hat,filler,FESTIVAL, +218,Iridium Fireplace,filler,FESTIVAL, +219,Lupini: Red Eagle,filler,FESTIVAL, +220,Lupini: Portrait Of A Mermaid,filler,FESTIVAL, +221,Lupini: Solar Kingdom,filler,FESTIVAL, +222,Lupini: Clouds,filler,FESTIVAL, +223,Lupini: 1000 Years From Now,filler,FESTIVAL, +224,Lupini: Three Trees,filler,FESTIVAL, +225,Lupini: The Serpent,filler,FESTIVAL, +226,Lupini: 'Tropical Fish #173',filler,FESTIVAL, +227,Lupini: Land Of Clay,filler,FESTIVAL, +228,Special Order Board,progression,SPECIAL_ORDER_BOARD, +229,Solar Panel Recipe,progression,SPECIAL_ORDER_BOARD, +230,Geode Crusher Recipe,progression,SPECIAL_ORDER_BOARD, +231,Farm Computer Recipe,progression,SPECIAL_ORDER_BOARD, +232,Bone Mill Recipe,progression,SPECIAL_ORDER_BOARD, +233,Fiber Seeds Recipe,progression,SPECIAL_ORDER_BOARD, +234,Stone Chest Recipe,progression,SPECIAL_ORDER_BOARD, +235,Quality Bobber Recipe,progression,SPECIAL_ORDER_BOARD, +236,Mini-Obelisk Recipe,progression,SPECIAL_ORDER_BOARD, +237,Monster Musk Recipe,progression,SPECIAL_ORDER_BOARD, +239,Sewing Machine,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +240,Coffee Maker,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +241,Mini-Fridge,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +242,Mini-Shipping Bin,progression,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +243,Deluxe Fish Tank,useful,"RESOURCE_PACK_USEFUL,SPECIAL_ORDER_BOARD", +244,10 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +245,20 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +246,25 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +247,35 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +248,40 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +249,50 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +250,100 Qi Gems,progression,"GINGER_ISLAND,SPECIAL_ORDER_QI", +251,Rare Seed,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +252,Apple Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +253,Apricot Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +254,Cherry Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +255,Orange Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +256,Pomegranate Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +257,Peach Sapling,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +258,Banana Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +259,Mango Sapling,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL,CROPSANITY", +260,Boat Repair,progression,GINGER_ISLAND, +261,Open Professor Snail Cave,progression,GINGER_ISLAND, +262,Island North Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +263,Island West Turtle,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +264,Island Farmhouse,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +265,Island Mailbox,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +266,Farm Obelisk,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +267,Dig Site Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +268,Island Trader,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +269,Volcano Bridge,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +270,Volcano Exit Shortcut,useful,"GINGER_ISLAND,WALNUT_PURCHASE", +271,Island Resort,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +272,Parrot Express,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +273,Qi Walnut Room,progression,"GINGER_ISLAND,WALNUT_PURCHASE", +274,Pineapple Seeds,progression,"GINGER_ISLAND,CROPSANITY", +275,Taro Tuber,progression,"GINGER_ISLAND,CROPSANITY", +276,Weather Report,useful,TV_CHANNEL, +277,Fortune Teller,useful,TV_CHANNEL, +278,Livin' Off The Land,useful,TV_CHANNEL, +279,The Queen of Sauce,progression,TV_CHANNEL, +280,Fishing Information Broadcasting Service,useful,TV_CHANNEL, +281,Sinister Signal,filler,TV_CHANNEL, +282,Dark Talisman,progression,, +283,Ostrich Incubator Recipe,progression,GINGER_ISLAND, +284,Cute Baby,progression,BABY, +285,Ugly Baby,progression,BABY, +286,Deluxe Scarecrow Recipe,progression,RARECROW, +287,Treehouse,progression,GINGER_ISLAND, +288,Coffee Bean,progression,CROPSANITY, +289,Progressive Weapon,progression,"WEAPON,WEAPON_GENERIC", +290,Progressive Sword,progression,"WEAPON,WEAPON_SWORD", +291,Progressive Club,progression,"WEAPON,WEAPON_CLUB", +292,Progressive Dagger,progression,"WEAPON,WEAPON_DAGGER", +293,Progressive Slingshot,progression,"WEAPON,WEAPON_SLINGSHOT", +294,Progressive Footwear,useful,FOOTWEAR, +295,Small Glow Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +296,Glow Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +297,Small Magnet Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +298,Magnet Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +299,Slime Charmer Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +300,Warrior Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +301,Vampire Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +302,Savage Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +303,Ring of Yoba,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +304,Sturdy Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +305,Burglar's Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +306,Iridium Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +307,Jukebox Ring,filler,"RING,RESOURCE_PACK,MAXIMUM_ONE", +308,Amethyst Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +309,Topaz Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +310,Aquamarine Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +311,Jade Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +312,Emerald Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +313,Ruby Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +314,Wedding Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +315,Crabshell Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +316,Napalm Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +317,Thorns Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +318,Lucky Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +319,Hot Java Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +320,Protection Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +321,Soul Sapper Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +322,Phoenix Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +323,Immunity Band,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +324,Glowstone Ring,useful,"RING,RESOURCE_PACK,MAXIMUM_ONE", +325,Fairy Dust Recipe,progression,, +326,Heavy Tapper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +327,Hyper Speed-Gro Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +328,Deluxe Fertilizer Recipe,progression,QI_CRAFTING_RECIPE, +329,Hopper Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +330,Magic Bait Recipe,progression,"QI_CRAFTING_RECIPE,GINGER_ISLAND", +331,Jack-O-Lantern Recipe,progression,FESTIVAL, +333,Tub o' Flowers Recipe,progression,FESTIVAL, +335,Moonlight Jellies Banner,filler,FESTIVAL, +336,Starport Decal,filler,FESTIVAL, +337,Golden Egg,progression,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +340,Algae Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +341,Artichoke Dip Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +342,Autumn's Bounty Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +343,Baked Fish Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +344,Banana Pudding Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +345,Bean Hotpot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +346,Blackberry Cobbler Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +347,Blueberry Tart Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +348,Bread Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +349,Bruschetta Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +350,Carp Surprise Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +351,Cheese Cauliflower Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +352,Chocolate Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +353,Chowder Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +354,Coleslaw Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +355,Complete Breakfast Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +356,Cookies Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +357,Crab Cakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +358,Cranberry Candy Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +359,Cranberry Sauce Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +360,Crispy Bass Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +361,Dish O' The Sea Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +362,Eggplant Parmesan Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +363,Escargot Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +364,Farmer's Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +365,Fiddlehead Risotto Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +366,Fish Stew Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +367,Fish Taco Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +368,Fried Calamari Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +369,Fried Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +370,Fried Egg Recipe,progression,CHEFSANITY_STARTER, +371,Fried Mushroom Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +372,Fruit Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +373,Ginger Ale Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +374,Glazed Yams Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +375,Hashbrowns Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +376,Ice Cream Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +377,Lobster Bisque Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +378,Lucky Lunch Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +379,Maki Roll Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +380,Mango Sticky Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +381,Maple Bar Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +382,Miner's Treat Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +383,Omelet Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +384,Pale Broth Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +385,Pancakes Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +386,Parsnip Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +387,Pepper Poppers Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +388,Pink Cake Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +389,Pizza Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +390,Plum Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +391,Poi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +392,Poppyseed Muffin Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +393,Pumpkin Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +394,Pumpkin Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +395,Radish Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +396,Red Plate Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +397,Rhubarb Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +398,Rice Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +399,Roasted Hazelnuts Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +400,Roots Platter Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +401,Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +402,Salmon Dinner Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +403,Sashimi Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +404,Seafoam Pudding Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +405,Shrimp Cocktail Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +406,Spaghetti Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +407,Spicy Eel Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +408,Squid Ink Ravioli Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +409,Stir Fry Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +410,Strange Bun Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +411,Stuffing Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +412,Super Meal Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +413,Survival Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_SKILL", +414,Tom Kha Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +415,Tortilla Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +416,Triple Shot Espresso Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE", +417,Tropical Curry Recipe,progression,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +418,Trout Soup Recipe,progression,"CHEFSANITY,CHEFSANITY_QOS", +419,Vegetable Medley Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +425,Gate Recipe,progression,CRAFTSANITY, +426,Wood Fence Recipe,progression,CRAFTSANITY, +427,Deluxe Retaining Soil Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +428,Grass Starter Recipe,progression,CRAFTSANITY, +429,Wood Floor Recipe,progression,CRAFTSANITY, +430,Rustic Plank Floor Recipe,progression,CRAFTSANITY, +431,Straw Floor Recipe,progression,CRAFTSANITY, +432,Weathered Floor Recipe,progression,CRAFTSANITY, +433,Crystal Floor Recipe,progression,CRAFTSANITY, +434,Stone Floor Recipe,progression,CRAFTSANITY, +435,Stone Walkway Floor Recipe,progression,CRAFTSANITY, +436,Brick Floor Recipe,progression,CRAFTSANITY, +437,Wood Path Recipe,progression,CRAFTSANITY, +438,Gravel Path Recipe,progression,CRAFTSANITY, +439,Cobblestone Path Recipe,progression,CRAFTSANITY, +440,Stepping Stone Path Recipe,progression,CRAFTSANITY, +441,Crystal Path Recipe,progression,CRAFTSANITY, +442,Wedding Ring Recipe,progression,CRAFTSANITY, +443,Warp Totem: Desert Recipe,progression,CRAFTSANITY, +444,Warp Totem: Island Recipe,progression,"CRAFTSANITY,GINGER_ISLAND", +445,Torch Recipe,progression,CRAFTSANITY, +446,Campfire Recipe,progression,CRAFTSANITY, +447,Wooden Brazier Recipe,progression,CRAFTSANITY, +448,Stone Brazier Recipe,progression,CRAFTSANITY, +449,Gold Brazier Recipe,progression,CRAFTSANITY, +450,Carved Brazier Recipe,progression,CRAFTSANITY, +451,Stump Brazier Recipe,progression,CRAFTSANITY, +452,Barrel Brazier Recipe,progression,CRAFTSANITY, +453,Skull Brazier Recipe,progression,CRAFTSANITY, +454,Marble Brazier Recipe,progression,CRAFTSANITY, +455,Wood Lamp-post Recipe,progression,CRAFTSANITY, +456,Iron Lamp-post Recipe,progression,CRAFTSANITY, +457,Furnace Recipe,progression,CRAFTSANITY, +458,Wicked Statue Recipe,progression,CRAFTSANITY, +459,Chest Recipe,progression,CRAFTSANITY, +460,Wood Sign Recipe,progression,CRAFTSANITY, +461,Stone Sign Recipe,progression,CRAFTSANITY, +469,Railroad Boulder Removed,progression,, +470,Fruit Bats,progression,, +471,Mushroom Boxes,progression,, +4001,Burnt Trap,trap,TRAP, +4002,Darkness Trap,trap,TRAP, +4003,Frozen Trap,trap,TRAP, +4004,Jinxed Trap,trap,TRAP, +4005,Nauseated Trap,trap,TRAP, +4006,Slimed Trap,trap,TRAP, +4007,Weakness Trap,trap,TRAP, +4008,Taxes Trap,trap,TRAP, +4009,Random Teleport Trap,trap,TRAP, +4010,The Crows Trap,trap,TRAP, +4011,Monsters Trap,trap,TRAP, +4012,Entrance Reshuffle Trap,trap,"TRAP,DEPRECATED", +4013,Debris Trap,trap,TRAP, +4014,Shuffle Trap,trap,TRAP, +4015,Temporary Winter Trap,trap,"TRAP,DEPRECATED", +4016,Pariah Trap,trap,TRAP, +4017,Drought Trap,trap,TRAP, +4018,Time Flies Trap,trap,TRAP, +4019,Babies Trap,trap,TRAP, +4020,Meow Trap,trap,TRAP, +4021,Bark Trap,trap,TRAP, +4022,Depression Trap,trap,"TRAP,DEPRECATED", +4023,Benjamin Budton Trap,trap,TRAP, +4024,Inflation Trap,trap,TRAP, +4025,Bomb Trap,trap,TRAP, +5000,Resource Pack: 500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5001,Resource Pack: 1000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5002,Resource Pack: 1500 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5003,Resource Pack: 2000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK", +5004,Resource Pack: 25 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5005,Resource Pack: 50 Stone,filler,"BASE_RESOURCE,RESOURCE_PACK", +5006,Resource Pack: 75 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5007,Resource Pack: 100 Stone,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5008,Resource Pack: 25 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5009,Resource Pack: 50 Wood,filler,"BASE_RESOURCE,RESOURCE_PACK", +5010,Resource Pack: 75 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5011,Resource Pack: 100 Wood,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5012,Resource Pack: 5 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5013,Resource Pack: 10 Hardwood,useful,"BASE_RESOURCE,RESOURCE_PACK", +5014,Resource Pack: 15 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5015,Resource Pack: 20 Hardwood,useful,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5016,Resource Pack: 15 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5017,Resource Pack: 30 Fiber,filler,"BASE_RESOURCE,RESOURCE_PACK", +5018,Resource Pack: 45 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5019,Resource Pack: 60 Fiber,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5020,Resource Pack: 5 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5021,Resource Pack: 10 Coal,filler,"BASE_RESOURCE,RESOURCE_PACK", +5022,Resource Pack: 15 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5023,Resource Pack: 20 Coal,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5024,Resource Pack: 5 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5025,Resource Pack: 10 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5026,Resource Pack: 15 Clay,filler,"DEPRECATED,BASE_RESOURCE,RESOURCE_PACK", +5027,Resource Pack: 20 Clay,filler,"BASE_RESOURCE,RESOURCE_PACK", +5028,Resource Pack: 1 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5029,Resource Pack: 3 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5030,Resource Pack: 5 Warp Totem: Beach,filler,"RESOURCE_PACK,WARP_TOTEM", +5031,Resource Pack: 7 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5032,Resource Pack: 9 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5033,Resource Pack: 10 Warp Totem: Beach,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5034,Resource Pack: 1 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5035,Resource Pack: 3 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5036,Resource Pack: 5 Warp Totem: Desert,filler,"RESOURCE_PACK,WARP_TOTEM", +5037,Resource Pack: 7 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5038,Resource Pack: 9 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5039,Resource Pack: 10 Warp Totem: Desert,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5040,Resource Pack: 1 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5041,Resource Pack: 3 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5042,Resource Pack: 5 Warp Totem: Farm,filler,"RESOURCE_PACK,WARP_TOTEM", +5043,Resource Pack: 7 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5044,Resource Pack: 9 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5045,Resource Pack: 10 Warp Totem: Farm,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5046,Resource Pack: 1 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5047,Resource Pack: 3 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5048,Resource Pack: 5 Warp Totem: Island,filler,"RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5049,Resource Pack: 7 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5050,Resource Pack: 9 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5051,Resource Pack: 10 Warp Totem: Island,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM,GINGER_ISLAND", +5052,Resource Pack: 1 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5053,Resource Pack: 3 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5054,Resource Pack: 5 Warp Totem: Mountains,filler,"RESOURCE_PACK,WARP_TOTEM", +5055,Resource Pack: 7 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5056,Resource Pack: 9 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5057,Resource Pack: 10 Warp Totem: Mountains,filler,"DEPRECATED,RESOURCE_PACK,WARP_TOTEM", +5058,Resource Pack: 6 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5059,Resource Pack: 12 Geode,filler,"GEODE,RESOURCE_PACK", +5060,Resource Pack: 18 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5061,Resource Pack: 24 Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5062,Resource Pack: 4 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5063,Resource Pack: 8 Frozen Geode,filler,"GEODE,RESOURCE_PACK", +5064,Resource Pack: 12 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5065,Resource Pack: 16 Frozen Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5066,Resource Pack: 3 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5067,Resource Pack: 6 Magma Geode,filler,"GEODE,RESOURCE_PACK", +5068,Resource Pack: 9 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5069,Resource Pack: 12 Magma Geode,filler,"DEPRECATED,GEODE,RESOURCE_PACK", +5070,Resource Pack: 2 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5071,Resource Pack: 4 Omni Geode,useful,"GEODE,RESOURCE_PACK", +5072,Resource Pack: 6 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5073,Resource Pack: 8 Omni Geode,useful,"DEPRECATED,GEODE,RESOURCE_PACK", +5074,Resource Pack: 25 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5075,Resource Pack: 50 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5076,Resource Pack: 75 Copper Ore,filler,"ORE,RESOURCE_PACK", +5077,Resource Pack: 100 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5078,Resource Pack: 125 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5079,Resource Pack: 150 Copper Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5080,Resource Pack: 25 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5081,Resource Pack: 50 Iron Ore,filler,"ORE,RESOURCE_PACK", +5082,Resource Pack: 75 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5083,Resource Pack: 100 Iron Ore,filler,"DEPRECATED,ORE,RESOURCE_PACK", +5084,Resource Pack: 12 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5085,Resource Pack: 25 Gold Ore,useful,"ORE,RESOURCE_PACK", +5086,Resource Pack: 38 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5087,Resource Pack: 50 Gold Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5088,Resource Pack: 5 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5089,Resource Pack: 10 Iridium Ore,useful,"ORE,RESOURCE_PACK", +5090,Resource Pack: 15 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5091,Resource Pack: 20 Iridium Ore,useful,"DEPRECATED,ORE,RESOURCE_PACK", +5092,Resource Pack: 5 Quartz,filler,"ORE,RESOURCE_PACK", +5093,Resource Pack: 10 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5094,Resource Pack: 15 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5095,Resource Pack: 20 Quartz,filler,"ORE,DEPRECATED,RESOURCE_PACK", +5096,Resource Pack: 10 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5097,Resource Pack: 20 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5098,Resource Pack: 30 Basic Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5099,Resource Pack: 40 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5100,Resource Pack: 50 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5101,Resource Pack: 60 Basic Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5102,Resource Pack: 10 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5103,Resource Pack: 20 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5104,Resource Pack: 30 Basic Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5105,Resource Pack: 40 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5106,Resource Pack: 50 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5107,Resource Pack: 60 Basic Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5108,Resource Pack: 10 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5109,Resource Pack: 20 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5110,Resource Pack: 30 Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5111,Resource Pack: 40 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5112,Resource Pack: 50 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5113,Resource Pack: 60 Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5114,Resource Pack: 4 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5115,Resource Pack: 12 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5116,Resource Pack: 20 Quality Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5117,Resource Pack: 28 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5118,Resource Pack: 36 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5119,Resource Pack: 40 Quality Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5120,Resource Pack: 4 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5121,Resource Pack: 12 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5122,Resource Pack: 20 Quality Retaining Soil,filler,"FERTILIZER,RESOURCE_PACK", +5123,Resource Pack: 28 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5124,Resource Pack: 36 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5125,Resource Pack: 40 Quality Retaining Soil,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5126,Resource Pack: 4 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5127,Resource Pack: 12 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5128,Resource Pack: 20 Deluxe Speed-Gro,filler,"FERTILIZER,RESOURCE_PACK", +5129,Resource Pack: 28 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5130,Resource Pack: 36 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5131,Resource Pack: 40 Deluxe Speed-Gro,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5132,Resource Pack: 2 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5133,Resource Pack: 6 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5134,Resource Pack: 10 Deluxe Fertilizer,useful,"FERTILIZER,RESOURCE_PACK", +5135,Resource Pack: 14 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5136,Resource Pack: 18 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5137,Resource Pack: 20 Deluxe Fertilizer,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5138,Resource Pack: 2 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5139,Resource Pack: 6 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5140,Resource Pack: 10 Deluxe Retaining Soil,useful,"FERTILIZER,RESOURCE_PACK", +5141,Resource Pack: 14 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5142,Resource Pack: 18 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5143,Resource Pack: 20 Deluxe Retaining Soil,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5144,Resource Pack: 2 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5145,Resource Pack: 6 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5146,Resource Pack: 10 Hyper Speed-Gro,useful,"FERTILIZER,RESOURCE_PACK", +5147,Resource Pack: 14 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5148,Resource Pack: 18 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5149,Resource Pack: 20 Hyper Speed-Gro,useful,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5150,Resource Pack: 2 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5151,Resource Pack: 6 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5152,Resource Pack: 10 Tree Fertilizer,filler,"FERTILIZER,RESOURCE_PACK", +5153,Resource Pack: 14 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5154,Resource Pack: 18 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5155,Resource Pack: 20 Tree Fertilizer,filler,"DEPRECATED,FERTILIZER,RESOURCE_PACK", +5156,Resource Pack: 10 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5157,Resource Pack: 20 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5158,Resource Pack: 30 Spring Seeds,filler,"RESOURCE_PACK,SEED", +5159,Resource Pack: 40 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5160,Resource Pack: 50 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5161,Resource Pack: 60 Spring Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5162,Resource Pack: 10 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5163,Resource Pack: 20 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5164,Resource Pack: 30 Summer Seeds,filler,"RESOURCE_PACK,SEED", +5165,Resource Pack: 40 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5166,Resource Pack: 50 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5167,Resource Pack: 60 Summer Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5168,Resource Pack: 10 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5169,Resource Pack: 20 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5170,Resource Pack: 30 Fall Seeds,filler,"RESOURCE_PACK,SEED", +5171,Resource Pack: 40 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5172,Resource Pack: 50 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5173,Resource Pack: 60 Fall Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5174,Resource Pack: 10 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5175,Resource Pack: 20 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5176,Resource Pack: 30 Winter Seeds,filler,"RESOURCE_PACK,SEED", +5177,Resource Pack: 40 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5178,Resource Pack: 50 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5179,Resource Pack: 60 Winter Seeds,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5180,Resource Pack: 1 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5181,Resource Pack: 3 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5182,Resource Pack: 5 Mahogany Seed,filler,"RESOURCE_PACK,SEED", +5183,Resource Pack: 7 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5184,Resource Pack: 9 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5185,Resource Pack: 10 Mahogany Seed,filler,"DEPRECATED,RESOURCE_PACK,SEED", +5186,Resource Pack: 10 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5187,Resource Pack: 20 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5188,Resource Pack: 30 Bait,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5189,Resource Pack: 40 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5190,Resource Pack: 50 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5191,Resource Pack: 60 Bait,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5192,Resource Pack: 1 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5193,Resource Pack: 2 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5194,Resource Pack: 3 Crab Pot,filler,"FISHING_RESOURCE,RESOURCE_PACK", +5195,Resource Pack: 4 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5196,Resource Pack: 5 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5197,Resource Pack: 6 Crab Pot,filler,"DEPRECATED,FISHING_RESOURCE,RESOURCE_PACK", +5198,Friendship Bonus (1 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5199,Friendship Bonus (2 <3),useful,"FRIENDSHIP_PACK,COMMUNITY_REWARD", +5200,Friendship Bonus (3 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5201,Friendship Bonus (4 <3),useful,"DEPRECATED,FRIENDSHIP_PACK,RESOURCE_PACK", +5202,15 Qi Gems,progression,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5203,Solar Panel,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5204,Geode Crusher,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5205,Farm Computer,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5206,Bone Mill,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5207,Fiber Seeds,filler,RESOURCE_PACK, +5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5210,Quality Bobber,filler,RESOURCE_PACK, +5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK", +5212,Monster Musk,filler,RESOURCE_PACK, +5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5216,Scarecrow,filler,RESOURCE_PACK, +5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", +5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5234,Resource Pack: 10 Qi Seasoning,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5235,Mr. Qi's Hat,filler,"MAXIMUM_ONE,RESOURCE_PACK", +5236,Aquatic Sanctuary,filler,RESOURCE_PACK, +5242,Exotic Double Bed,filler,RESOURCE_PACK, +5243,Resource Pack: 2 Qi Gem,filler,"GINGER_ISLAND,RESOURCE_PACK,DEPRECATED", +5245,Golden Walnut,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL,GINGER_ISLAND", +5247,Fairy Dust,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5248,Seed Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5249,Keg,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5250,Cask,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5251,Preserves Jar,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5252,Bee House,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5253,Garden Pot,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5254,Cheese Press,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5255,Mayonnaise Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5256,Loom,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5257,Oil Maker,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5258,Recycling Machine,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5259,Worm Bin,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5260,Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5261,Heavy Tapper,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5262,Slime Incubator,useful,RESOURCE_PACK, +5263,Slime Egg-Press,useful,RESOURCE_PACK, +5264,Crystalarium,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5265,Ostrich Incubator,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5266,Resource Pack: 5 Staircase,filler,"RESOURCE_PACK", +5267,Auto-Petter,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5268,Auto-Grabber,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +10001,Luck Level,progression,SKILL_LEVEL_UP,Luck Skill +10002,Magic Level,progression,SKILL_LEVEL_UP,Magic +10003,Socializing Level,progression,SKILL_LEVEL_UP,Socializing Skill +10004,Archaeology Level,progression,SKILL_LEVEL_UP,Archaeology +10005,Cooking Level,progression,SKILL_LEVEL_UP,Cooking Skill +10006,Binning Level,progression,SKILL_LEVEL_UP,Binning Skill +10007,Tractor Garage,useful,,Tractor Mod +10008,Woods Obelisk,progression,,DeepWoods +10009,Spell: Clear Debris,progression,MAGIC_SPELL,Magic +10010,Spell: Till,useful,MAGIC_SPELL,Magic +10011,Spell: Water,progression,MAGIC_SPELL,Magic +10012,Spell: Blink,progression,MAGIC_SPELL,Magic +10013,Spell: Evac,useful,MAGIC_SPELL,Magic +10014,Spell: Haste,useful,MAGIC_SPELL,Magic +10015,Spell: Heal,progression,MAGIC_SPELL,Magic +10016,Spell: Buff,useful,MAGIC_SPELL,Magic +10017,Spell: Shockwave,progression,MAGIC_SPELL,Magic +10018,Spell: Fireball,progression,MAGIC_SPELL,Magic +10019,Spell: Frostbolt,progression,MAGIC_SPELL,Magic +10020,Spell: Teleport,progression,MAGIC_SPELL,Magic +10021,Spell: Lantern,useful,MAGIC_SPELL,Magic +10022,Spell: Tendrils,progression,MAGIC_SPELL,Magic +10023,Spell: Photosynthesis,useful,MAGIC_SPELL,Magic +10024,Spell: Descend,progression,MAGIC_SPELL,Magic +10025,Spell: Meteor,progression,MAGIC_SPELL,Magic +10026,Spell: Bloodmana,useful,MAGIC_SPELL,Magic +10027,Spell: Lucksteal,useful,MAGIC_SPELL,Magic +10028,Spell: Spirit,progression,MAGIC_SPELL,Magic +10029,Spell: Rewind,useful,MAGIC_SPELL,Magic +10030,Pendant of Community,progression,,DeepWoods +10031,Pendant of Elders,progression,,DeepWoods +10032,Pendant of Depths,progression,,DeepWoods +10101,Juna <3,progression,FRIENDSANITY,Juna - Roommate NPC +10102,Jasper <3,progression,FRIENDSANITY,Professor Jasper Thomas +10103,Alec <3,progression,FRIENDSANITY,Alec Revisited +10104,Yoba <3,progression,FRIENDSANITY,Custom NPC - Yoba +10105,Eugene <3,progression,FRIENDSANITY,Custom NPC Eugene +10106,Wellwick <3,progression,FRIENDSANITY,'Prophet' Wellwick +10107,Mr. Ginger <3,progression,FRIENDSANITY,Mister Ginger (cat npc) +10108,Shiko <3,progression,FRIENDSANITY,Shiko - New Custom NPC +10109,Delores <3,progression,FRIENDSANITY,Delores - Custom NPC +10110,Ayeisha <3,progression,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +10111,Riley <3,progression,FRIENDSANITY,Custom NPC - Riley +10112,Claire <3,progression,FRIENDSANITY,Stardew Valley Expanded +10113,Lance <3,progression,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +10114,Olivia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10115,Sophia <3,progression,FRIENDSANITY,Stardew Valley Expanded +10116,Victor <3,progression,FRIENDSANITY,Stardew Valley Expanded +10117,Andy <3,progression,FRIENDSANITY,Stardew Valley Expanded +10118,Apples <3,progression,FRIENDSANITY,Stardew Valley Expanded +10119,Gunther <3,progression,FRIENDSANITY,Stardew Valley Expanded +10120,Martin <3,progression,FRIENDSANITY,Stardew Valley Expanded +10121,Marlon <3,progression,FRIENDSANITY,Stardew Valley Expanded +10122,Morgan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10123,Scarlett <3,progression,FRIENDSANITY,Stardew Valley Expanded +10124,Susan <3,progression,FRIENDSANITY,Stardew Valley Expanded +10125,Morris <3,progression,FRIENDSANITY,Stardew Valley Expanded +10126,Alecto <3,progression,FRIENDSANITY,Alecto the Witch +10127,Zic <3,progression,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +10128,Lacey <3,progression,FRIENDSANITY,Hat Mouse Lacey +10129,Gregory <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10130,Sheila <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10131,Joel <3,progression,FRIENDSANITY,Boarding House and Bus Stop Extension +10301,Progressive Woods Obelisk Sigils,progression,,DeepWoods +10302,Progressive Skull Cavern Elevator,progression,,Skull Cavern Elevator +10401,Baked Berry Oatmeal Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10402,Big Bark Burger Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10403,Flower Cookie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10404,Frog Legs Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10405,Glazed Butterfish Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10406,Mixed Berry Pie Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10407,Mushroom Berry Rice Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10408,Seaweed Salad Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10409,Void Delight Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10410,Void Salmon Sushi Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +10411,Mushroom Kebab Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10412,Crayfish Soup Recipe,progression,,Distant Lands - Witch Swamp Overhaul +10413,Pemmican Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10414,Void Mint Tea Recipe,progression,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +10415,Ginger Tincture Recipe,progression,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +10416,Special Pumpkin Soup Recipe,progression,,Boarding House and Bus Stop Extension +10450,Void Mint Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul +10451,Vile Ancient Fruit Seeds,progression,DEPRECATED,Distant Lands - Witch Swamp Overhaul +10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded +10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10503,Iridium Bomb,progression,,Stardew Valley Expanded +10504,Krobus' Protection,useful,,Stardew Valley Expanded +10505,Kittyfish Spell,progression,,Stardew Valley Expanded +10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded +10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded +10508,Nexus: Aurora Vineyard Runes,progression,MOD_WARP,Stardew Valley Expanded +10509,Nexus: Sprite Spring Runes,progression,MOD_WARP,Stardew Valley Expanded +10510,Nexus: Outpost Runes,progression,MOD_WARP,Stardew Valley Expanded +10511,Nexus: Farm Runes,progression,MOD_WARP,Stardew Valley Expanded +10512,Nexus: Wizard Runes,progression,MOD_WARP,Stardew Valley Expanded +10513,Fable Reef Portal,progression,GINGER_ISLAND,Stardew Valley Expanded +10514,Tempered Galaxy Sword,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10515,Tempered Galaxy Dagger,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10516,Tempered Galaxy Hammer,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded +10517,Grandpa's Shed,progression,,Stardew Valley Expanded +10518,Aurora Vineyard Tablet,progression,,Stardew Valley Expanded +10519,Scarlett's Job Offer,progression,,Stardew Valley Expanded +10520,Morgan's Schooling,progression,,Stardew Valley Expanded +10601,Magic Elixir Recipe,progression,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic +10602,Travel Core Recipe,progression,CRAFTSANITY,Magic +10603,Haste Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10604,Hero Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10605,Armor Elixir Recipe,progression,CRAFTSANITY,Stardew Valley Expanded +10606,Neanderthal Skeleton Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10607,Pterodactyl Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10608,Pterodactyl Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10609,Pterodactyl Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10610,T-Rex Skeleton L Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10611,T-Rex Skeleton M Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10612,T-Rex Skeleton R Recipe,progression,CRAFTSANITY,Boarding House and Bus Stop Extension +10701,Resource Pack: 3 Magic Elixir,filler,RESOURCE_PACK,Magic +10702,Resource Pack: 3 Travel Core,filler,RESOURCE_PACK,Magic +10703,Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10704,Hardwood Preservation Chamber,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10705,Resource Pack: 3 Water Shifter,filler,RESOURCE_PACK,Archaeology +10706,Resource Pack: 5 Hardwood Display,filler,RESOURCE_PACK,Archaeology +10707,Resource Pack: 5 Wooden Display,filler,RESOURCE_PACK,Archaeology +10708,Grinder,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10709,Ancient Battery Production Station,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",Archaeology +10710,Hero Elixir,filler,RESOURCE_PACK,Starde Valley Expanded +10711,Aegis Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10712,Haste Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10713,Lightning Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10714,Armor Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10715,Gravity Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded +10716,Barbarian Elixir,filler,RESOURCE_PACK,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 19077c3c45d6..943495fbfe2a 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -1,2939 +1,2939 @@ -id,region,name,tags,mod_name -1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", -32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", -34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", -35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", -36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", -37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", -39,Fish Tank,Deep Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", -47,Boiler Room,Paleontologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", -48,Boiler Room,Archaeologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", -49,Pantry,Slime Farmer Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", -56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -58,Fish Tank,Trash Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", -69,Boiler Room,Recycling Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -73,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -74,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -75,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -76,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", -77,Vault,250g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -78,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -79,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -80,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -81,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -82,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -83,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -84,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -85,Vault,"4,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -87,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -88,Vault,"9,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -89,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -90,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -91,Vault,"18,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -92,Vault,"20,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -93,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -94,Vault,"40,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -95,Vault,"45,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -96,Vault,"100,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -97,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -98,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -99,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -100,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", -101,Pierre's General Store,Large Pack,BACKPACK, -102,Pierre's General Store,Deluxe Pack,BACKPACK, -103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", -107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", -111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", -115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", -119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", -123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", -201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", -202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", -203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", -204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", -205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", -206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", -207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", -208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", -209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", -210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", -211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", -212,Quarry Mine,Grim Reaper statue,MANDATORY, -213,The Mines,The Mines Entrance Cutscene,MANDATORY, -214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, -215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, -216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, -217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, -218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, -219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, -220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, -221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, -222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, -223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, -224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, -225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, -226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, -227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, -228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, -229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, -230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, -231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, -232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, -233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, -234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, -235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, -236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, -237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, -250,Shipping,Demetrius's Breakthrough,MANDATORY -251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", -301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", -302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", -303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", -304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", -305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", -306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", -307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", -308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", -309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", -310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", -311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", -321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", -331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", -332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", -333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", -334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", -335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", -336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", -337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", -338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", -339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", -340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", -341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", -401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, -402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, -403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, -404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, -405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, -406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, -407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, -408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, -409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, -410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, -411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, -412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, -413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, -414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, -415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, -416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, -417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, -418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, -501,Town,Introductions,"STORY_QUEST", -502,Town,How To Win Friends,"STORY_QUEST", -503,Farm,Getting Started,"STORY_QUEST", -504,Farm,Raising Animals,"STORY_QUEST", -505,Farm,Advancement,"STORY_QUEST", -506,Museum,Archaeology,"STORY_QUEST", -507,Wizard Tower,Meet The Wizard,"STORY_QUEST", -508,The Mines - Floor 5,Forging Ahead,"STORY_QUEST", -509,The Mines - Floor 10,Smelting,"STORY_QUEST", -510,The Mines - Floor 15,Initiation,"STORY_QUEST", -511,Mountain,Robin's Lost Axe,"STORY_QUEST", -512,Town,Jodi's Request,"STORY_QUEST", -513,Town,"Mayor's ""Shorts""","STORY_QUEST", -514,Mountain,Blackberry Basket,"STORY_QUEST", -515,Marnie's Ranch,Marnie's Request,"STORY_QUEST", -516,Town,Pam Is Thirsty,"STORY_QUEST", -517,Wizard Tower,A Dark Reagent,"STORY_QUEST", -518,Forest,Cow's Delight,"STORY_QUEST", -519,Skull Cavern Entrance,The Skull Key,"STORY_QUEST", -520,Mountain,Crop Research,"STORY_QUEST", -521,Alex's House,Knee Therapy,"STORY_QUEST", -522,Mountain,Robin's Request,"STORY_QUEST", -523,Skull Cavern Floor 25,Qi's Challenge,"STORY_QUEST", -524,Desert,The Mysterious Qi,"STORY_QUEST", -525,Town,Carving Pumpkins,"STORY_QUEST", -526,Town,A Winter Mystery,"STORY_QUEST", -527,Secret Woods,Strange Note,"STORY_QUEST", -528,Skull Cavern Floor 100,Cryptic Note,"STORY_QUEST", -529,Town,Fresh Fruit,"STORY_QUEST", -530,Mountain,Aquatic Research,"STORY_QUEST", -531,Town,A Soldier's Star,"STORY_QUEST", -532,Town,Mayor's Need,"STORY_QUEST", -533,Saloon,Wanted: Lobster,"STORY_QUEST", -534,Town,Pam Needs Juice,"STORY_QUEST", -535,Sam's House,Fish Casserole,"STORY_QUEST", -536,Beach,Catch A Squid,"STORY_QUEST", -537,Saloon,Fish Stew,"STORY_QUEST", -538,Pierre's General Store,Pierre's Notice,"STORY_QUEST", -539,Clint's Blacksmith,Clint's Attempt,"STORY_QUEST", -540,Town,A Favor For Clint,"STORY_QUEST", -541,Wizard Tower,Staff Of Power,"STORY_QUEST", -542,Town,Granny's Gift,"STORY_QUEST", -543,Desert,Exotic Spirits,"STORY_QUEST", -544,Fishing,Catch a Lingcod,"STORY_QUEST", -545,Island West,The Pirate's Wife,"GINGER_ISLAND,STORY_QUEST", -546,Mutant Bug Lair,Dark Talisman,"STORY_QUEST", -547,Witch's Swamp,Goblin Problem,"STORY_QUEST", -548,Witch's Hut,Magic Ink,"STORY_QUEST", -601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", -602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", -603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", -604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", -605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", -606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", -607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", -608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", -609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", -610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", -611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", -612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", -613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", -614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", -615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", -616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", -617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", -618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", -619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", -620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", -621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", -701,Secret Woods,Old Master Cannoli,MANDATORY, -702,Beach,Beach Bridge Repair,MANDATORY, -703,Desert,Galaxy Sword Shrine,MANDATORY, -704,Farmhouse,Have a Baby,BABY, -705,Farmhouse,Have Another Baby,BABY, -706,Farmhouse,Spouse Stardrop,, -707,Sewer,Krobus Stardrop,MANDATORY, -801,Forest,Help Wanted: Gathering 1,HELP_WANTED, -802,Forest,Help Wanted: Gathering 2,HELP_WANTED, -803,Forest,Help Wanted: Gathering 3,HELP_WANTED, -804,Forest,Help Wanted: Gathering 4,HELP_WANTED, -805,Forest,Help Wanted: Gathering 5,HELP_WANTED, -806,Forest,Help Wanted: Gathering 6,HELP_WANTED, -807,Forest,Help Wanted: Gathering 7,HELP_WANTED, -808,Forest,Help Wanted: Gathering 8,HELP_WANTED, -811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, -812,The Mines - Floor 15,Help Wanted: Slay Monsters 2,HELP_WANTED, -813,The Mines - Floor 25,Help Wanted: Slay Monsters 3,HELP_WANTED, -814,The Mines - Floor 35,Help Wanted: Slay Monsters 4,HELP_WANTED, -815,The Mines - Floor 45,Help Wanted: Slay Monsters 5,HELP_WANTED, -816,The Mines - Floor 55,Help Wanted: Slay Monsters 6,HELP_WANTED, -817,The Mines - Floor 65,Help Wanted: Slay Monsters 7,HELP_WANTED, -818,The Mines - Floor 75,Help Wanted: Slay Monsters 8,HELP_WANTED, -821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, -822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, -823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, -824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, -825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, -826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, -827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, -828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, -841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, -842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, -843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, -844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, -845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, -846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, -847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, -848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, -849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, -850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, -851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, -852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, -853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, -854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, -855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, -856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, -857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, -858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, -859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, -860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, -861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, -862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, -863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, -864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, -865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, -866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, -867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, -868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, -869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, -870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, -871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, -872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, -901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", -902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", -903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", -911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", -912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", -913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", -921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", -932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", -933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", -941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", -942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", -943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", -951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", -952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", -953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", -961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", -962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", -963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", -1001,Fishing,Fishsanity: Carp,FISHSANITY, -1002,Fishing,Fishsanity: Herring,FISHSANITY, -1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, -1004,Fishing,Fishsanity: Anchovy,FISHSANITY, -1005,Fishing,Fishsanity: Sardine,FISHSANITY, -1006,Fishing,Fishsanity: Sunfish,FISHSANITY, -1007,Fishing,Fishsanity: Perch,FISHSANITY, -1008,Fishing,Fishsanity: Chub,FISHSANITY, -1009,Fishing,Fishsanity: Bream,FISHSANITY, -1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, -1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, -1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, -1013,Fishing,Fishsanity: Walleye,FISHSANITY, -1014,Fishing,Fishsanity: Shad,FISHSANITY, -1015,Fishing,Fishsanity: Bullhead,FISHSANITY, -1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, -1017,Fishing,Fishsanity: Salmon,FISHSANITY, -1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, -1019,Fishing,Fishsanity: Tilapia,FISHSANITY, -1020,Fishing,Fishsanity: Woodskip,FISHSANITY, -1021,Fishing,Fishsanity: Flounder,FISHSANITY, -1022,Fishing,Fishsanity: Halibut,FISHSANITY, -1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", -1024,Fishing,Fishsanity: Slimejack,FISHSANITY, -1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, -1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, -1027,Fishing,Fishsanity: Pike,FISHSANITY, -1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, -1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", -1030,Fishing,Fishsanity: Albacore,FISHSANITY, -1031,Fishing,Fishsanity: Sandfish,FISHSANITY, -1032,Fishing,Fishsanity: Stonefish,FISHSANITY, -1033,Fishing,Fishsanity: Tuna,FISHSANITY, -1034,Fishing,Fishsanity: Eel,FISHSANITY, -1035,Fishing,Fishsanity: Catfish,FISHSANITY, -1036,Fishing,Fishsanity: Squid,FISHSANITY, -1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, -1038,Fishing,Fishsanity: Dorado,FISHSANITY, -1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, -1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, -1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, -1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", -1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, -1044,Fishing,Fishsanity: Lingcod,FISHSANITY, -1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, -1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, -1047,Fishing,Fishsanity: Octopus,FISHSANITY, -1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, -1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, -1050,Fishing,Fishsanity: Blobfish,FISHSANITY, -1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, -1052,Fishing,Fishsanity: Angler,FISHSANITY, -1053,Fishing,Fishsanity: Legend,FISHSANITY, -1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, -1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, -1056,Town,Fishsanity: Crayfish,FISHSANITY, -1057,Town,Fishsanity: Snail,FISHSANITY, -1058,Town,Fishsanity: Periwinkle,FISHSANITY, -1059,Beach,Fishsanity: Lobster,FISHSANITY, -1060,Beach,Fishsanity: Clam,FISHSANITY, -1061,Beach,Fishsanity: Crab,FISHSANITY, -1062,Beach,Fishsanity: Cockle,FISHSANITY, -1063,Beach,Fishsanity: Mussel,FISHSANITY, -1064,Beach,Fishsanity: Shrimp,FISHSANITY, -1065,Beach,Fishsanity: Oyster,FISHSANITY, -1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", -1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, -1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, -1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, -1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, -1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, -1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, -1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, -1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, -1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, -1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, -1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, -1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, -1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, -1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, -1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, -1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, -1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, -1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, -1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, -1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, -1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, -1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, -1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, -1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, -1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, -1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, -1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, -1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, -1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, -1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, -1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, -1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, -1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, -1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, -1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, -1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, -1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, -1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, -1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, -1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, -1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, -1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, -1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, -1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, -1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, -1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, -1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", -1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, -1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, -1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, -1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, -1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, -1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, -1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, -1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, -1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, -1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, -1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, -1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, -1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, -1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, -1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, -1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, -1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, -1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, -1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, -1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, -1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, -1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, -1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, -1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, -1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, -1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, -1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, -1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, -1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, -1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, -1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, -1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, -1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, -1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, -1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, -1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, -1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, -1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, -1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, -1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, -1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, -1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, -1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, -1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, -1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, -1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, -1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, -1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, -1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, -1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, -1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, -1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, -1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, -1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, -1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, -1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, -1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, -1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, -1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, -1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, -1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, -1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, -1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, -1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, -1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, -1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, -1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, -1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, -1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, -1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, -1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, -1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, -1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, -1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, -1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, -1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, -1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, -1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, -1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, -1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, -1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, -1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, -1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, -1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, -1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, -1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, -1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, -1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, -1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, -1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, -1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, -1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, -1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, -1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, -1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, -1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, -1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, -1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, -1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, -1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, -1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, -1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, -1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, -1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, -1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, -1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, -1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, -1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, -1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, -1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, -1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, -1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, -1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, -1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, -1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, -1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, -1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, -1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, -1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, -1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, -1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, -1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, -1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, -1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, -1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, -1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, -1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, -1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, -1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, -1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, -1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, -1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, -1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, -1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, -1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, -1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, -1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, -1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, -1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, -1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, -1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, -1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, -1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, -1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, -1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, -1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, -1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, -1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, -1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, -1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, -1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, -1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, -1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, -1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, -1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, -1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, -1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, -1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, -1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, -1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, -1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, -1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, -1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, -1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, -1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, -1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, -1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, -1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, -1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, -1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, -1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, -1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, -1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, -1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, -1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, -1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, -1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, -1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, -1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, -1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, -1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, -1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, -1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, -1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, -1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, -1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, -1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, -1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, -1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, -1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, -1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, -1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, -1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, -1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, -1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, -1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, -1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, -1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, -1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, -1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, -1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, -1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, -1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, -1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, -1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, -1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, -1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, -1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, -1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, -1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, -1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, -1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, -1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, -1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, -1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, -1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, -1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, -1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, -1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, -1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, -1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, -1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, -1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, -1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, -1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, -1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, -1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, -1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, -1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, -1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, -1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, -1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, -1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, -1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, -1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, -1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, -1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, -1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, -1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, -1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, -1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, -1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, -1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, -1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, -1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, -1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, -1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, -1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, -1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, -1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, -1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, -1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, -1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, -1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, -1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, -1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, -1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, -1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, -1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, -1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, -1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, -1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, -1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, -1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, -1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, -1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, -1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, -1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, -1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, -1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, -1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, -1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, -1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, -1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, -1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, -1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, -1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, -1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, -1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, -1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, -1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, -1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, -1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, -1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, -1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, -1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, -1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, -1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, -1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, -1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, -1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, -1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, -1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, -1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, -1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, -1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, -1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, -1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, -1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, -1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, -1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, -1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, -1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, -1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, -1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, -1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, -1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, -1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, -1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, -1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, -1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, -1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, -1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, -1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, -1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, -1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, -1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, -1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, -1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, -1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, -1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, -1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, -1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, -1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, -1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, -1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, -1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, -1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, -1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, -1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, -1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, -1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, -1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, -1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, -1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, -1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, -1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, -1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, -1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, -1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, -1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, -1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, -1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, -1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, -1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, -1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, -1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, -1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, -1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, -1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, -1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, -1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, -1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, -1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, -1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, -1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", -1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", -1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", -1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", -1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", -1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", -1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", -1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", -1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", -1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", -1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, -1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, -1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, -1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, -1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, -1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, -1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, -1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, -1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, -1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, -1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, -1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, -1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, -1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, -1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, -1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, -1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, -1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, -1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, -1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, -1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, -1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, -1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, -1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, -1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, -1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, -1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, -1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, -1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, -1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, -1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, -1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, -1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, -1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, -1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, -1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, -1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, -1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, -1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, -1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, -1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, -1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, -1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, -1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, -1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, -1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, -1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, -1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, -1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, -1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, -1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, -1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, -1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, -1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, -1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, -1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, -1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, -1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, -1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, -1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, -1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, -1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, -1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, -1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, -1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, -1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, -1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, -1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, -1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, -1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, -1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, -1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, -1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, -1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, -1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, -1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, -1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, -1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, -1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, -1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, -1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, -1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, -1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, -1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, -1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, -1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, -1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, -1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, -1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, -1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, -1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, -1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, -1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, -1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, -1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, -1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, -1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, -1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, -1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, -1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, -1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, -1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, -1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, -1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, -1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, -1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, -1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, -1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, -1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, -1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, -1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, -1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, -1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, -1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, -1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, -1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, -1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, -1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, -1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, -2001,Egg Festival,Egg Hunt Victory,FESTIVAL, -2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, -2003,Flower Dance,Dance with someone,FESTIVAL, -2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, -2005,Luau,Luau Soup,FESTIVAL, -2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, -2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, -2008,Stardew Valley Fair,Grange Display,FESTIVAL, -2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, -2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, -2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, -2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, -2013,Festival of Ice,Win Fishing Competition,FESTIVAL, -2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, -2015,Night Market,Mermaid Pearl,FESTIVAL, -2016,Night Market,Cone Hat,FESTIVAL_HARD, -2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, -2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, -2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, -2020,Night Market,Lupini: Red Eagle,FESTIVAL, -2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, -2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, -2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, -2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, -2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, -2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, -2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, -2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, -2029,Feast of the Winter Star,Secret Santa,FESTIVAL, -2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, -2031,Farm,Collect All Rarecrows,FESTIVAL, -2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, -2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, -2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, -2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, -2036,Casino,Rarecrow #3 (Alien),FESTIVAL, -2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, -2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, -2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, -2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, -2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, -2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, -2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, -2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, -2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, -2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, -2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, -2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, -2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, -2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", -2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, -2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, -2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", -2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", -2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, -2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, -2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, -2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", -2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", -2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", -2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", -2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", -2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", -2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", -2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", -2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", -2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", -2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, -2216,Field Office,Complete Island Field Office,GINGER_ISLAND, -2301,Farming,Harvest Amaranth,CROPSANITY, -2302,Farming,Harvest Artichoke,CROPSANITY, -2303,Farming,Harvest Beet,CROPSANITY, -2304,Farming,Harvest Blue Jazz,CROPSANITY, -2305,Farming,Harvest Blueberry,CROPSANITY, -2306,Farming,Harvest Bok Choy,CROPSANITY, -2307,Farming,Harvest Cauliflower,CROPSANITY, -2308,Farming,Harvest Corn,CROPSANITY, -2309,Farming,Harvest Cranberries,CROPSANITY, -2310,Farming,Harvest Eggplant,CROPSANITY, -2311,Farming,Harvest Fairy Rose,CROPSANITY, -2312,Farming,Harvest Garlic,CROPSANITY, -2313,Farming,Harvest Grape,CROPSANITY, -2314,Farming,Harvest Green Bean,CROPSANITY, -2315,Farming,Harvest Hops,CROPSANITY, -2316,Farming,Harvest Hot Pepper,CROPSANITY, -2317,Farming,Harvest Kale,CROPSANITY, -2318,Farming,Harvest Melon,CROPSANITY, -2319,Farming,Harvest Parsnip,CROPSANITY, -2320,Farming,Harvest Poppy,CROPSANITY, -2321,Farming,Harvest Potato,CROPSANITY, -2322,Farming,Harvest Pumpkin,CROPSANITY, -2323,Farming,Harvest Radish,CROPSANITY, -2324,Farming,Harvest Red Cabbage,CROPSANITY, -2325,Farming,Harvest Rhubarb,CROPSANITY, -2326,Farming,Harvest Starfruit,CROPSANITY, -2327,Farming,Harvest Strawberry,CROPSANITY, -2328,Farming,Harvest Summer Spangle,CROPSANITY, -2329,Farming,Harvest Sunflower,CROPSANITY, -2330,Farming,Harvest Tomato,CROPSANITY, -2331,Farming,Harvest Tulip,CROPSANITY, -2332,Farming,Harvest Unmilled Rice,CROPSANITY, -2333,Farming,Harvest Wheat,CROPSANITY, -2334,Farming,Harvest Yam,CROPSANITY, -2335,Farming,Harvest Cactus Fruit,CROPSANITY, -2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", -2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", -2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, -2339,Farming,Harvest Apple,CROPSANITY, -2340,Farming,Harvest Apricot,CROPSANITY, -2341,Farming,Harvest Cherry,CROPSANITY, -2342,Farming,Harvest Orange,CROPSANITY, -2343,Farming,Harvest Pomegranate,CROPSANITY, -2344,Farming,Harvest Peach,CROPSANITY, -2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", -2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", -2347,Farming,Harvest Coffee Bean,CROPSANITY, -2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2416,Shipping,Shipsanity: Anchor,SHIPSANITY, -2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, -2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, -2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, -2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, -2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, -2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, -2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, -2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, -2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, -2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, -2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, -2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, -2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, -2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, -2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, -2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, -2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, -2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, -2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, -2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, -2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, -2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, -2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, -2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, -2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, -2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, -2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, -2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, -2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, -2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, -2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, -2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, -2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2454,Shipping,Shipsanity: Coffee,SHIPSANITY, -2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, -2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, -2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, -2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, -2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, -2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, -2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, -2479,Shipping,Shipsanity: Bread,SHIPSANITY, -2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, -2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, -2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, -2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, -2484,Shipping,Shipsanity: Chowder,SHIPSANITY, -2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, -2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, -2487,Shipping,Shipsanity: Cookies,SHIPSANITY, -2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, -2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, -2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, -2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, -2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, -2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, -2494,Shipping,Shipsanity: Escargot,SHIPSANITY, -2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, -2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, -2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, -2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, -2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, -2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, -2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, -2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, -2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, -2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, -2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, -2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, -2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, -2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, -2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, -2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, -2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, -2512,Shipping,Shipsanity: Omelet,SHIPSANITY, -2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, -2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, -2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, -2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, -2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, -2518,Shipping,Shipsanity: Pizza,SHIPSANITY, -2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, -2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, -2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, -2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, -2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, -2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, -2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, -2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, -2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, -2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, -2529,Shipping,Shipsanity: Salad,SHIPSANITY, -2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, -2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, -2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, -2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, -2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, -2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, -2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, -2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, -2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, -2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, -2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, -2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, -2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, -2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, -2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, -2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, -2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, -2547,Shipping,Shipsanity: Bait,SHIPSANITY, -2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, -2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, -2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, -2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, -2552,Shipping,Shipsanity: Bomb,SHIPSANITY, -2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, -2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, -2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, -2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, -2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, -2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, -2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, -2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, -2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, -2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, -2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, -2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, -2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, -2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, -2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, -2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, -2569,Shipping,Shipsanity: Gate,SHIPSANITY, -2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, -2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, -2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, -2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, -2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, -2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, -2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, -2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, -2578,Shipping,Shipsanity: Magnet,SHIPSANITY, -2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, -2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, -2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, -2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, -2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, -2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, -2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, -2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, -2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, -2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, -2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, -2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, -2591,Shipping,Shipsanity: Spinner,SHIPSANITY, -2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, -2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, -2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, -2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, -2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, -2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, -2598,Shipping,Shipsanity: Torch,SHIPSANITY, -2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, -2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, -2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, -2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, -2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, -2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, -2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", -2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, -2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, -2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, -2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, -2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, -2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, -2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", -2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", -2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", -2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", -2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", -2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", -2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", -2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", -2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", -2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", -2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", -2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", -2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", -2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", -2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", -2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", -2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", -2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", -2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", -2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", -2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", -2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", -2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", -2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", -2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", -2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", -2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", -2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", -2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", -2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", -2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", -2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", -2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", -2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", -2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", -2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", -2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", -2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", -2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", -2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", -2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", -2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", -2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", -2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", -2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", -2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", -2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", -2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", -2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", -2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", -2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", -2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", -2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", -2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", -2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", -2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", -2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", -2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", -2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, -2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2755,Shipping,Shipsanity: Oil,SHIPSANITY, -2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2757,Shipping,Shipsanity: Rice,SHIPSANITY, -2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2760,Shipping,Shipsanity: Sugar,SHIPSANITY, -2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, -2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, -2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, -2765,Shipping,Shipsanity: Alamite,SHIPSANITY, -2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, -2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, -2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, -2769,Shipping,Shipsanity: Baryte,SHIPSANITY, -2770,Shipping,Shipsanity: Basalt,SHIPSANITY, -2771,Shipping,Shipsanity: Bixite,SHIPSANITY, -2772,Shipping,Shipsanity: Calcite,SHIPSANITY, -2773,Shipping,Shipsanity: Celestine,SHIPSANITY, -2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2776,Shipping,Shipsanity: Diamond,SHIPSANITY, -2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, -2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, -2779,Shipping,Shipsanity: Emerald,SHIPSANITY, -2780,Shipping,Shipsanity: Esperite,SHIPSANITY, -2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, -2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, -2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, -2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, -2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, -2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, -2787,Shipping,Shipsanity: Geminite,SHIPSANITY, -2788,Shipping,Shipsanity: Geode,SHIPSANITY, -2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, -2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2791,Shipping,Shipsanity: Granite,SHIPSANITY, -2792,Shipping,Shipsanity: Helvite,SHIPSANITY, -2793,Shipping,Shipsanity: Hematite,SHIPSANITY, -2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2796,Shipping,Shipsanity: Jade,SHIPSANITY, -2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, -2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, -2799,Shipping,Shipsanity: Jasper,SHIPSANITY, -2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, -2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, -2802,Shipping,Shipsanity: Limestone,SHIPSANITY, -2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, -2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, -2805,Shipping,Shipsanity: Malachite,SHIPSANITY, -2806,Shipping,Shipsanity: Marble,SHIPSANITY, -2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, -2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, -2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, -2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, -2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, -2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, -2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, -2814,Shipping,Shipsanity: Opal,SHIPSANITY, -2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, -2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, -2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, -2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, -2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, -2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, -2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, -2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, -2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, -2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, -2825,Shipping,Shipsanity: Quartz,SHIPSANITY, -2826,Shipping,Shipsanity: Ruby,SHIPSANITY, -2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, -2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, -2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, -2830,Shipping,Shipsanity: Slate,SHIPSANITY, -2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, -2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, -2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, -2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, -2835,Shipping,Shipsanity: Topaz,SHIPSANITY, -2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, -2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, -2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, -2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, -2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, -2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, -2848,Shipping,Shipsanity: Hay,SHIPSANITY, -2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, -2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, -2851,Shipping,Shipsanity: Pearl,SHIPSANITY, -2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, -2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, -2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, -2855,Shipping,Shipsanity: White Algae,SHIPSANITY, -2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, -2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, -2858,Shipping,Shipsanity: Acorn,SHIPSANITY, -2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, -2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, -2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, -2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, -2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, -2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, -2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, -2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, -2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, -2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, -2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, -2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, -2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, -2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, -2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, -2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, -2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, -2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, -2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, -2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, -2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, -2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, -2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, -2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, -2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, -2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, -2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, -2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, -2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, -2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, -2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, -2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, -2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, -2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, -2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, -2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, -2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, -2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, -2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, -2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, -2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, -2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, -2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, -2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, -2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, -2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, -2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, -2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, -2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, -2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, -2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, -2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, -2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, -2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, -2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, -2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, -2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, -2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, -2918,Shipping,Shipsanity: Trash,SHIPSANITY, -2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, -2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", -2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", -2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", -2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", -2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", -2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", -2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", -2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", -2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", -2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", -2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", -2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", -2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", -2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", -2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", -2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", -2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", -2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", -2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", -2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", -2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", -2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", -2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", -2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", -2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", -2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", -2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", -2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", -2966,Shipping,Shipsanity: Movie Ticket,"SHIPSANITY", -2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", -2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", -2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", -2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", -2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", -2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", -2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", -3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", -3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", -3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", -3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", -3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", -3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", -3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", -3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", -3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", -3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", -3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", -3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", -3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", -3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", -3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", -3201,Kitchen,Cook Algae Soup,COOKSANITY, -3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", -3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, -3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", -3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", -3206,Kitchen,Cook Bean Hotpot,COOKSANITY, -3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", -3208,Kitchen,Cook Blueberry Tart,COOKSANITY, -3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", -3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", -3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", -3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, -3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", -3214,Kitchen,Cook Chowder,COOKSANITY, -3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", -3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", -3217,Kitchen,Cook Cookies,COOKSANITY, -3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", -3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", -3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, -3221,Kitchen,Cook Crispy Bass,COOKSANITY, -3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, -3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, -3224,Kitchen,Cook Escargot,COOKSANITY, -3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, -3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", -3227,Kitchen,Cook Fish Stew,COOKSANITY, -3228,Kitchen,Cook Fish Taco,COOKSANITY, -3229,Kitchen,Cook Fried Calamari,COOKSANITY, -3230,Kitchen,Cook Fried Eel,COOKSANITY, -3231,Kitchen,Cook Fried Egg,COOKSANITY, -3232,Kitchen,Cook Fried Mushroom,COOKSANITY, -3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", -3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", -3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", -3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", -3237,Kitchen,Cook Ice Cream,COOKSANITY, -3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", -3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", -3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", -3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", -3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", -3243,Kitchen,Cook Miner's Treat,COOKSANITY, -3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", -3245,Kitchen,Cook Pale Broth,COOKSANITY, -3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", -3247,Kitchen,Cook Parsnip Soup,COOKSANITY, -3248,Kitchen,Cook Pepper Poppers,COOKSANITY, -3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", -3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", -3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", -3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", -3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", -3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", -3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, -3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", -3257,Kitchen,Cook Red Plate,COOKSANITY, -3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, -3259,Kitchen,Cook Rice Pudding,COOKSANITY, -3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", -3261,Kitchen,Cook Roots Platter,COOKSANITY, -3262,Kitchen,Cook Salad,COOKSANITY, -3263,Kitchen,Cook Salmon Dinner,COOKSANITY, -3264,Kitchen,Cook Sashimi,COOKSANITY, -3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, -3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", -3267,Kitchen,Cook Spaghetti,COOKSANITY, -3268,Kitchen,Cook Spicy Eel,COOKSANITY, -3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, -3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", -3271,Kitchen,Cook Strange Bun,COOKSANITY, -3272,Kitchen,Cook Stuffing,COOKSANITY, -3273,Kitchen,Cook Super Meal,COOKSANITY, -3274,Kitchen,Cook Survival Burger,COOKSANITY, -3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, -3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", -3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, -3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", -3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", -3280,Kitchen,Cook Vegetable Medley,COOKSANITY, -3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", -3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, -3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", -3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", -3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", -3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", -3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", -3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", -3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", -3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", -3401,Farm,Craft Cherry Bomb,CRAFTSANITY, -3402,Farm,Craft Bomb,CRAFTSANITY, -3403,Farm,Craft Mega Bomb,CRAFTSANITY, -3404,Farm,Craft Gate,CRAFTSANITY, -3405,Farm,Craft Wood Fence,CRAFTSANITY, -3406,Farm,Craft Stone Fence,CRAFTSANITY, -3407,Farm,Craft Iron Fence,CRAFTSANITY, -3408,Farm,Craft Hardwood Fence,CRAFTSANITY, -3409,Farm,Craft Sprinkler,CRAFTSANITY, -3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, -3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, -3412,Farm,Craft Bee House,CRAFTSANITY, -3413,Farm,Craft Cask,CRAFTSANITY, -3414,Farm,Craft Cheese Press,CRAFTSANITY, -3415,Farm,Craft Keg,CRAFTSANITY, -3416,Farm,Craft Loom,CRAFTSANITY, -3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, -3418,Farm,Craft Oil Maker,CRAFTSANITY, -3419,Farm,Craft Preserves Jar,CRAFTSANITY, -3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, -3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, -3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, -3423,Farm,Craft Speed-Gro,CRAFTSANITY, -3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, -3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", -3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, -3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, -3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", -3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, -3430,Farm,Craft Spring Seeds,CRAFTSANITY, -3431,Farm,Craft Summer Seeds,CRAFTSANITY, -3432,Farm,Craft Fall Seeds,CRAFTSANITY, -3433,Farm,Craft Winter Seeds,CRAFTSANITY, -3434,Farm,Craft Ancient Seeds,CRAFTSANITY, -3435,Farm,Craft Grass Starter,CRAFTSANITY, -3436,Farm,Craft Tea Sapling,CRAFTSANITY, -3437,Farm,Craft Fiber Seeds,CRAFTSANITY, -3438,Farm,Craft Wood Floor,CRAFTSANITY, -3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, -3440,Farm,Craft Straw Floor,CRAFTSANITY, -3441,Farm,Craft Weathered Floor,CRAFTSANITY, -3442,Farm,Craft Crystal Floor,CRAFTSANITY, -3443,Farm,Craft Stone Floor,CRAFTSANITY, -3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, -3445,Farm,Craft Brick Floor,CRAFTSANITY, -3446,Farm,Craft Wood Path,CRAFTSANITY, -3447,Farm,Craft Gravel Path,CRAFTSANITY, -3448,Farm,Craft Cobblestone Path,CRAFTSANITY, -3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, -3450,Farm,Craft Crystal Path,CRAFTSANITY, -3451,Farm,Craft Spinner,CRAFTSANITY, -3452,Farm,Craft Trap Bobber,CRAFTSANITY, -3453,Farm,Craft Cork Bobber,CRAFTSANITY, -3454,Farm,Craft Quality Bobber,CRAFTSANITY, -3455,Farm,Craft Treasure Hunter,CRAFTSANITY, -3456,Farm,Craft Dressed Spinner,CRAFTSANITY, -3457,Farm,Craft Barbed Hook,CRAFTSANITY, -3458,Farm,Craft Magnet,CRAFTSANITY, -3459,Farm,Craft Bait,CRAFTSANITY, -3460,Farm,Craft Wild Bait,CRAFTSANITY, -3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", -3462,Farm,Craft Crab Pot,CRAFTSANITY, -3463,Farm,Craft Sturdy Ring,CRAFTSANITY, -3464,Farm,Craft Warrior Ring,CRAFTSANITY, -3465,Farm,Craft Ring of Yoba,CRAFTSANITY, -3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", -3467,Farm,Craft Glowstone Ring,CRAFTSANITY, -3468,Farm,Craft Iridium Band,CRAFTSANITY, -3469,Farm,Craft Wedding Ring,CRAFTSANITY, -3470,Farm,Craft Field Snack,CRAFTSANITY, -3471,Farm,Craft Bug Steak,CRAFTSANITY, -3472,Farm,Craft Life Elixir,CRAFTSANITY, -3473,Farm,Craft Oil of Garlic,CRAFTSANITY, -3474,Farm,Craft Monster Musk,CRAFTSANITY, -3475,Farm,Craft Fairy Dust,CRAFTSANITY, -3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, -3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, -3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, -3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, -3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", -3481,Farm,Craft Rain Totem,CRAFTSANITY, -3482,Farm,Craft Torch,CRAFTSANITY, -3483,Farm,Craft Campfire,CRAFTSANITY, -3484,Farm,Craft Wooden Brazier,CRAFTSANITY, -3485,Farm,Craft Stone Brazier,CRAFTSANITY, -3486,Farm,Craft Gold Brazier,CRAFTSANITY, -3487,Farm,Craft Carved Brazier,CRAFTSANITY, -3488,Farm,Craft Stump Brazier,CRAFTSANITY, -3489,Farm,Craft Barrel Brazier,CRAFTSANITY, -3490,Farm,Craft Skull Brazier,CRAFTSANITY, -3491,Farm,Craft Marble Brazier,CRAFTSANITY, -3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, -3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, -3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, -3495,Farm,Craft Bone Mill,CRAFTSANITY, -3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, -3497,Farm,Craft Crystalarium,CRAFTSANITY, -3498,Farm,Craft Furnace,CRAFTSANITY, -3499,Farm,Craft Geode Crusher,CRAFTSANITY, -3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", -3501,Farm,Craft Lightning Rod,CRAFTSANITY, -3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", -3503,Farm,Craft Recycling Machine,CRAFTSANITY, -3504,Farm,Craft Seed Maker,CRAFTSANITY, -3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, -3506,Farm,Craft Slime Incubator,CRAFTSANITY, -3507,Farm,Craft Solar Panel,CRAFTSANITY, -3508,Farm,Craft Tapper,CRAFTSANITY, -3509,Farm,Craft Worm Bin,CRAFTSANITY, -3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, -3511,Farm,Craft Wicked Statue,CRAFTSANITY, -3512,Farm,Craft Flute Block,CRAFTSANITY, -3513,Farm,Craft Drum Block,CRAFTSANITY, -3514,Farm,Craft Chest,CRAFTSANITY, -3515,Farm,Craft Stone Chest,CRAFTSANITY, -3516,Farm,Craft Wood Sign,CRAFTSANITY, -3517,Farm,Craft Stone Sign,CRAFTSANITY, -3518,Farm,Craft Dark Sign,CRAFTSANITY, -3519,Farm,Craft Garden Pot,CRAFTSANITY, -3520,Farm,Craft Scarecrow,CRAFTSANITY, -3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, -3522,Farm,Craft Staircase,CRAFTSANITY, -3523,Farm,Craft Explosive Ammo,CRAFTSANITY, -3524,Farm,Craft Transmute (Fe),CRAFTSANITY, -3525,Farm,Craft Transmute (Au),CRAFTSANITY, -3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, -3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, -3528,Farm,Craft Farm Computer,CRAFTSANITY, -3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", -3530,Farm,Craft Cookout Kit,CRAFTSANITY, -3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, -3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, -3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, -3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, -3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, -3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, -3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, -3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, -3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, -3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, -3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, -3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, -3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", -3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, -3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, -3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, -3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, -3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, -3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, -3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, -3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, -3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, -3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, -3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, -3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", -3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY,GINGER_ISLAND", -5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill -5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill -5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic -5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill -5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology -5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill -5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic -5502,Magic Altar,Analyze: Till,MANDATORY,Magic -5503,Magic Altar,Analyze: Water,MANDATORY,Magic -5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic -5505,Magic Altar,Analyze: Evac,MANDATORY,Magic -5506,Magic Altar,Analyze: Haste,MANDATORY,Magic -5507,Magic Altar,Analyze: Heal,MANDATORY,Magic -5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic -5509,Magic Altar,Analyze: Descend,MANDATORY,Magic -5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic -5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic -5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic -5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic -5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic -5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic -5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic -5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic -5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic -5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic -5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic -5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic -6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas -6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas -6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas -6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas -6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas -6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas -6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas -6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas -6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas -6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas -6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas -6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas -6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas -6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas -6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba -6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba -6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba -6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba -6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba -6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba -6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba -6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba -6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba -6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba -6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) -6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) -6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) -6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) -6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) -6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) -6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) -6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) -6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) -6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) -6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) -6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC -6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC -6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC -6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC -6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC -6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC -6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC -6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC -6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC -6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC -6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC -6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC -6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC -6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC -6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick -6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick -6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick -6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick -6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick -6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick -6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick -6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick -6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick -6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick -6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick -6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick -6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick -6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick -6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC -6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC -6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC -6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC -6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC -6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC -6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC -6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC -6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC -6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC -6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC -6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC -6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC -6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC -6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited -6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited -6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited -6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited -6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited -6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited -6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited -6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited -6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited -6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited -6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited -6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited -6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited -6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited -6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene -6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene -6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene -6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene -6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene -6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene -6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene -6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene -6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene -6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene -6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene -6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene -6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene -6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene -6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC -6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC -6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC -6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC -6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC -6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC -6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC -6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC -6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC -6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC -6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley -6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley -6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley -6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley -6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley -6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley -6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley -6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley -6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley -6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley -6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley -6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley -6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley -6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley -6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded -6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded -6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded -6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded -6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded -6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded -6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded -6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded -6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded -6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded -6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded -6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded -6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded -6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded -6153,Galmoran Outpost,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6154,Galmoran Outpost,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6155,Galmoran Outpost,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6156,Galmoran Outpost,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6157,Galmoran Outpost,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6158,Galmoran Outpost,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6159,Galmoran Outpost,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6160,Galmoran Outpost,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6161,Galmoran Outpost,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6162,Galmoran Outpost,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6163,Galmoran Outpost,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6164,Galmoran Outpost,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6165,Galmoran Outpost,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6166,Galmoran Outpost,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded -6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded -6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded -6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded -6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded -6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded -6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded -6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded -6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded -6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded -6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded -6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded -6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded -6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded -6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded -6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded -6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded -6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded -6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded -6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded -6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded -6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded -6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded -6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded -6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded -6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded -6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded -6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded -6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded -6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded -6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded -6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded -6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded -6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded -6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded -6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded -6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded -6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded -6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded -6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded -6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded -6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded -6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded -6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded -6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded -6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded -6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded -6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded -6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded -6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded -6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded -6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded -6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded -6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded -6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded -6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded -6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded -6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded -6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded -6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded -6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded -6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded -6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded -6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded -6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded -6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded -6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded -6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded -6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded -6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded -6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded -6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded -6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded -6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded -6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded -6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded -6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded -6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded -6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded -6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded -6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded -6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded -6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded -6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6273,Scarlett's House,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded -6274,Scarlett's House,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded -6275,Scarlett's House,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded -6276,Scarlett's House,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded -6277,Scarlett's House,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded -6278,Scarlett's House,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded -6279,Scarlett's House,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded -6280,Scarlett's House,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded -6281,Scarlett's House,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded -6282,Scarlett's House,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded -6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded -6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded -6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded -6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded -6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded -6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded -6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded -6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded -6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded -6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded -6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded -6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded -6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded -6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded -6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded -6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded -6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded -6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded -6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded -6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded -6303,Witch's Swamp,Friendsanity: Zic 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6304,Witch's Swamp,Friendsanity: Zic 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6305,Witch's Swamp,Friendsanity: Zic 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6306,Witch's Swamp,Friendsanity: Zic 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6307,Witch's Swamp,Friendsanity: Zic 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6308,Witch's Swamp,Friendsanity: Zic 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6309,Witch's Swamp,Friendsanity: Zic 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6310,Witch's Swamp,Friendsanity: Zic 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6311,Witch's Swamp,Friendsanity: Zic 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6312,Witch's Swamp,Friendsanity: Zic 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul -6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch -6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch -6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch -6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch -6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch -6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch -6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch -6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch -6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch -6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch -6323,Mouse House,Friendsanity: Lacey 1 <3,FRIENDSANITY,Hat Mouse Lacey -6324,Mouse House,Friendsanity: Lacey 2 <3,FRIENDSANITY,Hat Mouse Lacey -6325,Mouse House,Friendsanity: Lacey 3 <3,FRIENDSANITY,Hat Mouse Lacey -6326,Mouse House,Friendsanity: Lacey 4 <3,FRIENDSANITY,Hat Mouse Lacey -6327,Mouse House,Friendsanity: Lacey 5 <3,FRIENDSANITY,Hat Mouse Lacey -6328,Mouse House,Friendsanity: Lacey 6 <3,FRIENDSANITY,Hat Mouse Lacey -6329,Mouse House,Friendsanity: Lacey 7 <3,FRIENDSANITY,Hat Mouse Lacey -6330,Mouse House,Friendsanity: Lacey 8 <3,FRIENDSANITY,Hat Mouse Lacey -6331,Mouse House,Friendsanity: Lacey 9 <3,FRIENDSANITY,Hat Mouse Lacey -6332,Mouse House,Friendsanity: Lacey 10 <3,FRIENDSANITY,Hat Mouse Lacey -6333,Mouse House,Friendsanity: Lacey 11 <3,FRIENDSANITY,Hat Mouse Lacey -6334,Mouse House,Friendsanity: Lacey 12 <3,FRIENDSANITY,Hat Mouse Lacey -6335,Mouse House,Friendsanity: Lacey 13 <3,FRIENDSANITY,Hat Mouse Lacey -6336,Mouse House,Friendsanity: Lacey 14 <3,FRIENDSANITY,Hat Mouse Lacey -6337,Boarding House - First Floor,Friendsanity: Joel 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6338,Boarding House - First Floor,Friendsanity: Joel 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6339,Boarding House - First Floor,Friendsanity: Joel 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6340,Boarding House - First Floor,Friendsanity: Joel 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6341,Boarding House - First Floor,Friendsanity: Joel 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6342,Boarding House - First Floor,Friendsanity: Joel 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6343,Boarding House - First Floor,Friendsanity: Joel 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6344,Boarding House - First Floor,Friendsanity: Joel 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6345,Boarding House - First Floor,Friendsanity: Joel 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6346,Boarding House - First Floor,Friendsanity: Joel 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6347,Boarding House - First Floor,Friendsanity: Sheila 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6348,Boarding House - First Floor,Friendsanity: Sheila 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6349,Boarding House - First Floor,Friendsanity: Sheila 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6350,Boarding House - First Floor,Friendsanity: Sheila 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6351,Boarding House - First Floor,Friendsanity: Sheila 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6352,Boarding House - First Floor,Friendsanity: Sheila 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6353,Boarding House - First Floor,Friendsanity: Sheila 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6354,Boarding House - First Floor,Friendsanity: Sheila 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6355,Boarding House - First Floor,Friendsanity: Sheila 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6356,Boarding House - First Floor,Friendsanity: Sheila 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6357,Boarding House - First Floor,Friendsanity: Sheila 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6358,Boarding House - First Floor,Friendsanity: Sheila 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6359,Boarding House - First Floor,Friendsanity: Sheila 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6360,Boarding House - First Floor,Friendsanity: Sheila 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6361,The Lost Valley,Friendsanity: Gregory 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6362,The Lost Valley,Friendsanity: Gregory 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6363,The Lost Valley,Friendsanity: Gregory 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6364,The Lost Valley,Friendsanity: Gregory 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6365,The Lost Valley,Friendsanity: Gregory 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6366,The Lost Valley,Friendsanity: Gregory 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6367,The Lost Valley,Friendsanity: Gregory 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6368,The Lost Valley,Friendsanity: Gregory 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6369,The Lost Valley,Friendsanity: Gregory 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6370,The Lost Valley,Friendsanity: Gregory 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6371,The Lost Valley,Friendsanity: Gregory 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6372,The Lost Valley,Friendsanity: Gregory 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6373,The Lost Valley,Friendsanity: Gregory 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -6374,The Lost Valley,Friendsanity: Gregory 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension -7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack -7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod -7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods -7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods -7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods -7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods -7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods -7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods -7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods -7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods -7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods -7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods -7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods -7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods -7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods -7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods -7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods -7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods -7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods -7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator -7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator -7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator -7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator -7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator -7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator -7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator -7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator -7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods -7051,Abandoned Mines - 1A,Abandoned Treasure - Floor 1A,MANDATORY,Boarding House and Bus Stop Extension -7052,Abandoned Mines - 1B,Abandoned Treasure - Floor 1B,MANDATORY,Boarding House and Bus Stop Extension -7053,Abandoned Mines - 2A,Abandoned Treasure - Floor 2A,MANDATORY,Boarding House and Bus Stop Extension -7054,Abandoned Mines - 2B,Abandoned Treasure - Floor 2B,MANDATORY,Boarding House and Bus Stop Extension -7055,Abandoned Mines - 3,Abandoned Treasure - Floor 3,MANDATORY,Boarding House and Bus Stop Extension -7056,Abandoned Mines - 4,Abandoned Treasure - Floor 4,MANDATORY,Boarding House and Bus Stop Extension -7057,Abandoned Mines - 5,Abandoned Treasure - Floor 5,MANDATORY,Boarding House and Bus Stop Extension -7401,Farm,Cook Magic Elixir,COOKSANITY,Magic -7402,Farm,Craft Travel Core,CRAFTSANITY,Magic -7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded -7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded -7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded -7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -7407,Farm,Craft Glass Path,CRAFTSANITY,Archaeology -7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology -7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology -7410,Farm,Craft Bone Path,CRAFTSANITY,Archaeology -7411,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology -7412,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology -7413,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology -7414,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology -7415,Farm,Craft Grinder,CRAFTSANITY,Archaeology -7416,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology -7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology -7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology -7419,Farm,Craft Neanderthal Skeleton,CRAFTSANITY,Boarding House and Bus Stop Extension -7420,Farm,Craft Pterodactyl Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension -7421,Farm,Craft Pterodactyl Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension -7422,Farm,Craft Pterodactyl Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension -7423,Farm,Craft T-Rex Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension -7424,Farm,Craft T-Rex Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension -7425,Farm,Craft T-Rex Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension -7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic -7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic -7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded -7501,Mountain,Missing Envelope,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) -7502,Forest,Lost Emerald Ring,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) -7503,Forest,Mr.Ginger's request,"STORY_QUEST",Mister Ginger (cat npc) -7504,Forest,Juna's Drink Request,"STORY_QUEST",Juna - Roommate NPC -7505,Forest,Juna's BFF Request,"STORY_QUEST",Juna - Roommate NPC -7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC -7507,Adventurer's Guild,Marlon's Boat,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded -7508,Railroad,The Railroad Boulder,"STORY_QUEST",Stardew Valley Expanded -7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded -7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded -7511,Lance's House Main,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded -7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded -7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded -7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7520,Witch's Swamp,A New Pot,STORY_QUEST,Distant Lands - Witch Swamp Overhaul -7521,Witch's Swamp,Fancy Blanket Task,STORY_QUEST,Distant Lands - Witch Swamp Overhaul -7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul -7523,Boarding House - First Floor,Pumpkin Soup,STORY_QUEST,Boarding House and Bus Stop Extension -7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas -7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas -7526,Mouse House,Hats for the Hat Mouse,STORY_QUEST,Hat Mouse Lacey -7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded -7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded -7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded -7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded -7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded -7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded -7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded -7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded -7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded -7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded -7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul -7565,Kitchen,Cook Special Pumpkin Soup,COOKSANITY,Boarding House and Bus Stop Extension -7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded -7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded -7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul -7616,Mines Dwarf Shop,Neanderthal Skeleton Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7617,Mines Dwarf Shop,Pterodactyl Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7618,Mines Dwarf Shop,Pterodactyl Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7619,Mines Dwarf Shop,Pterodactyl Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7620,Mines Dwarf Shop,T-Rex Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7621,Mines Dwarf Shop,T-Rex Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7622,Mines Dwarf Shop,T-Rex Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension -7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded -7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded -7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded -7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded -7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded -7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded -7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7706,Highlands Outside,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded -7708,Highlands Outside,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded -7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded -7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded -7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded -7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded -7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded -7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded -7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded -7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded -7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded -7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded -7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded -7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded -7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded -7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7731,Witch's Swamp,Fishsanity: Purple Algae,FISHSANITY,Distant Lands - Witch Swamp Overhaul -7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded -7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded -7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded -7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul -7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul -8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic -8002,Shipping,Shipsanity: Travel Core,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Magic -8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded -8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded -8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded -8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded -8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded -8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded -8013,Shipping,Shipsanity: Big Conch,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded -8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8021,Shipping,Shipsanity: Dried Sand Dollar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded -8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded -8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY",Stardew Valley Expanded -8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded -8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded -8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded -8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded -8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded -8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded -8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded -8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded -8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded -8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded -8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded -8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded -8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded -8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded -8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded -8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded -8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded -8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded -8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded -8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology -8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology -8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology -8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology -8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology -8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology -8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology -8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology -8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology -8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology -8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology -8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology -8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology -8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology -8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology -8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology -8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology -8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology -8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology -8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology -8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology -8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology -8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology -8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology -8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology -8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology -8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology -8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology -8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology -8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology -8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology -8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology -8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology -8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology -8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology -8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology -8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology -8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology -8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology -8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology -8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology -8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology -8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology -8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology -8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology -8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology -8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology -8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology -8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology -8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology -8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology -8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology -8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology -8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology -8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology -8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology -8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology -8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology -8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology -8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology -8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology -8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology -8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology -8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology -8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology -8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology -8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology -8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology -8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology -8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology -8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology -8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology -8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology -8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology -8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology -8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology -8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology -8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology -8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology -8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology -8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology -8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology -8194,Shipping,Shipsanity: Wooden Display: Trilobite Fossil,SHIPSANITY,Archaeology -8195,Shipping,Shipsanity: Hardwood Display: Trilobite Fossil,SHIPSANITY,Archaeology -8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology -8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology -8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology -8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology -8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology -8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology -8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology -8203,Shipping,Shipsanity: Brown Amanita,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul -8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul -8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul -8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul -8218,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension -8219,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension -8220,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension -8221,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension -8222,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8223,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension -8224,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension -8225,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8226,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension -8227,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8228,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension -8229,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension -8230,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension -8231,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension -8232,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension -8233,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8234,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension -8235,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension -8236,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension -8237,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +id,region,name,tags,mod_name +1,Crafts Room,Spring Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +2,Crafts Room,Summer Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +3,Crafts Room,Fall Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +4,Crafts Room,Winter Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +5,Crafts Room,Construction Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +6,Crafts Room,Exotic Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +7,Pantry,Spring Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +8,Pantry,Summer Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +9,Pantry,Fall Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +10,Pantry,Quality Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +11,Pantry,Animal Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +12,Pantry,Artisan Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +13,Fish Tank,River Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +14,Fish Tank,Lake Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +15,Fish Tank,Ocean Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +16,Fish Tank,Night Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +17,Fish Tank,Crab Pot Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +18,Fish Tank,Specialty Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +19,Boiler Room,Blacksmith's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +20,Boiler Room,Geologist's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +21,Boiler Room,Adventurer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +22,Bulletin Board,Chef's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +23,Bulletin Board,Dye Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +24,Bulletin Board,Field Research Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +25,Bulletin Board,Fodder Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +26,Bulletin Board,Enchanter's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +27,Vault,"2,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +28,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +29,Vault,"10,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +30,Vault,"25,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +31,Abandoned JojaMart,The Missing Bundle,"BUNDLE,MANDATORY", +32,Crafts Room,Complete Crafts Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +33,Pantry,Complete Pantry,"COMMUNITY_CENTER_ROOM,MANDATORY", +34,Fish Tank,Complete Fish Tank,"COMMUNITY_CENTER_ROOM,MANDATORY", +35,Boiler Room,Complete Boiler Room,"COMMUNITY_CENTER_ROOM,MANDATORY", +36,Bulletin Board,Complete Bulletin Board,"COMMUNITY_CENTER_ROOM,MANDATORY", +37,Vault,Complete Vault,"COMMUNITY_CENTER_ROOM,MANDATORY", +39,Fish Tank,Deep Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +40,Crafts Room,Beach Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +41,Crafts Room,Mines Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +42,Crafts Room,Desert Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +43,Crafts Room,Island Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +44,Crafts Room,Sticky Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +45,Crafts Room,Wild Medicine Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +46,Crafts Room,Quality Foraging Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,CRAFTS_ROOM_BUNDLE", +47,Boiler Room,Paleontologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", +48,Boiler Room,Archaeologist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,BOILER_ROOM_BUNDLE", +49,Pantry,Slime Farmer Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +50,Pantry,Rare Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +51,Pantry,Fish Farmer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +52,Pantry,Garden Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +53,Pantry,Brewer's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +54,Pantry,Orchard Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +55,Pantry,Island Crops Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,PANTRY_BUNDLE", +56,Pantry,Agronomist's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +57,Fish Tank,Tackle Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +58,Fish Tank,Trash Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +59,Fish Tank,Spring Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +60,Fish Tank,Summer Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +61,Fish Tank,Fall Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +62,Fish Tank,Winter Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +63,Fish Tank,Rain Fishing Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +64,Fish Tank,Quality Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +65,Fish Tank,Master Fisher's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +66,Fish Tank,Legendary Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +67,Fish Tank,Island Fish Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +68,Fish Tank,Master Baiter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,FISH_TANK_BUNDLE", +69,Boiler Room,Recycling Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +70,Boiler Room,Treasure Hunter's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +71,Boiler Room,Engineer's Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +72,Boiler Room,Demolition Bundle,"BOILER_ROOM_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +73,Bulletin Board,Children's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +74,Bulletin Board,Forager's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +75,Bulletin Board,Home Cook's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +76,Bulletin Board,Bartender's Bundle,"BULLETIN_BOARD_BUNDLE,BUNDLE,COMMUNITY_CENTER_BUNDLE", +77,Vault,250g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +78,Vault,500g Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +79,Vault,"1,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +80,Vault,"2,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +81,Vault,"5,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +82,Vault,"1,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +83,Vault,"3,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +84,Vault,"3,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +85,Vault,"4,500g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +86,Vault,"6,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +87,Vault,"7,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +88,Vault,"9,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +89,Vault,"14,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +90,Vault,"15,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +91,Vault,"18,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +92,Vault,"20,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +93,Vault,"35,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +94,Vault,"40,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +95,Vault,"45,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +96,Vault,"100,000g Bundle","BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +97,Vault,Gambler's Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +98,Vault,Carnival Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +99,Vault,Walnut Hunter Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +100,Vault,Qi's Helper Bundle,"BUNDLE,COMMUNITY_CENTER_BUNDLE,VAULT_BUNDLE", +101,Pierre's General Store,Large Pack,BACKPACK, +102,Pierre's General Store,Deluxe Pack,BACKPACK, +103,Blacksmith Copper Upgrades,Copper Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +104,Blacksmith Iron Upgrades,Iron Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +105,Blacksmith Gold Upgrades,Gold Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +106,Blacksmith Iridium Upgrades,Iridium Hoe Upgrade,"HOE_UPGRADE,TOOL_UPGRADE", +107,Blacksmith Copper Upgrades,Copper Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +108,Blacksmith Iron Upgrades,Iron Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +109,Blacksmith Gold Upgrades,Gold Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +110,Blacksmith Iridium Upgrades,Iridium Pickaxe Upgrade,"PICKAXE_UPGRADE,TOOL_UPGRADE", +111,Blacksmith Copper Upgrades,Copper Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +112,Blacksmith Iron Upgrades,Iron Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +113,Blacksmith Gold Upgrades,Gold Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +114,Blacksmith Iridium Upgrades,Iridium Axe Upgrade,"AXE_UPGRADE,TOOL_UPGRADE", +115,Blacksmith Copper Upgrades,Copper Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +116,Blacksmith Iron Upgrades,Iron Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +117,Blacksmith Gold Upgrades,Gold Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +118,Blacksmith Iridium Upgrades,Iridium Watering Can Upgrade,"TOOL_UPGRADE,WATERING_CAN_UPGRADE", +119,Blacksmith Copper Upgrades,Copper Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +120,Blacksmith Iron Upgrades,Iron Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +121,Blacksmith Gold Upgrades,Gold Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +122,Blacksmith Iridium Upgrades,Iridium Trash Can Upgrade,"TOOL_UPGRADE,TRASH_CAN_UPGRADE", +123,Willy's Fish Shop,Purchase Training Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +124,Beach,Bamboo Pole Cutscene,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +125,Willy's Fish Shop,Purchase Fiberglass Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +126,Willy's Fish Shop,Purchase Iridium Rod,"FISHING_ROD_UPGRADE,TOOL_UPGRADE", +201,The Mines - Floor 10,The Mines Floor 10 Treasure,"MANDATORY,THE_MINES_TREASURE", +202,The Mines - Floor 20,The Mines Floor 20 Treasure,"MANDATORY,THE_MINES_TREASURE", +203,The Mines - Floor 40,The Mines Floor 40 Treasure,"MANDATORY,THE_MINES_TREASURE", +204,The Mines - Floor 50,The Mines Floor 50 Treasure,"MANDATORY,THE_MINES_TREASURE", +205,The Mines - Floor 60,The Mines Floor 60 Treasure,"MANDATORY,THE_MINES_TREASURE", +206,The Mines - Floor 70,The Mines Floor 70 Treasure,"MANDATORY,THE_MINES_TREASURE", +207,The Mines - Floor 80,The Mines Floor 80 Treasure,"MANDATORY,THE_MINES_TREASURE", +208,The Mines - Floor 90,The Mines Floor 90 Treasure,"MANDATORY,THE_MINES_TREASURE", +209,The Mines - Floor 100,The Mines Floor 100 Treasure,"MANDATORY,THE_MINES_TREASURE", +210,The Mines - Floor 110,The Mines Floor 110 Treasure,"MANDATORY,THE_MINES_TREASURE", +211,The Mines - Floor 120,The Mines Floor 120 Treasure,"MANDATORY,THE_MINES_TREASURE", +212,Quarry Mine,Grim Reaper statue,MANDATORY, +213,The Mines,The Mines Entrance Cutscene,MANDATORY, +214,The Mines - Floor 5,Floor 5 Elevator,ELEVATOR, +215,The Mines - Floor 10,Floor 10 Elevator,ELEVATOR, +216,The Mines - Floor 15,Floor 15 Elevator,ELEVATOR, +217,The Mines - Floor 20,Floor 20 Elevator,ELEVATOR, +218,The Mines - Floor 25,Floor 25 Elevator,ELEVATOR, +219,The Mines - Floor 30,Floor 30 Elevator,ELEVATOR, +220,The Mines - Floor 35,Floor 35 Elevator,ELEVATOR, +221,The Mines - Floor 40,Floor 40 Elevator,ELEVATOR, +222,The Mines - Floor 45,Floor 45 Elevator,ELEVATOR, +223,The Mines - Floor 50,Floor 50 Elevator,ELEVATOR, +224,The Mines - Floor 55,Floor 55 Elevator,ELEVATOR, +225,The Mines - Floor 60,Floor 60 Elevator,ELEVATOR, +226,The Mines - Floor 65,Floor 65 Elevator,ELEVATOR, +227,The Mines - Floor 70,Floor 70 Elevator,ELEVATOR, +228,The Mines - Floor 75,Floor 75 Elevator,ELEVATOR, +229,The Mines - Floor 80,Floor 80 Elevator,ELEVATOR, +230,The Mines - Floor 85,Floor 85 Elevator,ELEVATOR, +231,The Mines - Floor 90,Floor 90 Elevator,ELEVATOR, +232,The Mines - Floor 95,Floor 95 Elevator,ELEVATOR, +233,The Mines - Floor 100,Floor 100 Elevator,ELEVATOR, +234,The Mines - Floor 105,Floor 105 Elevator,ELEVATOR, +235,The Mines - Floor 110,Floor 110 Elevator,ELEVATOR, +236,The Mines - Floor 115,Floor 115 Elevator,ELEVATOR, +237,The Mines - Floor 120,Floor 120 Elevator,ELEVATOR, +250,Shipping,Demetrius's Breakthrough,MANDATORY +251,Volcano - Floor 10,Volcano Caldera Treasure,"GINGER_ISLAND,MANDATORY", +301,Farming,Level 1 Farming,"FARMING_LEVEL,SKILL_LEVEL", +302,Farming,Level 2 Farming,"FARMING_LEVEL,SKILL_LEVEL", +303,Farming,Level 3 Farming,"FARMING_LEVEL,SKILL_LEVEL", +304,Farming,Level 4 Farming,"FARMING_LEVEL,SKILL_LEVEL", +305,Farming,Level 5 Farming,"FARMING_LEVEL,SKILL_LEVEL", +306,Farming,Level 6 Farming,"FARMING_LEVEL,SKILL_LEVEL", +307,Farming,Level 7 Farming,"FARMING_LEVEL,SKILL_LEVEL", +308,Farming,Level 8 Farming,"FARMING_LEVEL,SKILL_LEVEL", +309,Farming,Level 9 Farming,"FARMING_LEVEL,SKILL_LEVEL", +310,Farming,Level 10 Farming,"FARMING_LEVEL,SKILL_LEVEL", +311,Fishing,Level 1 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +312,Fishing,Level 2 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +313,Fishing,Level 3 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +314,Fishing,Level 4 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +315,Fishing,Level 5 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +316,Fishing,Level 6 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +317,Fishing,Level 7 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +318,Fishing,Level 8 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +319,Fishing,Level 9 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +320,Fishing,Level 10 Fishing,"FISHING_LEVEL,SKILL_LEVEL", +321,Forest,Level 1 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +322,Forest,Level 2 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +323,Forest,Level 3 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +324,Forest,Level 4 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +325,Forest,Level 5 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +326,Secret Woods,Level 6 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +327,Secret Woods,Level 7 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +328,Secret Woods,Level 8 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +329,Secret Woods,Level 9 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +330,Secret Woods,Level 10 Foraging,"FORAGING_LEVEL,SKILL_LEVEL", +331,The Mines - Floor 20,Level 1 Mining,"MINING_LEVEL,SKILL_LEVEL", +332,The Mines - Floor 30,Level 2 Mining,"MINING_LEVEL,SKILL_LEVEL", +333,The Mines - Floor 40,Level 3 Mining,"MINING_LEVEL,SKILL_LEVEL", +334,The Mines - Floor 50,Level 4 Mining,"MINING_LEVEL,SKILL_LEVEL", +335,The Mines - Floor 60,Level 5 Mining,"MINING_LEVEL,SKILL_LEVEL", +336,The Mines - Floor 70,Level 6 Mining,"MINING_LEVEL,SKILL_LEVEL", +337,The Mines - Floor 80,Level 7 Mining,"MINING_LEVEL,SKILL_LEVEL", +338,The Mines - Floor 90,Level 8 Mining,"MINING_LEVEL,SKILL_LEVEL", +339,The Mines - Floor 100,Level 9 Mining,"MINING_LEVEL,SKILL_LEVEL", +340,The Mines - Floor 110,Level 10 Mining,"MINING_LEVEL,SKILL_LEVEL", +341,The Mines - Floor 20,Level 1 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +342,The Mines - Floor 30,Level 2 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +343,The Mines - Floor 40,Level 3 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +344,The Mines - Floor 50,Level 4 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +345,The Mines - Floor 60,Level 5 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +346,The Mines - Floor 70,Level 6 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +347,The Mines - Floor 80,Level 7 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +348,The Mines - Floor 90,Level 8 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +349,The Mines - Floor 100,Level 9 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +350,The Mines - Floor 110,Level 10 Combat,"COMBAT_LEVEL,SKILL_LEVEL", +401,Carpenter Shop,Coop Blueprint,BUILDING_BLUEPRINT, +402,Carpenter Shop,Big Coop Blueprint,BUILDING_BLUEPRINT, +403,Carpenter Shop,Deluxe Coop Blueprint,BUILDING_BLUEPRINT, +404,Carpenter Shop,Barn Blueprint,BUILDING_BLUEPRINT, +405,Carpenter Shop,Big Barn Blueprint,BUILDING_BLUEPRINT, +406,Carpenter Shop,Deluxe Barn Blueprint,BUILDING_BLUEPRINT, +407,Carpenter Shop,Well Blueprint,BUILDING_BLUEPRINT, +408,Carpenter Shop,Silo Blueprint,BUILDING_BLUEPRINT, +409,Carpenter Shop,Mill Blueprint,BUILDING_BLUEPRINT, +410,Carpenter Shop,Shed Blueprint,BUILDING_BLUEPRINT, +411,Carpenter Shop,Big Shed Blueprint,BUILDING_BLUEPRINT, +412,Carpenter Shop,Fish Pond Blueprint,BUILDING_BLUEPRINT, +413,Carpenter Shop,Stable Blueprint,BUILDING_BLUEPRINT, +414,Carpenter Shop,Slime Hutch Blueprint,BUILDING_BLUEPRINT, +415,Carpenter Shop,Shipping Bin Blueprint,BUILDING_BLUEPRINT, +416,Carpenter Shop,Kitchen Blueprint,BUILDING_BLUEPRINT, +417,Carpenter Shop,Kids Room Blueprint,BUILDING_BLUEPRINT, +418,Carpenter Shop,Cellar Blueprint,BUILDING_BLUEPRINT, +501,Town,Introductions,"STORY_QUEST", +502,Town,How To Win Friends,"STORY_QUEST", +503,Farm,Getting Started,"STORY_QUEST", +504,Farm,Raising Animals,"STORY_QUEST", +505,Farm,Advancement,"STORY_QUEST", +506,Museum,Archaeology,"STORY_QUEST", +507,Wizard Tower,Meet The Wizard,"STORY_QUEST", +508,The Mines - Floor 5,Forging Ahead,"STORY_QUEST", +509,The Mines - Floor 10,Smelting,"STORY_QUEST", +510,The Mines - Floor 15,Initiation,"STORY_QUEST", +511,Mountain,Robin's Lost Axe,"STORY_QUEST", +512,Town,Jodi's Request,"STORY_QUEST", +513,Town,"Mayor's ""Shorts""","STORY_QUEST", +514,Mountain,Blackberry Basket,"STORY_QUEST", +515,Marnie's Ranch,Marnie's Request,"STORY_QUEST", +516,Town,Pam Is Thirsty,"STORY_QUEST", +517,Wizard Tower,A Dark Reagent,"STORY_QUEST", +518,Forest,Cow's Delight,"STORY_QUEST", +519,Skull Cavern Entrance,The Skull Key,"STORY_QUEST", +520,Mountain,Crop Research,"STORY_QUEST", +521,Alex's House,Knee Therapy,"STORY_QUEST", +522,Mountain,Robin's Request,"STORY_QUEST", +523,Skull Cavern Floor 25,Qi's Challenge,"STORY_QUEST", +524,Desert,The Mysterious Qi,"STORY_QUEST", +525,Town,Carving Pumpkins,"STORY_QUEST", +526,Town,A Winter Mystery,"STORY_QUEST", +527,Secret Woods,Strange Note,"STORY_QUEST", +528,Skull Cavern Floor 100,Cryptic Note,"STORY_QUEST", +529,Town,Fresh Fruit,"STORY_QUEST", +530,Mountain,Aquatic Research,"STORY_QUEST", +531,Town,A Soldier's Star,"STORY_QUEST", +532,Town,Mayor's Need,"STORY_QUEST", +533,Saloon,Wanted: Lobster,"STORY_QUEST", +534,Town,Pam Needs Juice,"STORY_QUEST", +535,Sam's House,Fish Casserole,"STORY_QUEST", +536,Beach,Catch A Squid,"STORY_QUEST", +537,Saloon,Fish Stew,"STORY_QUEST", +538,Pierre's General Store,Pierre's Notice,"STORY_QUEST", +539,Clint's Blacksmith,Clint's Attempt,"STORY_QUEST", +540,Town,A Favor For Clint,"STORY_QUEST", +541,Wizard Tower,Staff Of Power,"STORY_QUEST", +542,Town,Granny's Gift,"STORY_QUEST", +543,Desert,Exotic Spirits,"STORY_QUEST", +544,Fishing,Catch a Lingcod,"STORY_QUEST", +545,Island West,The Pirate's Wife,"GINGER_ISLAND,STORY_QUEST", +546,Mutant Bug Lair,Dark Talisman,"STORY_QUEST", +547,Witch's Swamp,Goblin Problem,"STORY_QUEST", +548,Witch's Hut,Magic Ink,"STORY_QUEST", +601,JotPK World 1,JotPK: Boots 1,"ARCADE_MACHINE,JOTPK", +602,JotPK World 1,JotPK: Boots 2,"ARCADE_MACHINE,JOTPK", +603,JotPK World 1,JotPK: Gun 1,"ARCADE_MACHINE,JOTPK", +604,JotPK World 2,JotPK: Gun 2,"ARCADE_MACHINE,JOTPK", +605,JotPK World 2,JotPK: Gun 3,"ARCADE_MACHINE,JOTPK", +606,JotPK World 3,JotPK: Super Gun,"ARCADE_MACHINE,JOTPK", +607,JotPK World 1,JotPK: Ammo 1,"ARCADE_MACHINE,JOTPK", +608,JotPK World 2,JotPK: Ammo 2,"ARCADE_MACHINE,JOTPK", +609,JotPK World 3,JotPK: Ammo 3,"ARCADE_MACHINE,JOTPK", +610,JotPK World 1,JotPK: Cowboy 1,"ARCADE_MACHINE,JOTPK", +611,JotPK World 2,JotPK: Cowboy 2,"ARCADE_MACHINE,JOTPK", +612,Junimo Kart 1,Junimo Kart: Crumble Cavern,"ARCADE_MACHINE,JUNIMO_KART", +613,Junimo Kart 1,Junimo Kart: Slippery Slopes,"ARCADE_MACHINE,JUNIMO_KART", +614,Junimo Kart 2,Junimo Kart: Secret Level,"ARCADE_MACHINE,JUNIMO_KART", +615,Junimo Kart 2,Junimo Kart: The Gem Sea Giant,"ARCADE_MACHINE,JUNIMO_KART", +616,Junimo Kart 2,Junimo Kart: Slomp's Stomp,"ARCADE_MACHINE,JUNIMO_KART", +617,Junimo Kart 2,Junimo Kart: Ghastly Galleon,"ARCADE_MACHINE,JUNIMO_KART", +618,Junimo Kart 3,Junimo Kart: Glowshroom Grotto,"ARCADE_MACHINE,JUNIMO_KART", +619,Junimo Kart 3,Junimo Kart: Red Hot Rollercoaster,"ARCADE_MACHINE,JUNIMO_KART", +620,JotPK World 3,Journey of the Prairie King Victory,"ARCADE_MACHINE_VICTORY,JOTPK", +621,Junimo Kart 3,Junimo Kart: Sunset Speedway (Victory),"ARCADE_MACHINE_VICTORY,JUNIMO_KART", +701,Secret Woods,Old Master Cannoli,MANDATORY, +702,Beach,Beach Bridge Repair,MANDATORY, +703,Desert,Galaxy Sword Shrine,MANDATORY, +704,Farmhouse,Have a Baby,BABY, +705,Farmhouse,Have Another Baby,BABY, +706,Farmhouse,Spouse Stardrop,, +707,Sewer,Krobus Stardrop,MANDATORY, +801,Forest,Help Wanted: Gathering 1,HELP_WANTED, +802,Forest,Help Wanted: Gathering 2,HELP_WANTED, +803,Forest,Help Wanted: Gathering 3,HELP_WANTED, +804,Forest,Help Wanted: Gathering 4,HELP_WANTED, +805,Forest,Help Wanted: Gathering 5,HELP_WANTED, +806,Forest,Help Wanted: Gathering 6,HELP_WANTED, +807,Forest,Help Wanted: Gathering 7,HELP_WANTED, +808,Forest,Help Wanted: Gathering 8,HELP_WANTED, +811,The Mines - Floor 5,Help Wanted: Slay Monsters 1,HELP_WANTED, +812,The Mines - Floor 15,Help Wanted: Slay Monsters 2,HELP_WANTED, +813,The Mines - Floor 25,Help Wanted: Slay Monsters 3,HELP_WANTED, +814,The Mines - Floor 35,Help Wanted: Slay Monsters 4,HELP_WANTED, +815,The Mines - Floor 45,Help Wanted: Slay Monsters 5,HELP_WANTED, +816,The Mines - Floor 55,Help Wanted: Slay Monsters 6,HELP_WANTED, +817,The Mines - Floor 65,Help Wanted: Slay Monsters 7,HELP_WANTED, +818,The Mines - Floor 75,Help Wanted: Slay Monsters 8,HELP_WANTED, +821,Fishing,Help Wanted: Fishing 1,HELP_WANTED, +822,Fishing,Help Wanted: Fishing 2,HELP_WANTED, +823,Fishing,Help Wanted: Fishing 3,HELP_WANTED, +824,Fishing,Help Wanted: Fishing 4,HELP_WANTED, +825,Fishing,Help Wanted: Fishing 5,HELP_WANTED, +826,Fishing,Help Wanted: Fishing 6,HELP_WANTED, +827,Fishing,Help Wanted: Fishing 7,HELP_WANTED, +828,Fishing,Help Wanted: Fishing 8,HELP_WANTED, +841,Town,Help Wanted: Item Delivery 1,HELP_WANTED, +842,Town,Help Wanted: Item Delivery 2,HELP_WANTED, +843,Town,Help Wanted: Item Delivery 3,HELP_WANTED, +844,Town,Help Wanted: Item Delivery 4,HELP_WANTED, +845,Town,Help Wanted: Item Delivery 5,HELP_WANTED, +846,Town,Help Wanted: Item Delivery 6,HELP_WANTED, +847,Town,Help Wanted: Item Delivery 7,HELP_WANTED, +848,Town,Help Wanted: Item Delivery 8,HELP_WANTED, +849,Town,Help Wanted: Item Delivery 9,HELP_WANTED, +850,Town,Help Wanted: Item Delivery 10,HELP_WANTED, +851,Town,Help Wanted: Item Delivery 11,HELP_WANTED, +852,Town,Help Wanted: Item Delivery 12,HELP_WANTED, +853,Town,Help Wanted: Item Delivery 13,HELP_WANTED, +854,Town,Help Wanted: Item Delivery 14,HELP_WANTED, +855,Town,Help Wanted: Item Delivery 15,HELP_WANTED, +856,Town,Help Wanted: Item Delivery 16,HELP_WANTED, +857,Town,Help Wanted: Item Delivery 17,HELP_WANTED, +858,Town,Help Wanted: Item Delivery 18,HELP_WANTED, +859,Town,Help Wanted: Item Delivery 19,HELP_WANTED, +860,Town,Help Wanted: Item Delivery 20,HELP_WANTED, +861,Town,Help Wanted: Item Delivery 21,HELP_WANTED, +862,Town,Help Wanted: Item Delivery 22,HELP_WANTED, +863,Town,Help Wanted: Item Delivery 23,HELP_WANTED, +864,Town,Help Wanted: Item Delivery 24,HELP_WANTED, +865,Town,Help Wanted: Item Delivery 25,HELP_WANTED, +866,Town,Help Wanted: Item Delivery 26,HELP_WANTED, +867,Town,Help Wanted: Item Delivery 27,HELP_WANTED, +868,Town,Help Wanted: Item Delivery 28,HELP_WANTED, +869,Town,Help Wanted: Item Delivery 29,HELP_WANTED, +870,Town,Help Wanted: Item Delivery 30,HELP_WANTED, +871,Town,Help Wanted: Item Delivery 31,HELP_WANTED, +872,Town,Help Wanted: Item Delivery 32,HELP_WANTED, +901,Traveling Cart Sunday,Traveling Merchant Sunday Item 1,"MANDATORY,TRAVELING_MERCHANT", +902,Traveling Cart Sunday,Traveling Merchant Sunday Item 2,"MANDATORY,TRAVELING_MERCHANT", +903,Traveling Cart Sunday,Traveling Merchant Sunday Item 3,"MANDATORY,TRAVELING_MERCHANT", +911,Traveling Cart Monday,Traveling Merchant Monday Item 1,"MANDATORY,TRAVELING_MERCHANT", +912,Traveling Cart Monday,Traveling Merchant Monday Item 2,"MANDATORY,TRAVELING_MERCHANT", +913,Traveling Cart Monday,Traveling Merchant Monday Item 3,"MANDATORY,TRAVELING_MERCHANT", +921,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +922,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +923,Traveling Cart Tuesday,Traveling Merchant Tuesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +931,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 1,"MANDATORY,TRAVELING_MERCHANT", +932,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 2,"MANDATORY,TRAVELING_MERCHANT", +933,Traveling Cart Wednesday,Traveling Merchant Wednesday Item 3,"MANDATORY,TRAVELING_MERCHANT", +941,Traveling Cart Thursday,Traveling Merchant Thursday Item 1,"MANDATORY,TRAVELING_MERCHANT", +942,Traveling Cart Thursday,Traveling Merchant Thursday Item 2,"MANDATORY,TRAVELING_MERCHANT", +943,Traveling Cart Thursday,Traveling Merchant Thursday Item 3,"MANDATORY,TRAVELING_MERCHANT", +951,Traveling Cart Friday,Traveling Merchant Friday Item 1,"MANDATORY,TRAVELING_MERCHANT", +952,Traveling Cart Friday,Traveling Merchant Friday Item 2,"MANDATORY,TRAVELING_MERCHANT", +953,Traveling Cart Friday,Traveling Merchant Friday Item 3,"MANDATORY,TRAVELING_MERCHANT", +961,Traveling Cart Saturday,Traveling Merchant Saturday Item 1,"MANDATORY,TRAVELING_MERCHANT", +962,Traveling Cart Saturday,Traveling Merchant Saturday Item 2,"MANDATORY,TRAVELING_MERCHANT", +963,Traveling Cart Saturday,Traveling Merchant Saturday Item 3,"MANDATORY,TRAVELING_MERCHANT", +1001,Fishing,Fishsanity: Carp,FISHSANITY, +1002,Fishing,Fishsanity: Herring,FISHSANITY, +1003,Fishing,Fishsanity: Smallmouth Bass,FISHSANITY, +1004,Fishing,Fishsanity: Anchovy,FISHSANITY, +1005,Fishing,Fishsanity: Sardine,FISHSANITY, +1006,Fishing,Fishsanity: Sunfish,FISHSANITY, +1007,Fishing,Fishsanity: Perch,FISHSANITY, +1008,Fishing,Fishsanity: Chub,FISHSANITY, +1009,Fishing,Fishsanity: Bream,FISHSANITY, +1010,Fishing,Fishsanity: Red Snapper,FISHSANITY, +1011,Fishing,Fishsanity: Sea Cucumber,FISHSANITY, +1012,Fishing,Fishsanity: Rainbow Trout,FISHSANITY, +1013,Fishing,Fishsanity: Walleye,FISHSANITY, +1014,Fishing,Fishsanity: Shad,FISHSANITY, +1015,Fishing,Fishsanity: Bullhead,FISHSANITY, +1016,Fishing,Fishsanity: Largemouth Bass,FISHSANITY, +1017,Fishing,Fishsanity: Salmon,FISHSANITY, +1018,Fishing,Fishsanity: Ghostfish,FISHSANITY, +1019,Fishing,Fishsanity: Tilapia,FISHSANITY, +1020,Fishing,Fishsanity: Woodskip,FISHSANITY, +1021,Fishing,Fishsanity: Flounder,FISHSANITY, +1022,Fishing,Fishsanity: Halibut,FISHSANITY, +1023,Fishing,Fishsanity: Lionfish,"FISHSANITY,GINGER_ISLAND", +1024,Fishing,Fishsanity: Slimejack,FISHSANITY, +1025,Fishing,Fishsanity: Midnight Carp,FISHSANITY, +1026,Fishing,Fishsanity: Red Mullet,FISHSANITY, +1027,Fishing,Fishsanity: Pike,FISHSANITY, +1028,Fishing,Fishsanity: Tiger Trout,FISHSANITY, +1029,Fishing,Fishsanity: Blue Discus,"FISHSANITY,GINGER_ISLAND", +1030,Fishing,Fishsanity: Albacore,FISHSANITY, +1031,Fishing,Fishsanity: Sandfish,FISHSANITY, +1032,Fishing,Fishsanity: Stonefish,FISHSANITY, +1033,Fishing,Fishsanity: Tuna,FISHSANITY, +1034,Fishing,Fishsanity: Eel,FISHSANITY, +1035,Fishing,Fishsanity: Catfish,FISHSANITY, +1036,Fishing,Fishsanity: Squid,FISHSANITY, +1037,Fishing,Fishsanity: Sturgeon,FISHSANITY, +1038,Fishing,Fishsanity: Dorado,FISHSANITY, +1039,Fishing,Fishsanity: Pufferfish,FISHSANITY, +1040,Fishing,Fishsanity: Void Salmon,FISHSANITY, +1041,Fishing,Fishsanity: Super Cucumber,FISHSANITY, +1042,Fishing,Fishsanity: Stingray,"FISHSANITY,GINGER_ISLAND", +1043,Fishing,Fishsanity: Ice Pip,FISHSANITY, +1044,Fishing,Fishsanity: Lingcod,FISHSANITY, +1045,Desert,Fishsanity: Scorpion Carp,FISHSANITY, +1046,Fishing,Fishsanity: Lava Eel,FISHSANITY, +1047,Fishing,Fishsanity: Octopus,FISHSANITY, +1048,Fishing,Fishsanity: Midnight Squid,FISHSANITY, +1049,Fishing,Fishsanity: Spook Fish,FISHSANITY, +1050,Fishing,Fishsanity: Blobfish,FISHSANITY, +1051,Fishing,Fishsanity: Crimsonfish,FISHSANITY, +1052,Fishing,Fishsanity: Angler,FISHSANITY, +1053,Fishing,Fishsanity: Legend,FISHSANITY, +1054,Fishing,Fishsanity: Glacierfish,FISHSANITY, +1055,Fishing,Fishsanity: Mutant Carp,FISHSANITY, +1056,Town,Fishsanity: Crayfish,FISHSANITY, +1057,Town,Fishsanity: Snail,FISHSANITY, +1058,Town,Fishsanity: Periwinkle,FISHSANITY, +1059,Beach,Fishsanity: Lobster,FISHSANITY, +1060,Beach,Fishsanity: Clam,FISHSANITY, +1061,Beach,Fishsanity: Crab,FISHSANITY, +1062,Beach,Fishsanity: Cockle,FISHSANITY, +1063,Beach,Fishsanity: Mussel,FISHSANITY, +1064,Beach,Fishsanity: Shrimp,FISHSANITY, +1065,Beach,Fishsanity: Oyster,FISHSANITY, +1066,Beach,Fishsanity: Son of Crimsonfish,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1067,Beach,Fishsanity: Glacierfish Jr.,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1068,Beach,Fishsanity: Legend II,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1069,Beach,Fishsanity: Ms. Angler,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1070,Beach,Fishsanity: Radioactive Carp,"FISHSANITY,GINGER_ISLAND,REQUIRES_QI_ORDERS", +1100,Museum,Museumsanity: 5 Donations,MUSEUM_MILESTONES, +1101,Museum,Museumsanity: 10 Donations,MUSEUM_MILESTONES, +1102,Museum,Museumsanity: 15 Donations,MUSEUM_MILESTONES, +1103,Museum,Museumsanity: 20 Donations,MUSEUM_MILESTONES, +1104,Museum,Museumsanity: 25 Donations,MUSEUM_MILESTONES, +1105,Museum,Museumsanity: 30 Donations,MUSEUM_MILESTONES, +1106,Museum,Museumsanity: 35 Donations,MUSEUM_MILESTONES, +1107,Museum,Museumsanity: 40 Donations,MUSEUM_MILESTONES, +1108,Museum,Museumsanity: 50 Donations,MUSEUM_MILESTONES, +1109,Museum,Museumsanity: 60 Donations,MUSEUM_MILESTONES, +1110,Museum,Museumsanity: 70 Donations,MUSEUM_MILESTONES, +1111,Museum,Museumsanity: 80 Donations,MUSEUM_MILESTONES, +1112,Museum,Museumsanity: 90 Donations,MUSEUM_MILESTONES, +1113,Museum,Museumsanity: 95 Donations,MUSEUM_MILESTONES, +1114,Museum,Museumsanity: 11 Minerals,MUSEUM_MILESTONES, +1115,Museum,Museumsanity: 21 Minerals,MUSEUM_MILESTONES, +1116,Museum,Museumsanity: 31 Minerals,MUSEUM_MILESTONES, +1117,Museum,Museumsanity: 41 Minerals,MUSEUM_MILESTONES, +1118,Museum,Museumsanity: 50 Minerals,MUSEUM_MILESTONES, +1119,Museum,Museumsanity: 3 Artifacts,MUSEUM_MILESTONES, +1120,Museum,Museumsanity: 6 Artifacts,MUSEUM_MILESTONES, +1121,Museum,Museumsanity: 9 Artifacts,MUSEUM_MILESTONES, +1122,Museum,Museumsanity: 11 Artifacts,MUSEUM_MILESTONES, +1123,Museum,Museumsanity: 15 Artifacts,MUSEUM_MILESTONES, +1124,Museum,Museumsanity: 20 Artifacts,MUSEUM_MILESTONES, +1125,Museum,Museumsanity: Dwarf Scrolls,MUSEUM_MILESTONES, +1126,Museum,Museumsanity: Skeleton Front,MUSEUM_MILESTONES, +1127,Museum,Museumsanity: Skeleton Middle,MUSEUM_MILESTONES, +1128,Museum,Museumsanity: Skeleton Back,MUSEUM_MILESTONES, +1201,Museum,Museumsanity: Dwarf Scroll I,MUSEUM_DONATIONS, +1202,Museum,Museumsanity: Dwarf Scroll II,MUSEUM_DONATIONS, +1203,Museum,Museumsanity: Dwarf Scroll III,MUSEUM_DONATIONS, +1204,Museum,Museumsanity: Dwarf Scroll IV,MUSEUM_DONATIONS, +1205,Museum,Museumsanity: Chipped Amphora,MUSEUM_DONATIONS, +1206,Museum,Museumsanity: Arrowhead,MUSEUM_DONATIONS, +1207,Museum,Museumsanity: Ancient Doll,MUSEUM_DONATIONS, +1208,Museum,Museumsanity: Elvish Jewelry,MUSEUM_DONATIONS, +1209,Museum,Museumsanity: Chewing Stick,MUSEUM_DONATIONS, +1210,Museum,Museumsanity: Ornamental Fan,MUSEUM_DONATIONS, +1211,Museum,Museumsanity: Dinosaur Egg,MUSEUM_DONATIONS, +1212,Museum,Museumsanity: Rare Disc,MUSEUM_DONATIONS, +1213,Museum,Museumsanity: Ancient Sword,MUSEUM_DONATIONS, +1214,Museum,Museumsanity: Rusty Spoon,MUSEUM_DONATIONS, +1215,Museum,Museumsanity: Rusty Spur,MUSEUM_DONATIONS, +1216,Museum,Museumsanity: Rusty Cog,MUSEUM_DONATIONS, +1217,Museum,Museumsanity: Chicken Statue,MUSEUM_DONATIONS, +1218,Museum,Museumsanity: Ancient Seed,"MUSEUM_DONATIONS,MUSEUM_MILESTONES", +1219,Museum,Museumsanity: Prehistoric Tool,MUSEUM_DONATIONS, +1220,Museum,Museumsanity: Dried Starfish,MUSEUM_DONATIONS, +1221,Museum,Museumsanity: Anchor,MUSEUM_DONATIONS, +1222,Museum,Museumsanity: Glass Shards,MUSEUM_DONATIONS, +1223,Museum,Museumsanity: Bone Flute,MUSEUM_DONATIONS, +1224,Museum,Museumsanity: Prehistoric Handaxe,MUSEUM_DONATIONS, +1225,Museum,Museumsanity: Dwarvish Helm,MUSEUM_DONATIONS, +1226,Museum,Museumsanity: Dwarf Gadget,MUSEUM_DONATIONS, +1227,Museum,Museumsanity: Ancient Drum,MUSEUM_DONATIONS, +1228,Museum,Museumsanity: Golden Mask,MUSEUM_DONATIONS, +1229,Museum,Museumsanity: Golden Relic,MUSEUM_DONATIONS, +1230,Museum,Museumsanity: Strange Doll (Green),MUSEUM_DONATIONS, +1231,Museum,Museumsanity: Strange Doll,MUSEUM_DONATIONS, +1232,Museum,Museumsanity: Prehistoric Scapula,MUSEUM_DONATIONS, +1233,Museum,Museumsanity: Prehistoric Tibia,MUSEUM_DONATIONS, +1234,Museum,Museumsanity: Prehistoric Skull,MUSEUM_DONATIONS, +1235,Museum,Museumsanity: Skeletal Hand,MUSEUM_DONATIONS, +1236,Museum,Museumsanity: Prehistoric Rib,MUSEUM_DONATIONS, +1237,Museum,Museumsanity: Prehistoric Vertebra,MUSEUM_DONATIONS, +1238,Museum,Museumsanity: Skeletal Tail,MUSEUM_DONATIONS, +1239,Museum,Museumsanity: Nautilus Fossil,MUSEUM_DONATIONS, +1240,Museum,Museumsanity: Amphibian Fossil,MUSEUM_DONATIONS, +1241,Museum,Museumsanity: Palm Fossil,MUSEUM_DONATIONS, +1242,Museum,Museumsanity: Trilobite,MUSEUM_DONATIONS, +1243,Museum,Museumsanity: Quartz,MUSEUM_DONATIONS, +1244,Museum,Museumsanity: Fire Quartz,MUSEUM_DONATIONS, +1245,Museum,Museumsanity: Frozen Tear,MUSEUM_DONATIONS, +1246,Museum,Museumsanity: Earth Crystal,MUSEUM_DONATIONS, +1247,Museum,Museumsanity: Emerald,MUSEUM_DONATIONS, +1248,Museum,Museumsanity: Aquamarine,MUSEUM_DONATIONS, +1249,Museum,Museumsanity: Ruby,MUSEUM_DONATIONS, +1250,Museum,Museumsanity: Amethyst,MUSEUM_DONATIONS, +1251,Museum,Museumsanity: Topaz,MUSEUM_DONATIONS, +1252,Museum,Museumsanity: Jade,MUSEUM_DONATIONS, +1253,Museum,Museumsanity: Diamond,MUSEUM_DONATIONS, +1254,Museum,Museumsanity: Prismatic Shard,MUSEUM_DONATIONS, +1255,Museum,Museumsanity: Alamite,MUSEUM_DONATIONS, +1256,Museum,Museumsanity: Bixite,MUSEUM_DONATIONS, +1257,Museum,Museumsanity: Baryte,MUSEUM_DONATIONS, +1258,Museum,Museumsanity: Aerinite,MUSEUM_DONATIONS, +1259,Museum,Museumsanity: Calcite,MUSEUM_DONATIONS, +1260,Museum,Museumsanity: Dolomite,MUSEUM_DONATIONS, +1261,Museum,Museumsanity: Esperite,MUSEUM_DONATIONS, +1262,Museum,Museumsanity: Fluorapatite,MUSEUM_DONATIONS, +1263,Museum,Museumsanity: Geminite,MUSEUM_DONATIONS, +1264,Museum,Museumsanity: Helvite,MUSEUM_DONATIONS, +1265,Museum,Museumsanity: Jamborite,MUSEUM_DONATIONS, +1266,Museum,Museumsanity: Jagoite,MUSEUM_DONATIONS, +1267,Museum,Museumsanity: Kyanite,MUSEUM_DONATIONS, +1268,Museum,Museumsanity: Lunarite,MUSEUM_DONATIONS, +1269,Museum,Museumsanity: Malachite,MUSEUM_DONATIONS, +1270,Museum,Museumsanity: Neptunite,MUSEUM_DONATIONS, +1271,Museum,Museumsanity: Lemon Stone,MUSEUM_DONATIONS, +1272,Museum,Museumsanity: Nekoite,MUSEUM_DONATIONS, +1273,Museum,Museumsanity: Orpiment,MUSEUM_DONATIONS, +1274,Museum,Museumsanity: Petrified Slime,MUSEUM_DONATIONS, +1275,Museum,Museumsanity: Thunder Egg,MUSEUM_DONATIONS, +1276,Museum,Museumsanity: Pyrite,MUSEUM_DONATIONS, +1277,Museum,Museumsanity: Ocean Stone,MUSEUM_DONATIONS, +1278,Museum,Museumsanity: Ghost Crystal,MUSEUM_DONATIONS, +1279,Museum,Museumsanity: Tigerseye,MUSEUM_DONATIONS, +1280,Museum,Museumsanity: Jasper,MUSEUM_DONATIONS, +1281,Museum,Museumsanity: Opal,MUSEUM_DONATIONS, +1282,Museum,Museumsanity: Fire Opal,MUSEUM_DONATIONS, +1283,Museum,Museumsanity: Celestine,MUSEUM_DONATIONS, +1284,Museum,Museumsanity: Marble,MUSEUM_DONATIONS, +1285,Museum,Museumsanity: Sandstone,MUSEUM_DONATIONS, +1286,Museum,Museumsanity: Granite,MUSEUM_DONATIONS, +1287,Museum,Museumsanity: Basalt,MUSEUM_DONATIONS, +1288,Museum,Museumsanity: Limestone,MUSEUM_DONATIONS, +1289,Museum,Museumsanity: Soapstone,MUSEUM_DONATIONS, +1290,Museum,Museumsanity: Hematite,MUSEUM_DONATIONS, +1291,Museum,Museumsanity: Mudstone,MUSEUM_DONATIONS, +1292,Museum,Museumsanity: Obsidian,MUSEUM_DONATIONS, +1293,Museum,Museumsanity: Slate,MUSEUM_DONATIONS, +1294,Museum,Museumsanity: Fairy Stone,MUSEUM_DONATIONS, +1295,Museum,Museumsanity: Star Shards,MUSEUM_DONATIONS, +1301,Alex's House,Friendsanity: Alex 1 <3,FRIENDSANITY, +1302,Alex's House,Friendsanity: Alex 2 <3,FRIENDSANITY, +1303,Alex's House,Friendsanity: Alex 3 <3,FRIENDSANITY, +1304,Alex's House,Friendsanity: Alex 4 <3,FRIENDSANITY, +1305,Alex's House,Friendsanity: Alex 5 <3,FRIENDSANITY, +1306,Alex's House,Friendsanity: Alex 6 <3,FRIENDSANITY, +1307,Alex's House,Friendsanity: Alex 7 <3,FRIENDSANITY, +1308,Alex's House,Friendsanity: Alex 8 <3,FRIENDSANITY, +1309,Alex's House,Friendsanity: Alex 9 <3,FRIENDSANITY, +1310,Alex's House,Friendsanity: Alex 10 <3,FRIENDSANITY, +1311,Alex's House,Friendsanity: Alex 11 <3,FRIENDSANITY, +1312,Alex's House,Friendsanity: Alex 12 <3,FRIENDSANITY, +1313,Alex's House,Friendsanity: Alex 13 <3,FRIENDSANITY, +1314,Alex's House,Friendsanity: Alex 14 <3,FRIENDSANITY, +1315,Elliott's House,Friendsanity: Elliott 1 <3,FRIENDSANITY, +1316,Elliott's House,Friendsanity: Elliott 2 <3,FRIENDSANITY, +1317,Elliott's House,Friendsanity: Elliott 3 <3,FRIENDSANITY, +1318,Elliott's House,Friendsanity: Elliott 4 <3,FRIENDSANITY, +1319,Elliott's House,Friendsanity: Elliott 5 <3,FRIENDSANITY, +1320,Elliott's House,Friendsanity: Elliott 6 <3,FRIENDSANITY, +1321,Elliott's House,Friendsanity: Elliott 7 <3,FRIENDSANITY, +1322,Elliott's House,Friendsanity: Elliott 8 <3,FRIENDSANITY, +1323,Elliott's House,Friendsanity: Elliott 9 <3,FRIENDSANITY, +1324,Elliott's House,Friendsanity: Elliott 10 <3,FRIENDSANITY, +1325,Elliott's House,Friendsanity: Elliott 11 <3,FRIENDSANITY, +1326,Elliott's House,Friendsanity: Elliott 12 <3,FRIENDSANITY, +1327,Elliott's House,Friendsanity: Elliott 13 <3,FRIENDSANITY, +1328,Elliott's House,Friendsanity: Elliott 14 <3,FRIENDSANITY, +1329,Hospital,Friendsanity: Harvey 1 <3,FRIENDSANITY, +1330,Hospital,Friendsanity: Harvey 2 <3,FRIENDSANITY, +1331,Hospital,Friendsanity: Harvey 3 <3,FRIENDSANITY, +1332,Hospital,Friendsanity: Harvey 4 <3,FRIENDSANITY, +1333,Hospital,Friendsanity: Harvey 5 <3,FRIENDSANITY, +1334,Hospital,Friendsanity: Harvey 6 <3,FRIENDSANITY, +1335,Hospital,Friendsanity: Harvey 7 <3,FRIENDSANITY, +1336,Hospital,Friendsanity: Harvey 8 <3,FRIENDSANITY, +1337,Hospital,Friendsanity: Harvey 9 <3,FRIENDSANITY, +1338,Hospital,Friendsanity: Harvey 10 <3,FRIENDSANITY, +1339,Hospital,Friendsanity: Harvey 11 <3,FRIENDSANITY, +1340,Hospital,Friendsanity: Harvey 12 <3,FRIENDSANITY, +1341,Hospital,Friendsanity: Harvey 13 <3,FRIENDSANITY, +1342,Hospital,Friendsanity: Harvey 14 <3,FRIENDSANITY, +1343,Sam's House,Friendsanity: Sam 1 <3,FRIENDSANITY, +1344,Sam's House,Friendsanity: Sam 2 <3,FRIENDSANITY, +1345,Sam's House,Friendsanity: Sam 3 <3,FRIENDSANITY, +1346,Sam's House,Friendsanity: Sam 4 <3,FRIENDSANITY, +1347,Sam's House,Friendsanity: Sam 5 <3,FRIENDSANITY, +1348,Sam's House,Friendsanity: Sam 6 <3,FRIENDSANITY, +1349,Sam's House,Friendsanity: Sam 7 <3,FRIENDSANITY, +1350,Sam's House,Friendsanity: Sam 8 <3,FRIENDSANITY, +1351,Sam's House,Friendsanity: Sam 9 <3,FRIENDSANITY, +1352,Sam's House,Friendsanity: Sam 10 <3,FRIENDSANITY, +1353,Sam's House,Friendsanity: Sam 11 <3,FRIENDSANITY, +1354,Sam's House,Friendsanity: Sam 12 <3,FRIENDSANITY, +1355,Sam's House,Friendsanity: Sam 13 <3,FRIENDSANITY, +1356,Sam's House,Friendsanity: Sam 14 <3,FRIENDSANITY, +1357,Carpenter Shop,Friendsanity: Sebastian 1 <3,FRIENDSANITY, +1358,Carpenter Shop,Friendsanity: Sebastian 2 <3,FRIENDSANITY, +1359,Carpenter Shop,Friendsanity: Sebastian 3 <3,FRIENDSANITY, +1360,Carpenter Shop,Friendsanity: Sebastian 4 <3,FRIENDSANITY, +1361,Carpenter Shop,Friendsanity: Sebastian 5 <3,FRIENDSANITY, +1362,Carpenter Shop,Friendsanity: Sebastian 6 <3,FRIENDSANITY, +1363,Carpenter Shop,Friendsanity: Sebastian 7 <3,FRIENDSANITY, +1364,Carpenter Shop,Friendsanity: Sebastian 8 <3,FRIENDSANITY, +1365,Carpenter Shop,Friendsanity: Sebastian 9 <3,FRIENDSANITY, +1366,Carpenter Shop,Friendsanity: Sebastian 10 <3,FRIENDSANITY, +1367,Carpenter Shop,Friendsanity: Sebastian 11 <3,FRIENDSANITY, +1368,Carpenter Shop,Friendsanity: Sebastian 12 <3,FRIENDSANITY, +1369,Carpenter Shop,Friendsanity: Sebastian 13 <3,FRIENDSANITY, +1370,Carpenter Shop,Friendsanity: Sebastian 14 <3,FRIENDSANITY, +1371,Marnie's Ranch,Friendsanity: Shane 1 <3,FRIENDSANITY, +1372,Marnie's Ranch,Friendsanity: Shane 2 <3,FRIENDSANITY, +1373,Marnie's Ranch,Friendsanity: Shane 3 <3,FRIENDSANITY, +1374,Marnie's Ranch,Friendsanity: Shane 4 <3,FRIENDSANITY, +1375,Marnie's Ranch,Friendsanity: Shane 5 <3,FRIENDSANITY, +1376,Marnie's Ranch,Friendsanity: Shane 6 <3,FRIENDSANITY, +1377,Marnie's Ranch,Friendsanity: Shane 7 <3,FRIENDSANITY, +1378,Marnie's Ranch,Friendsanity: Shane 8 <3,FRIENDSANITY, +1379,Marnie's Ranch,Friendsanity: Shane 9 <3,FRIENDSANITY, +1380,Marnie's Ranch,Friendsanity: Shane 10 <3,FRIENDSANITY, +1381,Marnie's Ranch,Friendsanity: Shane 11 <3,FRIENDSANITY, +1382,Marnie's Ranch,Friendsanity: Shane 12 <3,FRIENDSANITY, +1383,Marnie's Ranch,Friendsanity: Shane 13 <3,FRIENDSANITY, +1384,Marnie's Ranch,Friendsanity: Shane 14 <3,FRIENDSANITY, +1385,Pierre's General Store,Friendsanity: Abigail 1 <3,FRIENDSANITY, +1386,Pierre's General Store,Friendsanity: Abigail 2 <3,FRIENDSANITY, +1387,Pierre's General Store,Friendsanity: Abigail 3 <3,FRIENDSANITY, +1388,Pierre's General Store,Friendsanity: Abigail 4 <3,FRIENDSANITY, +1389,Pierre's General Store,Friendsanity: Abigail 5 <3,FRIENDSANITY, +1390,Pierre's General Store,Friendsanity: Abigail 6 <3,FRIENDSANITY, +1391,Pierre's General Store,Friendsanity: Abigail 7 <3,FRIENDSANITY, +1392,Pierre's General Store,Friendsanity: Abigail 8 <3,FRIENDSANITY, +1393,Pierre's General Store,Friendsanity: Abigail 9 <3,FRIENDSANITY, +1394,Pierre's General Store,Friendsanity: Abigail 10 <3,FRIENDSANITY, +1395,Pierre's General Store,Friendsanity: Abigail 11 <3,FRIENDSANITY, +1396,Pierre's General Store,Friendsanity: Abigail 12 <3,FRIENDSANITY, +1397,Pierre's General Store,Friendsanity: Abigail 13 <3,FRIENDSANITY, +1398,Pierre's General Store,Friendsanity: Abigail 14 <3,FRIENDSANITY, +1399,Haley's House,Friendsanity: Emily 1 <3,FRIENDSANITY, +1400,Haley's House,Friendsanity: Emily 2 <3,FRIENDSANITY, +1401,Haley's House,Friendsanity: Emily 3 <3,FRIENDSANITY, +1402,Haley's House,Friendsanity: Emily 4 <3,FRIENDSANITY, +1403,Haley's House,Friendsanity: Emily 5 <3,FRIENDSANITY, +1404,Haley's House,Friendsanity: Emily 6 <3,FRIENDSANITY, +1405,Haley's House,Friendsanity: Emily 7 <3,FRIENDSANITY, +1406,Haley's House,Friendsanity: Emily 8 <3,FRIENDSANITY, +1407,Haley's House,Friendsanity: Emily 9 <3,FRIENDSANITY, +1408,Haley's House,Friendsanity: Emily 10 <3,FRIENDSANITY, +1409,Haley's House,Friendsanity: Emily 11 <3,FRIENDSANITY, +1410,Haley's House,Friendsanity: Emily 12 <3,FRIENDSANITY, +1411,Haley's House,Friendsanity: Emily 13 <3,FRIENDSANITY, +1412,Haley's House,Friendsanity: Emily 14 <3,FRIENDSANITY, +1413,Haley's House,Friendsanity: Haley 1 <3,FRIENDSANITY, +1414,Haley's House,Friendsanity: Haley 2 <3,FRIENDSANITY, +1415,Haley's House,Friendsanity: Haley 3 <3,FRIENDSANITY, +1416,Haley's House,Friendsanity: Haley 4 <3,FRIENDSANITY, +1417,Haley's House,Friendsanity: Haley 5 <3,FRIENDSANITY, +1418,Haley's House,Friendsanity: Haley 6 <3,FRIENDSANITY, +1419,Haley's House,Friendsanity: Haley 7 <3,FRIENDSANITY, +1420,Haley's House,Friendsanity: Haley 8 <3,FRIENDSANITY, +1421,Haley's House,Friendsanity: Haley 9 <3,FRIENDSANITY, +1422,Haley's House,Friendsanity: Haley 10 <3,FRIENDSANITY, +1423,Haley's House,Friendsanity: Haley 11 <3,FRIENDSANITY, +1424,Haley's House,Friendsanity: Haley 12 <3,FRIENDSANITY, +1425,Haley's House,Friendsanity: Haley 13 <3,FRIENDSANITY, +1426,Haley's House,Friendsanity: Haley 14 <3,FRIENDSANITY, +1427,Leah's Cottage,Friendsanity: Leah 1 <3,FRIENDSANITY, +1428,Leah's Cottage,Friendsanity: Leah 2 <3,FRIENDSANITY, +1429,Leah's Cottage,Friendsanity: Leah 3 <3,FRIENDSANITY, +1430,Leah's Cottage,Friendsanity: Leah 4 <3,FRIENDSANITY, +1431,Leah's Cottage,Friendsanity: Leah 5 <3,FRIENDSANITY, +1432,Leah's Cottage,Friendsanity: Leah 6 <3,FRIENDSANITY, +1433,Leah's Cottage,Friendsanity: Leah 7 <3,FRIENDSANITY, +1434,Leah's Cottage,Friendsanity: Leah 8 <3,FRIENDSANITY, +1435,Leah's Cottage,Friendsanity: Leah 9 <3,FRIENDSANITY, +1436,Leah's Cottage,Friendsanity: Leah 10 <3,FRIENDSANITY, +1437,Leah's Cottage,Friendsanity: Leah 11 <3,FRIENDSANITY, +1438,Leah's Cottage,Friendsanity: Leah 12 <3,FRIENDSANITY, +1439,Leah's Cottage,Friendsanity: Leah 13 <3,FRIENDSANITY, +1440,Leah's Cottage,Friendsanity: Leah 14 <3,FRIENDSANITY, +1441,Carpenter Shop,Friendsanity: Maru 1 <3,FRIENDSANITY, +1442,Carpenter Shop,Friendsanity: Maru 2 <3,FRIENDSANITY, +1443,Carpenter Shop,Friendsanity: Maru 3 <3,FRIENDSANITY, +1444,Carpenter Shop,Friendsanity: Maru 4 <3,FRIENDSANITY, +1445,Carpenter Shop,Friendsanity: Maru 5 <3,FRIENDSANITY, +1446,Carpenter Shop,Friendsanity: Maru 6 <3,FRIENDSANITY, +1447,Carpenter Shop,Friendsanity: Maru 7 <3,FRIENDSANITY, +1448,Carpenter Shop,Friendsanity: Maru 8 <3,FRIENDSANITY, +1449,Carpenter Shop,Friendsanity: Maru 9 <3,FRIENDSANITY, +1450,Carpenter Shop,Friendsanity: Maru 10 <3,FRIENDSANITY, +1451,Carpenter Shop,Friendsanity: Maru 11 <3,FRIENDSANITY, +1452,Carpenter Shop,Friendsanity: Maru 12 <3,FRIENDSANITY, +1453,Carpenter Shop,Friendsanity: Maru 13 <3,FRIENDSANITY, +1454,Carpenter Shop,Friendsanity: Maru 14 <3,FRIENDSANITY, +1455,Trailer,Friendsanity: Penny 1 <3,FRIENDSANITY, +1456,Trailer,Friendsanity: Penny 2 <3,FRIENDSANITY, +1457,Trailer,Friendsanity: Penny 3 <3,FRIENDSANITY, +1458,Trailer,Friendsanity: Penny 4 <3,FRIENDSANITY, +1459,Trailer,Friendsanity: Penny 5 <3,FRIENDSANITY, +1460,Trailer,Friendsanity: Penny 6 <3,FRIENDSANITY, +1461,Trailer,Friendsanity: Penny 7 <3,FRIENDSANITY, +1462,Trailer,Friendsanity: Penny 8 <3,FRIENDSANITY, +1463,Trailer,Friendsanity: Penny 9 <3,FRIENDSANITY, +1464,Trailer,Friendsanity: Penny 10 <3,FRIENDSANITY, +1465,Trailer,Friendsanity: Penny 11 <3,FRIENDSANITY, +1466,Trailer,Friendsanity: Penny 12 <3,FRIENDSANITY, +1467,Trailer,Friendsanity: Penny 13 <3,FRIENDSANITY, +1468,Trailer,Friendsanity: Penny 14 <3,FRIENDSANITY, +1469,Pierre's General Store,Friendsanity: Caroline 1 <3,FRIENDSANITY, +1470,Pierre's General Store,Friendsanity: Caroline 2 <3,FRIENDSANITY, +1471,Pierre's General Store,Friendsanity: Caroline 3 <3,FRIENDSANITY, +1472,Pierre's General Store,Friendsanity: Caroline 4 <3,FRIENDSANITY, +1473,Pierre's General Store,Friendsanity: Caroline 5 <3,FRIENDSANITY, +1474,Pierre's General Store,Friendsanity: Caroline 6 <3,FRIENDSANITY, +1475,Pierre's General Store,Friendsanity: Caroline 7 <3,FRIENDSANITY, +1476,Pierre's General Store,Friendsanity: Caroline 8 <3,FRIENDSANITY, +1477,Pierre's General Store,Friendsanity: Caroline 9 <3,FRIENDSANITY, +1478,Pierre's General Store,Friendsanity: Caroline 10 <3,FRIENDSANITY, +1480,Clint's Blacksmith,Friendsanity: Clint 1 <3,FRIENDSANITY, +1481,Clint's Blacksmith,Friendsanity: Clint 2 <3,FRIENDSANITY, +1482,Clint's Blacksmith,Friendsanity: Clint 3 <3,FRIENDSANITY, +1483,Clint's Blacksmith,Friendsanity: Clint 4 <3,FRIENDSANITY, +1484,Clint's Blacksmith,Friendsanity: Clint 5 <3,FRIENDSANITY, +1485,Clint's Blacksmith,Friendsanity: Clint 6 <3,FRIENDSANITY, +1486,Clint's Blacksmith,Friendsanity: Clint 7 <3,FRIENDSANITY, +1487,Clint's Blacksmith,Friendsanity: Clint 8 <3,FRIENDSANITY, +1488,Clint's Blacksmith,Friendsanity: Clint 9 <3,FRIENDSANITY, +1489,Clint's Blacksmith,Friendsanity: Clint 10 <3,FRIENDSANITY, +1491,Carpenter Shop,Friendsanity: Demetrius 1 <3,FRIENDSANITY, +1492,Carpenter Shop,Friendsanity: Demetrius 2 <3,FRIENDSANITY, +1493,Carpenter Shop,Friendsanity: Demetrius 3 <3,FRIENDSANITY, +1494,Carpenter Shop,Friendsanity: Demetrius 4 <3,FRIENDSANITY, +1495,Carpenter Shop,Friendsanity: Demetrius 5 <3,FRIENDSANITY, +1496,Carpenter Shop,Friendsanity: Demetrius 6 <3,FRIENDSANITY, +1497,Carpenter Shop,Friendsanity: Demetrius 7 <3,FRIENDSANITY, +1498,Carpenter Shop,Friendsanity: Demetrius 8 <3,FRIENDSANITY, +1499,Carpenter Shop,Friendsanity: Demetrius 9 <3,FRIENDSANITY, +1500,Carpenter Shop,Friendsanity: Demetrius 10 <3,FRIENDSANITY, +1502,Mines Dwarf Shop,Friendsanity: Dwarf 1 <3,FRIENDSANITY, +1503,Mines Dwarf Shop,Friendsanity: Dwarf 2 <3,FRIENDSANITY, +1504,Mines Dwarf Shop,Friendsanity: Dwarf 3 <3,FRIENDSANITY, +1505,Mines Dwarf Shop,Friendsanity: Dwarf 4 <3,FRIENDSANITY, +1506,Mines Dwarf Shop,Friendsanity: Dwarf 5 <3,FRIENDSANITY, +1507,Mines Dwarf Shop,Friendsanity: Dwarf 6 <3,FRIENDSANITY, +1508,Mines Dwarf Shop,Friendsanity: Dwarf 7 <3,FRIENDSANITY, +1509,Mines Dwarf Shop,Friendsanity: Dwarf 8 <3,FRIENDSANITY, +1510,Mines Dwarf Shop,Friendsanity: Dwarf 9 <3,FRIENDSANITY, +1511,Mines Dwarf Shop,Friendsanity: Dwarf 10 <3,FRIENDSANITY, +1513,Alex's House,Friendsanity: Evelyn 1 <3,FRIENDSANITY, +1514,Alex's House,Friendsanity: Evelyn 2 <3,FRIENDSANITY, +1515,Alex's House,Friendsanity: Evelyn 3 <3,FRIENDSANITY, +1516,Alex's House,Friendsanity: Evelyn 4 <3,FRIENDSANITY, +1517,Alex's House,Friendsanity: Evelyn 5 <3,FRIENDSANITY, +1518,Alex's House,Friendsanity: Evelyn 6 <3,FRIENDSANITY, +1519,Alex's House,Friendsanity: Evelyn 7 <3,FRIENDSANITY, +1520,Alex's House,Friendsanity: Evelyn 8 <3,FRIENDSANITY, +1521,Alex's House,Friendsanity: Evelyn 9 <3,FRIENDSANITY, +1522,Alex's House,Friendsanity: Evelyn 10 <3,FRIENDSANITY, +1524,Alex's House,Friendsanity: George 1 <3,FRIENDSANITY, +1525,Alex's House,Friendsanity: George 2 <3,FRIENDSANITY, +1526,Alex's House,Friendsanity: George 3 <3,FRIENDSANITY, +1527,Alex's House,Friendsanity: George 4 <3,FRIENDSANITY, +1528,Alex's House,Friendsanity: George 5 <3,FRIENDSANITY, +1529,Alex's House,Friendsanity: George 6 <3,FRIENDSANITY, +1530,Alex's House,Friendsanity: George 7 <3,FRIENDSANITY, +1531,Alex's House,Friendsanity: George 8 <3,FRIENDSANITY, +1532,Alex's House,Friendsanity: George 9 <3,FRIENDSANITY, +1533,Alex's House,Friendsanity: George 10 <3,FRIENDSANITY, +1535,Saloon,Friendsanity: Gus 1 <3,FRIENDSANITY, +1536,Saloon,Friendsanity: Gus 2 <3,FRIENDSANITY, +1537,Saloon,Friendsanity: Gus 3 <3,FRIENDSANITY, +1538,Saloon,Friendsanity: Gus 4 <3,FRIENDSANITY, +1539,Saloon,Friendsanity: Gus 5 <3,FRIENDSANITY, +1540,Saloon,Friendsanity: Gus 6 <3,FRIENDSANITY, +1541,Saloon,Friendsanity: Gus 7 <3,FRIENDSANITY, +1542,Saloon,Friendsanity: Gus 8 <3,FRIENDSANITY, +1543,Saloon,Friendsanity: Gus 9 <3,FRIENDSANITY, +1544,Saloon,Friendsanity: Gus 10 <3,FRIENDSANITY, +1546,Marnie's Ranch,Friendsanity: Jas 1 <3,FRIENDSANITY, +1547,Marnie's Ranch,Friendsanity: Jas 2 <3,FRIENDSANITY, +1548,Marnie's Ranch,Friendsanity: Jas 3 <3,FRIENDSANITY, +1549,Marnie's Ranch,Friendsanity: Jas 4 <3,FRIENDSANITY, +1550,Marnie's Ranch,Friendsanity: Jas 5 <3,FRIENDSANITY, +1551,Marnie's Ranch,Friendsanity: Jas 6 <3,FRIENDSANITY, +1552,Marnie's Ranch,Friendsanity: Jas 7 <3,FRIENDSANITY, +1553,Marnie's Ranch,Friendsanity: Jas 8 <3,FRIENDSANITY, +1554,Marnie's Ranch,Friendsanity: Jas 9 <3,FRIENDSANITY, +1555,Marnie's Ranch,Friendsanity: Jas 10 <3,FRIENDSANITY, +1557,Sam's House,Friendsanity: Jodi 1 <3,FRIENDSANITY, +1558,Sam's House,Friendsanity: Jodi 2 <3,FRIENDSANITY, +1559,Sam's House,Friendsanity: Jodi 3 <3,FRIENDSANITY, +1560,Sam's House,Friendsanity: Jodi 4 <3,FRIENDSANITY, +1561,Sam's House,Friendsanity: Jodi 5 <3,FRIENDSANITY, +1562,Sam's House,Friendsanity: Jodi 6 <3,FRIENDSANITY, +1563,Sam's House,Friendsanity: Jodi 7 <3,FRIENDSANITY, +1564,Sam's House,Friendsanity: Jodi 8 <3,FRIENDSANITY, +1565,Sam's House,Friendsanity: Jodi 9 <3,FRIENDSANITY, +1566,Sam's House,Friendsanity: Jodi 10 <3,FRIENDSANITY, +1568,Sam's House,Friendsanity: Kent 1 <3,FRIENDSANITY, +1569,Sam's House,Friendsanity: Kent 2 <3,FRIENDSANITY, +1570,Sam's House,Friendsanity: Kent 3 <3,FRIENDSANITY, +1571,Sam's House,Friendsanity: Kent 4 <3,FRIENDSANITY, +1572,Sam's House,Friendsanity: Kent 5 <3,FRIENDSANITY, +1573,Sam's House,Friendsanity: Kent 6 <3,FRIENDSANITY, +1574,Sam's House,Friendsanity: Kent 7 <3,FRIENDSANITY, +1575,Sam's House,Friendsanity: Kent 8 <3,FRIENDSANITY, +1576,Sam's House,Friendsanity: Kent 9 <3,FRIENDSANITY, +1577,Sam's House,Friendsanity: Kent 10 <3,FRIENDSANITY, +1579,Sewer,Friendsanity: Krobus 1 <3,FRIENDSANITY, +1580,Sewer,Friendsanity: Krobus 2 <3,FRIENDSANITY, +1581,Sewer,Friendsanity: Krobus 3 <3,FRIENDSANITY, +1582,Sewer,Friendsanity: Krobus 4 <3,FRIENDSANITY, +1583,Sewer,Friendsanity: Krobus 5 <3,FRIENDSANITY, +1584,Sewer,Friendsanity: Krobus 6 <3,FRIENDSANITY, +1585,Sewer,Friendsanity: Krobus 7 <3,FRIENDSANITY, +1586,Sewer,Friendsanity: Krobus 8 <3,FRIENDSANITY, +1587,Sewer,Friendsanity: Krobus 9 <3,FRIENDSANITY, +1588,Sewer,Friendsanity: Krobus 10 <3,FRIENDSANITY, +1590,Leo's Hut,Friendsanity: Leo 1 <3,"FRIENDSANITY,GINGER_ISLAND", +1591,Leo's Hut,Friendsanity: Leo 2 <3,"FRIENDSANITY,GINGER_ISLAND", +1592,Leo's Hut,Friendsanity: Leo 3 <3,"FRIENDSANITY,GINGER_ISLAND", +1593,Leo's Hut,Friendsanity: Leo 4 <3,"FRIENDSANITY,GINGER_ISLAND", +1594,Leo's Hut,Friendsanity: Leo 5 <3,"FRIENDSANITY,GINGER_ISLAND", +1595,Leo's Hut,Friendsanity: Leo 6 <3,"FRIENDSANITY,GINGER_ISLAND", +1596,Leo's Hut,Friendsanity: Leo 7 <3,"FRIENDSANITY,GINGER_ISLAND", +1597,Leo's Hut,Friendsanity: Leo 8 <3,"FRIENDSANITY,GINGER_ISLAND", +1598,Leo's Hut,Friendsanity: Leo 9 <3,"FRIENDSANITY,GINGER_ISLAND", +1599,Leo's Hut,Friendsanity: Leo 10 <3,"FRIENDSANITY,GINGER_ISLAND", +1601,Mayor's Manor,Friendsanity: Lewis 1 <3,FRIENDSANITY, +1602,Mayor's Manor,Friendsanity: Lewis 2 <3,FRIENDSANITY, +1603,Mayor's Manor,Friendsanity: Lewis 3 <3,FRIENDSANITY, +1604,Mayor's Manor,Friendsanity: Lewis 4 <3,FRIENDSANITY, +1605,Mayor's Manor,Friendsanity: Lewis 5 <3,FRIENDSANITY, +1606,Mayor's Manor,Friendsanity: Lewis 6 <3,FRIENDSANITY, +1607,Mayor's Manor,Friendsanity: Lewis 7 <3,FRIENDSANITY, +1608,Mayor's Manor,Friendsanity: Lewis 8 <3,FRIENDSANITY, +1609,Mayor's Manor,Friendsanity: Lewis 9 <3,FRIENDSANITY, +1610,Mayor's Manor,Friendsanity: Lewis 10 <3,FRIENDSANITY, +1612,Tent,Friendsanity: Linus 1 <3,FRIENDSANITY, +1613,Tent,Friendsanity: Linus 2 <3,FRIENDSANITY, +1614,Tent,Friendsanity: Linus 3 <3,FRIENDSANITY, +1615,Tent,Friendsanity: Linus 4 <3,FRIENDSANITY, +1616,Tent,Friendsanity: Linus 5 <3,FRIENDSANITY, +1617,Tent,Friendsanity: Linus 6 <3,FRIENDSANITY, +1618,Tent,Friendsanity: Linus 7 <3,FRIENDSANITY, +1619,Tent,Friendsanity: Linus 8 <3,FRIENDSANITY, +1620,Tent,Friendsanity: Linus 9 <3,FRIENDSANITY, +1621,Tent,Friendsanity: Linus 10 <3,FRIENDSANITY, +1623,Marnie's Ranch,Friendsanity: Marnie 1 <3,FRIENDSANITY, +1624,Marnie's Ranch,Friendsanity: Marnie 2 <3,FRIENDSANITY, +1625,Marnie's Ranch,Friendsanity: Marnie 3 <3,FRIENDSANITY, +1626,Marnie's Ranch,Friendsanity: Marnie 4 <3,FRIENDSANITY, +1627,Marnie's Ranch,Friendsanity: Marnie 5 <3,FRIENDSANITY, +1628,Marnie's Ranch,Friendsanity: Marnie 6 <3,FRIENDSANITY, +1629,Marnie's Ranch,Friendsanity: Marnie 7 <3,FRIENDSANITY, +1630,Marnie's Ranch,Friendsanity: Marnie 8 <3,FRIENDSANITY, +1631,Marnie's Ranch,Friendsanity: Marnie 9 <3,FRIENDSANITY, +1632,Marnie's Ranch,Friendsanity: Marnie 10 <3,FRIENDSANITY, +1634,Trailer,Friendsanity: Pam 1 <3,FRIENDSANITY, +1635,Trailer,Friendsanity: Pam 2 <3,FRIENDSANITY, +1636,Trailer,Friendsanity: Pam 3 <3,FRIENDSANITY, +1637,Trailer,Friendsanity: Pam 4 <3,FRIENDSANITY, +1638,Trailer,Friendsanity: Pam 5 <3,FRIENDSANITY, +1639,Trailer,Friendsanity: Pam 6 <3,FRIENDSANITY, +1640,Trailer,Friendsanity: Pam 7 <3,FRIENDSANITY, +1641,Trailer,Friendsanity: Pam 8 <3,FRIENDSANITY, +1642,Trailer,Friendsanity: Pam 9 <3,FRIENDSANITY, +1643,Trailer,Friendsanity: Pam 10 <3,FRIENDSANITY, +1645,Pierre's General Store,Friendsanity: Pierre 1 <3,FRIENDSANITY, +1646,Pierre's General Store,Friendsanity: Pierre 2 <3,FRIENDSANITY, +1647,Pierre's General Store,Friendsanity: Pierre 3 <3,FRIENDSANITY, +1648,Pierre's General Store,Friendsanity: Pierre 4 <3,FRIENDSANITY, +1649,Pierre's General Store,Friendsanity: Pierre 5 <3,FRIENDSANITY, +1650,Pierre's General Store,Friendsanity: Pierre 6 <3,FRIENDSANITY, +1651,Pierre's General Store,Friendsanity: Pierre 7 <3,FRIENDSANITY, +1652,Pierre's General Store,Friendsanity: Pierre 8 <3,FRIENDSANITY, +1653,Pierre's General Store,Friendsanity: Pierre 9 <3,FRIENDSANITY, +1654,Pierre's General Store,Friendsanity: Pierre 10 <3,FRIENDSANITY, +1656,Carpenter Shop,Friendsanity: Robin 1 <3,FRIENDSANITY, +1657,Carpenter Shop,Friendsanity: Robin 2 <3,FRIENDSANITY, +1658,Carpenter Shop,Friendsanity: Robin 3 <3,FRIENDSANITY, +1659,Carpenter Shop,Friendsanity: Robin 4 <3,FRIENDSANITY, +1660,Carpenter Shop,Friendsanity: Robin 5 <3,FRIENDSANITY, +1661,Carpenter Shop,Friendsanity: Robin 6 <3,FRIENDSANITY, +1662,Carpenter Shop,Friendsanity: Robin 7 <3,FRIENDSANITY, +1663,Carpenter Shop,Friendsanity: Robin 8 <3,FRIENDSANITY, +1664,Carpenter Shop,Friendsanity: Robin 9 <3,FRIENDSANITY, +1665,Carpenter Shop,Friendsanity: Robin 10 <3,FRIENDSANITY, +1667,Oasis,Friendsanity: Sandy 1 <3,FRIENDSANITY, +1668,Oasis,Friendsanity: Sandy 2 <3,FRIENDSANITY, +1669,Oasis,Friendsanity: Sandy 3 <3,FRIENDSANITY, +1670,Oasis,Friendsanity: Sandy 4 <3,FRIENDSANITY, +1671,Oasis,Friendsanity: Sandy 5 <3,FRIENDSANITY, +1672,Oasis,Friendsanity: Sandy 6 <3,FRIENDSANITY, +1673,Oasis,Friendsanity: Sandy 7 <3,FRIENDSANITY, +1674,Oasis,Friendsanity: Sandy 8 <3,FRIENDSANITY, +1675,Oasis,Friendsanity: Sandy 9 <3,FRIENDSANITY, +1676,Oasis,Friendsanity: Sandy 10 <3,FRIENDSANITY, +1678,Sam's House,Friendsanity: Vincent 1 <3,FRIENDSANITY, +1679,Sam's House,Friendsanity: Vincent 2 <3,FRIENDSANITY, +1680,Sam's House,Friendsanity: Vincent 3 <3,FRIENDSANITY, +1681,Sam's House,Friendsanity: Vincent 4 <3,FRIENDSANITY, +1682,Sam's House,Friendsanity: Vincent 5 <3,FRIENDSANITY, +1683,Sam's House,Friendsanity: Vincent 6 <3,FRIENDSANITY, +1684,Sam's House,Friendsanity: Vincent 7 <3,FRIENDSANITY, +1685,Sam's House,Friendsanity: Vincent 8 <3,FRIENDSANITY, +1686,Sam's House,Friendsanity: Vincent 9 <3,FRIENDSANITY, +1687,Sam's House,Friendsanity: Vincent 10 <3,FRIENDSANITY, +1689,Willy's Fish Shop,Friendsanity: Willy 1 <3,FRIENDSANITY, +1690,Willy's Fish Shop,Friendsanity: Willy 2 <3,FRIENDSANITY, +1691,Willy's Fish Shop,Friendsanity: Willy 3 <3,FRIENDSANITY, +1692,Willy's Fish Shop,Friendsanity: Willy 4 <3,FRIENDSANITY, +1693,Willy's Fish Shop,Friendsanity: Willy 5 <3,FRIENDSANITY, +1694,Willy's Fish Shop,Friendsanity: Willy 6 <3,FRIENDSANITY, +1695,Willy's Fish Shop,Friendsanity: Willy 7 <3,FRIENDSANITY, +1696,Willy's Fish Shop,Friendsanity: Willy 8 <3,FRIENDSANITY, +1697,Willy's Fish Shop,Friendsanity: Willy 9 <3,FRIENDSANITY, +1698,Willy's Fish Shop,Friendsanity: Willy 10 <3,FRIENDSANITY, +1700,Wizard Tower,Friendsanity: Wizard 1 <3,FRIENDSANITY, +1701,Wizard Tower,Friendsanity: Wizard 2 <3,FRIENDSANITY, +1702,Wizard Tower,Friendsanity: Wizard 3 <3,FRIENDSANITY, +1703,Wizard Tower,Friendsanity: Wizard 4 <3,FRIENDSANITY, +1704,Wizard Tower,Friendsanity: Wizard 5 <3,FRIENDSANITY, +1705,Wizard Tower,Friendsanity: Wizard 6 <3,FRIENDSANITY, +1706,Wizard Tower,Friendsanity: Wizard 7 <3,FRIENDSANITY, +1707,Wizard Tower,Friendsanity: Wizard 8 <3,FRIENDSANITY, +1708,Wizard Tower,Friendsanity: Wizard 9 <3,FRIENDSANITY, +1709,Wizard Tower,Friendsanity: Wizard 10 <3,FRIENDSANITY, +1710,Farm,Friendsanity: Pet 1 <3,FRIENDSANITY, +1711,Farm,Friendsanity: Pet 2 <3,FRIENDSANITY, +1712,Farm,Friendsanity: Pet 3 <3,FRIENDSANITY, +1713,Farm,Friendsanity: Pet 4 <3,FRIENDSANITY, +1714,Farm,Friendsanity: Pet 5 <3,FRIENDSANITY, +1715,Town,Friendsanity: Friend 1 <3,FRIENDSANITY, +1716,Town,Friendsanity: Friend 2 <3,FRIENDSANITY, +1717,Town,Friendsanity: Friend 3 <3,FRIENDSANITY, +1718,Town,Friendsanity: Friend 4 <3,FRIENDSANITY, +1719,Town,Friendsanity: Friend 5 <3,FRIENDSANITY, +1720,Town,Friendsanity: Friend 6 <3,FRIENDSANITY, +1721,Town,Friendsanity: Friend 7 <3,FRIENDSANITY, +1722,Town,Friendsanity: Friend 8 <3,FRIENDSANITY, +1723,Town,Friendsanity: Suitor 9 <3,FRIENDSANITY, +1724,Town,Friendsanity: Suitor 10 <3,FRIENDSANITY, +1725,Town,Friendsanity: Spouse 11 <3,FRIENDSANITY, +1726,Town,Friendsanity: Spouse 12 <3,FRIENDSANITY, +1727,Town,Friendsanity: Spouse 13 <3,FRIENDSANITY, +1728,Town,Friendsanity: Spouse 14 <3,FRIENDSANITY, +2001,Egg Festival,Egg Hunt Victory,FESTIVAL, +2002,Egg Festival,Egg Festival: Strawberry Seeds,FESTIVAL, +2003,Flower Dance,Dance with someone,FESTIVAL, +2004,Flower Dance,Rarecrow #5 (Woman),FESTIVAL, +2005,Luau,Luau Soup,FESTIVAL, +2006,Dance of the Moonlight Jellies,Dance of the Moonlight Jellies,FESTIVAL, +2007,Stardew Valley Fair,Smashing Stone,FESTIVAL, +2008,Stardew Valley Fair,Grange Display,FESTIVAL, +2009,Stardew Valley Fair,Rarecrow #1 (Turnip Head),FESTIVAL, +2010,Stardew Valley Fair,Fair Stardrop,FESTIVAL, +2011,Spirit's Eve,Spirit's Eve Maze,FESTIVAL, +2012,Spirit's Eve,Rarecrow #2 (Witch),FESTIVAL, +2013,Festival of Ice,Win Fishing Competition,FESTIVAL, +2014,Festival of Ice,Rarecrow #4 (Snowman),FESTIVAL, +2015,Night Market,Mermaid Pearl,FESTIVAL, +2016,Night Market,Cone Hat,FESTIVAL_HARD, +2017,Night Market,Iridium Fireplace,FESTIVAL_HARD, +2018,Night Market,Rarecrow #7 (Tanuki),FESTIVAL, +2019,Night Market,Rarecrow #8 (Tribal Mask),FESTIVAL, +2020,Night Market,Lupini: Red Eagle,FESTIVAL, +2021,Night Market,Lupini: Portrait Of A Mermaid,FESTIVAL, +2022,Night Market,Lupini: Solar Kingdom,FESTIVAL, +2023,Night Market,Lupini: Clouds,FESTIVAL_HARD, +2024,Night Market,Lupini: 1000 Years From Now,FESTIVAL_HARD, +2025,Night Market,Lupini: Three Trees,FESTIVAL_HARD, +2026,Night Market,Lupini: The Serpent,FESTIVAL_HARD, +2027,Night Market,Lupini: 'Tropical Fish #173',FESTIVAL_HARD, +2028,Night Market,Lupini: Land Of Clay,FESTIVAL_HARD, +2029,Feast of the Winter Star,Secret Santa,FESTIVAL, +2030,Feast of the Winter Star,The Legend of the Winter Star,FESTIVAL, +2031,Farm,Collect All Rarecrows,FESTIVAL, +2032,Flower Dance,Tub o' Flowers Recipe,FESTIVAL, +2033,Spirit's Eve,Jack-O-Lantern Recipe,FESTIVAL, +2034,Dance of the Moonlight Jellies,Moonlight Jellies Banner,FESTIVAL, +2035,Dance of the Moonlight Jellies,Starport Decal,FESTIVAL, +2036,Casino,Rarecrow #3 (Alien),FESTIVAL, +2101,Town,Island Ingredients,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2102,The Mines - Floor 75,Cave Patrol,SPECIAL_ORDER_BOARD, +2103,Fishing,Aquatic Overpopulation,SPECIAL_ORDER_BOARD, +2104,Fishing,Biome Balance,SPECIAL_ORDER_BOARD, +2105,Haley's House,Rock Rejuvenation,SPECIAL_ORDER_BOARD, +2106,Alex's House,Gifts for George,SPECIAL_ORDER_BOARD, +2107,Museum,Fragments of the past,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2108,Saloon,Gus' Famous Omelet,SPECIAL_ORDER_BOARD, +2109,Farm,Crop Order,SPECIAL_ORDER_BOARD, +2110,Railroad,Community Cleanup,SPECIAL_ORDER_BOARD, +2111,Trailer,The Strong Stuff,SPECIAL_ORDER_BOARD, +2112,Pierre's General Store,Pierre's Prime Produce,SPECIAL_ORDER_BOARD, +2113,Carpenter Shop,Robin's Project,SPECIAL_ORDER_BOARD, +2114,Carpenter Shop,Robin's Resource Rush,SPECIAL_ORDER_BOARD, +2115,Beach,Juicy Bugs Wanted!,SPECIAL_ORDER_BOARD, +2116,Town,Tropical Fish,"GINGER_ISLAND,SPECIAL_ORDER_BOARD", +2117,The Mines - Floor 75,A Curious Substance,SPECIAL_ORDER_BOARD, +2118,The Mines - Floor 35,Prismatic Jelly,SPECIAL_ORDER_BOARD, +2151,Qi's Walnut Room,Qi's Crop,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2152,Qi's Walnut Room,Let's Play A Game,"GINGER_ISLAND,JUNIMO_KART,SPECIAL_ORDER_QI", +2153,Qi's Walnut Room,Four Precious Stones,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2154,Qi's Walnut Room,Qi's Hungry Challenge,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2155,Qi's Walnut Room,Qi's Cuisine,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2156,Qi's Walnut Room,Qi's Kindness,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2157,Qi's Walnut Room,Extended Family,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2158,Qi's Walnut Room,Danger In The Deep,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2159,Qi's Walnut Room,Skull Cavern Invasion,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2160,Qi's Walnut Room,Qi's Prismatic Grange,"GINGER_ISLAND,SPECIAL_ORDER_QI", +2201,Boat Tunnel,Repair Ticket Machine,GINGER_ISLAND, +2202,Boat Tunnel,Repair Boat Hull,GINGER_ISLAND, +2203,Boat Tunnel,Repair Boat Anchor,GINGER_ISLAND, +2204,Leo's Hut,Leo's Parrot,"GINGER_ISLAND,WALNUT_PURCHASE", +2205,Island South,Island West Turtle,"GINGER_ISLAND,WALNUT_PURCHASE", +2206,Island West,Island Farmhouse,"GINGER_ISLAND,WALNUT_PURCHASE", +2207,Island Farmhouse,Island Mailbox,"GINGER_ISLAND,WALNUT_PURCHASE", +2208,Island Farmhouse,Farm Obelisk,"GINGER_ISLAND,WALNUT_PURCHASE", +2209,Island North,Dig Site Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2210,Island North,Island Trader,"GINGER_ISLAND,WALNUT_PURCHASE", +2211,Volcano Entrance,Volcano Bridge,"GINGER_ISLAND,WALNUT_PURCHASE", +2212,Volcano - Floor 5,Volcano Exit Shortcut,"GINGER_ISLAND,WALNUT_PURCHASE", +2213,Island South,Island Resort,"GINGER_ISLAND,WALNUT_PURCHASE", +2214,Island West,Parrot Express,"GINGER_ISLAND,WALNUT_PURCHASE", +2215,Dig Site,Open Professor Snail Cave,GINGER_ISLAND, +2216,Field Office,Complete Island Field Office,GINGER_ISLAND, +2301,Farming,Harvest Amaranth,CROPSANITY, +2302,Farming,Harvest Artichoke,CROPSANITY, +2303,Farming,Harvest Beet,CROPSANITY, +2304,Farming,Harvest Blue Jazz,CROPSANITY, +2305,Farming,Harvest Blueberry,CROPSANITY, +2306,Farming,Harvest Bok Choy,CROPSANITY, +2307,Farming,Harvest Cauliflower,CROPSANITY, +2308,Farming,Harvest Corn,CROPSANITY, +2309,Farming,Harvest Cranberries,CROPSANITY, +2310,Farming,Harvest Eggplant,CROPSANITY, +2311,Farming,Harvest Fairy Rose,CROPSANITY, +2312,Farming,Harvest Garlic,CROPSANITY, +2313,Farming,Harvest Grape,CROPSANITY, +2314,Farming,Harvest Green Bean,CROPSANITY, +2315,Farming,Harvest Hops,CROPSANITY, +2316,Farming,Harvest Hot Pepper,CROPSANITY, +2317,Farming,Harvest Kale,CROPSANITY, +2318,Farming,Harvest Melon,CROPSANITY, +2319,Farming,Harvest Parsnip,CROPSANITY, +2320,Farming,Harvest Poppy,CROPSANITY, +2321,Farming,Harvest Potato,CROPSANITY, +2322,Farming,Harvest Pumpkin,CROPSANITY, +2323,Farming,Harvest Radish,CROPSANITY, +2324,Farming,Harvest Red Cabbage,CROPSANITY, +2325,Farming,Harvest Rhubarb,CROPSANITY, +2326,Farming,Harvest Starfruit,CROPSANITY, +2327,Farming,Harvest Strawberry,CROPSANITY, +2328,Farming,Harvest Summer Spangle,CROPSANITY, +2329,Farming,Harvest Sunflower,CROPSANITY, +2330,Farming,Harvest Tomato,CROPSANITY, +2331,Farming,Harvest Tulip,CROPSANITY, +2332,Farming,Harvest Unmilled Rice,CROPSANITY, +2333,Farming,Harvest Wheat,CROPSANITY, +2334,Farming,Harvest Yam,CROPSANITY, +2335,Farming,Harvest Cactus Fruit,CROPSANITY, +2336,Farming,Harvest Pineapple,"CROPSANITY,GINGER_ISLAND", +2337,Farming,Harvest Taro Root,"CROPSANITY,GINGER_ISLAND", +2338,Farming,Harvest Sweet Gem Berry,CROPSANITY, +2339,Farming,Harvest Apple,CROPSANITY, +2340,Farming,Harvest Apricot,CROPSANITY, +2341,Farming,Harvest Cherry,CROPSANITY, +2342,Farming,Harvest Orange,CROPSANITY, +2343,Farming,Harvest Pomegranate,CROPSANITY, +2344,Farming,Harvest Peach,CROPSANITY, +2345,Farming,Harvest Banana,"CROPSANITY,GINGER_ISLAND", +2346,Farming,Harvest Mango,"CROPSANITY,GINGER_ISLAND", +2347,Farming,Harvest Coffee Bean,CROPSANITY, +2401,Shipping,Shipsanity: Duck Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2402,Shipping,Shipsanity: Duck Feather,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2403,Shipping,Shipsanity: Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2404,Shipping,Shipsanity: Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2405,Shipping,Shipsanity: Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2406,Shipping,Shipsanity: Large Goat Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2407,Shipping,Shipsanity: Large Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2408,Shipping,Shipsanity: Large Egg (Brown),"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2409,Shipping,Shipsanity: Large Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2410,Shipping,Shipsanity: Milk,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2411,Shipping,Shipsanity: Rabbit's Foot,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2412,Shipping,Shipsanity: Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2413,Shipping,Shipsanity: Truffle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2414,Shipping,Shipsanity: Void Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2415,Shipping,Shipsanity: Wool,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2416,Shipping,Shipsanity: Anchor,SHIPSANITY, +2417,Shipping,Shipsanity: Ancient Doll,SHIPSANITY, +2418,Shipping,Shipsanity: Ancient Drum,SHIPSANITY, +2419,Shipping,Shipsanity: Ancient Seed,SHIPSANITY, +2420,Shipping,Shipsanity: Ancient Sword,SHIPSANITY, +2421,Shipping,Shipsanity: Arrowhead,SHIPSANITY, +2422,Shipping,Shipsanity: Artifact Trove,SHIPSANITY, +2423,Shipping,Shipsanity: Bone Flute,SHIPSANITY, +2424,Shipping,Shipsanity: Chewing Stick,SHIPSANITY, +2425,Shipping,Shipsanity: Chicken Statue,SHIPSANITY, +2426,Shipping,Shipsanity: Chipped Amphora,SHIPSANITY, +2427,Shipping,Shipsanity: Dinosaur Egg,SHIPSANITY, +2428,Shipping,Shipsanity: Dried Starfish,SHIPSANITY, +2429,Shipping,Shipsanity: Dwarf Gadget,SHIPSANITY, +2430,Shipping,Shipsanity: Dwarf Scroll I,SHIPSANITY, +2431,Shipping,Shipsanity: Dwarf Scroll II,SHIPSANITY, +2432,Shipping,Shipsanity: Dwarf Scroll III,SHIPSANITY, +2433,Shipping,Shipsanity: Dwarf Scroll IV,SHIPSANITY, +2434,Shipping,Shipsanity: Dwarvish Helm,SHIPSANITY, +2435,Shipping,Shipsanity: Elvish Jewelry,SHIPSANITY, +2436,Shipping,Shipsanity: Glass Shards,SHIPSANITY, +2437,Shipping,Shipsanity: Golden Mask,SHIPSANITY, +2438,Shipping,Shipsanity: Golden Relic,SHIPSANITY, +2439,Shipping,Shipsanity: Ornamental Fan,SHIPSANITY, +2440,Shipping,Shipsanity: Prehistoric Handaxe,SHIPSANITY, +2441,Shipping,Shipsanity: Prehistoric Tool,SHIPSANITY, +2442,Shipping,Shipsanity: Rare Disc,SHIPSANITY, +2443,Shipping,Shipsanity: Rusty Cog,SHIPSANITY, +2444,Shipping,Shipsanity: Rusty Spoon,SHIPSANITY, +2445,Shipping,Shipsanity: Rusty Spur,SHIPSANITY, +2446,Shipping,Shipsanity: Strange Doll,SHIPSANITY, +2447,Shipping,Shipsanity: Strange Doll (Green),SHIPSANITY, +2448,Shipping,Shipsanity: Treasure Chest,SHIPSANITY, +2449,Shipping,Shipsanity: Aged Roe,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2450,Shipping,Shipsanity: Beer,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2451,Shipping,Shipsanity: Caviar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2452,Shipping,Shipsanity: Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2453,Shipping,Shipsanity: Cloth,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2454,Shipping,Shipsanity: Coffee,SHIPSANITY, +2455,Shipping,Shipsanity: Dinosaur Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2456,Shipping,Shipsanity: Duck Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2457,Shipping,Shipsanity: Goat Cheese,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2458,Shipping,Shipsanity: Green Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2459,Shipping,Shipsanity: Honey,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2460,Shipping,Shipsanity: Jelly,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2461,Shipping,Shipsanity: Juice,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2462,Shipping,Shipsanity: Maple Syrup,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2463,Shipping,Shipsanity: Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2464,Shipping,Shipsanity: Mead,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2465,Shipping,Shipsanity: Oak Resin,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2466,Shipping,Shipsanity: Pale Ale,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2467,Shipping,Shipsanity: Pickles,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2468,Shipping,Shipsanity: Pine Tar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2469,Shipping,Shipsanity: Truffle Oil,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2470,Shipping,Shipsanity: Void Mayonnaise,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2471,Shipping,Shipsanity: Wine,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2472,Shipping,Shipsanity: Algae Soup,SHIPSANITY, +2473,Shipping,Shipsanity: Artichoke Dip,SHIPSANITY, +2474,Shipping,Shipsanity: Autumn's Bounty,SHIPSANITY, +2475,Shipping,Shipsanity: Baked Fish,SHIPSANITY, +2476,Shipping,Shipsanity: Bean Hotpot,SHIPSANITY, +2477,Shipping,Shipsanity: Blackberry Cobbler,SHIPSANITY, +2478,Shipping,Shipsanity: Blueberry Tart,SHIPSANITY, +2479,Shipping,Shipsanity: Bread,SHIPSANITY, +2480,Shipping,Shipsanity: Bruschetta,SHIPSANITY, +2481,Shipping,Shipsanity: Carp Surprise,SHIPSANITY, +2482,Shipping,Shipsanity: Cheese Cauliflower,SHIPSANITY, +2483,Shipping,Shipsanity: Chocolate Cake,SHIPSANITY, +2484,Shipping,Shipsanity: Chowder,SHIPSANITY, +2485,Shipping,Shipsanity: Coleslaw,SHIPSANITY, +2486,Shipping,Shipsanity: Complete Breakfast,SHIPSANITY, +2487,Shipping,Shipsanity: Cookies,SHIPSANITY, +2488,Shipping,Shipsanity: Crab Cakes,SHIPSANITY, +2489,Shipping,Shipsanity: Cranberry Candy,SHIPSANITY, +2490,Shipping,Shipsanity: Cranberry Sauce,SHIPSANITY, +2491,Shipping,Shipsanity: Crispy Bass,SHIPSANITY, +2492,Shipping,Shipsanity: Dish O' The Sea,SHIPSANITY, +2493,Shipping,Shipsanity: Eggplant Parmesan,SHIPSANITY, +2494,Shipping,Shipsanity: Escargot,SHIPSANITY, +2495,Shipping,Shipsanity: Farmer's Lunch,SHIPSANITY, +2496,Shipping,Shipsanity: Fiddlehead Risotto,SHIPSANITY, +2497,Shipping,Shipsanity: Fish Stew,SHIPSANITY, +2498,Shipping,Shipsanity: Fish Taco,SHIPSANITY, +2499,Shipping,Shipsanity: Fried Calamari,SHIPSANITY, +2500,Shipping,Shipsanity: Fried Eel,SHIPSANITY, +2501,Shipping,Shipsanity: Fried Egg,SHIPSANITY, +2502,Shipping,Shipsanity: Fried Mushroom,SHIPSANITY, +2503,Shipping,Shipsanity: Fruit Salad,SHIPSANITY, +2504,Shipping,Shipsanity: Glazed Yams,SHIPSANITY, +2505,Shipping,Shipsanity: Hashbrowns,SHIPSANITY, +2506,Shipping,Shipsanity: Ice Cream,SHIPSANITY, +2507,Shipping,Shipsanity: Lobster Bisque,SHIPSANITY, +2508,Shipping,Shipsanity: Lucky Lunch,SHIPSANITY, +2509,Shipping,Shipsanity: Maki Roll,SHIPSANITY, +2510,Shipping,Shipsanity: Maple Bar,SHIPSANITY, +2511,Shipping,Shipsanity: Miner's Treat,SHIPSANITY, +2512,Shipping,Shipsanity: Omelet,SHIPSANITY, +2513,Shipping,Shipsanity: Pale Broth,SHIPSANITY, +2514,Shipping,Shipsanity: Pancakes,SHIPSANITY, +2515,Shipping,Shipsanity: Parsnip Soup,SHIPSANITY, +2516,Shipping,Shipsanity: Pepper Poppers,SHIPSANITY, +2517,Shipping,Shipsanity: Pink Cake,SHIPSANITY, +2518,Shipping,Shipsanity: Pizza,SHIPSANITY, +2519,Shipping,Shipsanity: Plum Pudding,SHIPSANITY, +2520,Shipping,Shipsanity: Poppyseed Muffin,SHIPSANITY, +2521,Shipping,Shipsanity: Pumpkin Pie,SHIPSANITY, +2522,Shipping,Shipsanity: Pumpkin Soup,SHIPSANITY, +2523,Shipping,Shipsanity: Radish Salad,SHIPSANITY, +2524,Shipping,Shipsanity: Red Plate,SHIPSANITY, +2525,Shipping,Shipsanity: Rhubarb Pie,SHIPSANITY, +2526,Shipping,Shipsanity: Rice Pudding,SHIPSANITY, +2527,Shipping,Shipsanity: Roasted Hazelnuts,SHIPSANITY, +2528,Shipping,Shipsanity: Roots Platter,SHIPSANITY, +2529,Shipping,Shipsanity: Salad,SHIPSANITY, +2530,Shipping,Shipsanity: Salmon Dinner,SHIPSANITY, +2531,Shipping,Shipsanity: Sashimi,SHIPSANITY, +2532,Shipping,Shipsanity: Seafoam Pudding,SHIPSANITY, +2533,Shipping,Shipsanity: Shrimp Cocktail,SHIPSANITY, +2534,Shipping,Shipsanity: Spaghetti,SHIPSANITY, +2535,Shipping,Shipsanity: Spicy Eel,SHIPSANITY, +2536,Shipping,Shipsanity: Squid Ink Ravioli,SHIPSANITY, +2537,Shipping,Shipsanity: Stir Fry,SHIPSANITY, +2538,Shipping,Shipsanity: Strange Bun,SHIPSANITY, +2539,Shipping,Shipsanity: Stuffing,SHIPSANITY, +2540,Shipping,Shipsanity: Super Meal,SHIPSANITY, +2541,Shipping,Shipsanity: Survival Burger,SHIPSANITY, +2542,Shipping,Shipsanity: Tom Kha Soup,SHIPSANITY, +2543,Shipping,Shipsanity: Tortilla,SHIPSANITY, +2544,Shipping,Shipsanity: Triple Shot Espresso,SHIPSANITY, +2545,Shipping,Shipsanity: Trout Soup,SHIPSANITY, +2546,Shipping,Shipsanity: Vegetable Medley,SHIPSANITY, +2547,Shipping,Shipsanity: Bait,SHIPSANITY, +2548,Shipping,Shipsanity: Barbed Hook,SHIPSANITY, +2549,Shipping,Shipsanity: Basic Fertilizer,SHIPSANITY, +2550,Shipping,Shipsanity: Basic Retaining Soil,SHIPSANITY, +2551,Shipping,Shipsanity: Blue Slime Egg,SHIPSANITY, +2552,Shipping,Shipsanity: Bomb,SHIPSANITY, +2553,Shipping,Shipsanity: Brick Floor,SHIPSANITY, +2554,Shipping,Shipsanity: Bug Steak,SHIPSANITY, +2555,Shipping,Shipsanity: Cherry Bomb,SHIPSANITY, +2556,Shipping,Shipsanity: Cobblestone Path,SHIPSANITY, +2557,Shipping,Shipsanity: Cookout Kit,SHIPSANITY, +2558,Shipping,Shipsanity: Cork Bobber,SHIPSANITY, +2559,Shipping,Shipsanity: Crab Pot,SHIPSANITY, +2560,Shipping,Shipsanity: Crystal Floor,SHIPSANITY, +2561,Shipping,Shipsanity: Crystal Path,SHIPSANITY, +2562,Shipping,Shipsanity: Deluxe Speed-Gro,SHIPSANITY, +2563,Shipping,Shipsanity: Dressed Spinner,SHIPSANITY, +2564,Shipping,Shipsanity: Drum Block,SHIPSANITY, +2565,Shipping,Shipsanity: Explosive Ammo,SHIPSANITY, +2566,Shipping,Shipsanity: Fiber Seeds,SHIPSANITY, +2567,Shipping,Shipsanity: Field Snack,SHIPSANITY, +2568,Shipping,Shipsanity: Flute Block,SHIPSANITY, +2569,Shipping,Shipsanity: Gate,SHIPSANITY, +2570,Shipping,Shipsanity: Gravel Path,SHIPSANITY, +2571,Shipping,Shipsanity: Green Slime Egg,SHIPSANITY, +2572,Shipping,Shipsanity: Hardwood Fence,SHIPSANITY, +2573,Shipping,Shipsanity: Iridium Sprinkler,SHIPSANITY, +2574,Shipping,Shipsanity: Iron Fence,SHIPSANITY, +2575,Shipping,Shipsanity: Jack-O-Lantern,SHIPSANITY, +2576,Shipping,Shipsanity: Lead Bobber,SHIPSANITY, +2577,Shipping,Shipsanity: Life Elixir,SHIPSANITY, +2578,Shipping,Shipsanity: Magnet,SHIPSANITY, +2579,Shipping,Shipsanity: Mega Bomb,SHIPSANITY, +2580,Shipping,Shipsanity: Monster Musk,SHIPSANITY, +2581,Shipping,Shipsanity: Oil of Garlic,SHIPSANITY, +2582,Shipping,Shipsanity: Purple Slime Egg,SHIPSANITY, +2583,Shipping,Shipsanity: Quality Bobber,SHIPSANITY, +2584,Shipping,Shipsanity: Quality Fertilizer,SHIPSANITY, +2585,Shipping,Shipsanity: Quality Retaining Soil,SHIPSANITY, +2586,Shipping,Shipsanity: Quality Sprinkler,SHIPSANITY, +2587,Shipping,Shipsanity: Rain Totem,SHIPSANITY, +2588,Shipping,Shipsanity: Red Slime Egg,SHIPSANITY, +2589,Shipping,Shipsanity: Rustic Plank Floor,SHIPSANITY, +2590,Shipping,Shipsanity: Speed-Gro,SHIPSANITY, +2591,Shipping,Shipsanity: Spinner,SHIPSANITY, +2592,Shipping,Shipsanity: Sprinkler,SHIPSANITY, +2593,Shipping,Shipsanity: Stepping Stone Path,SHIPSANITY, +2594,Shipping,Shipsanity: Stone Fence,SHIPSANITY, +2595,Shipping,Shipsanity: Stone Floor,SHIPSANITY, +2596,Shipping,Shipsanity: Stone Walkway Floor,SHIPSANITY, +2597,Shipping,Shipsanity: Straw Floor,SHIPSANITY, +2598,Shipping,Shipsanity: Torch,SHIPSANITY, +2599,Shipping,Shipsanity: Trap Bobber,SHIPSANITY, +2600,Shipping,Shipsanity: Treasure Hunter,SHIPSANITY, +2601,Shipping,Shipsanity: Tree Fertilizer,SHIPSANITY, +2602,Shipping,Shipsanity: Warp Totem: Beach,SHIPSANITY, +2603,Shipping,Shipsanity: Warp Totem: Desert,SHIPSANITY, +2604,Shipping,Shipsanity: Warp Totem: Farm,SHIPSANITY, +2605,Shipping,Shipsanity: Warp Totem: Island,"SHIPSANITY,GINGER_ISLAND", +2606,Shipping,Shipsanity: Warp Totem: Mountains,SHIPSANITY, +2607,Shipping,Shipsanity: Weathered Floor,SHIPSANITY, +2608,Shipping,Shipsanity: Wild Bait,SHIPSANITY, +2609,Shipping,Shipsanity: Wood Fence,SHIPSANITY, +2610,Shipping,Shipsanity: Wood Floor,SHIPSANITY, +2611,Shipping,Shipsanity: Wood Path,SHIPSANITY, +2612,Shipping,Shipsanity: Amaranth,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2613,Shipping,Shipsanity: Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2614,Shipping,Shipsanity: Apple,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2615,Shipping,Shipsanity: Apricot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2616,Shipping,Shipsanity: Artichoke,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2617,Shipping,Shipsanity: Beet,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2618,Shipping,Shipsanity: Blue Jazz,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2619,Shipping,Shipsanity: Blueberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2620,Shipping,Shipsanity: Bok Choy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2621,Shipping,Shipsanity: Cauliflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2622,Shipping,Shipsanity: Cherry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2623,Shipping,Shipsanity: Corn,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2624,Shipping,Shipsanity: Cranberries,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2625,Shipping,Shipsanity: Eggplant,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2626,Shipping,Shipsanity: Fairy Rose,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2627,Shipping,Shipsanity: Garlic,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2628,Shipping,Shipsanity: Grape,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2629,Shipping,Shipsanity: Green Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2630,Shipping,Shipsanity: Hops,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2631,Shipping,Shipsanity: Hot Pepper,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2632,Shipping,Shipsanity: Kale,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2633,Shipping,Shipsanity: Melon,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2634,Shipping,Shipsanity: Orange,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2635,Shipping,Shipsanity: Parsnip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2636,Shipping,Shipsanity: Peach,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2637,Shipping,Shipsanity: Pomegranate,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2638,Shipping,Shipsanity: Poppy,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2639,Shipping,Shipsanity: Potato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2640,Shipping,Shipsanity: Pumpkin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2641,Shipping,Shipsanity: Radish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2642,Shipping,Shipsanity: Red Cabbage,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2643,Shipping,Shipsanity: Rhubarb,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2644,Shipping,Shipsanity: Starfruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2645,Shipping,Shipsanity: Strawberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2646,Shipping,Shipsanity: Summer Spangle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2647,Shipping,Shipsanity: Sunflower,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2648,Shipping,Shipsanity: Sweet Gem Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2649,Shipping,Shipsanity: Tea Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2650,Shipping,Shipsanity: Tomato,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2651,Shipping,Shipsanity: Tulip,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2652,Shipping,Shipsanity: Unmilled Rice,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2653,Shipping,Shipsanity: Wheat,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2654,Shipping,Shipsanity: Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2655,Shipping,Shipsanity: Albacore,"SHIPSANITY,SHIPSANITY_FISH", +2656,Shipping,Shipsanity: Anchovy,"SHIPSANITY,SHIPSANITY_FISH", +2657,Shipping,Shipsanity: Angler,"SHIPSANITY,SHIPSANITY_FISH", +2658,Shipping,Shipsanity: Blobfish,"SHIPSANITY,SHIPSANITY_FISH", +2659,Shipping,Shipsanity: Bream,"SHIPSANITY,SHIPSANITY_FISH", +2660,Shipping,Shipsanity: Bullhead,"SHIPSANITY,SHIPSANITY_FISH", +2661,Shipping,Shipsanity: Carp,"SHIPSANITY,SHIPSANITY_FISH", +2662,Shipping,Shipsanity: Catfish,"SHIPSANITY,SHIPSANITY_FISH", +2663,Shipping,Shipsanity: Chub,"SHIPSANITY,SHIPSANITY_FISH", +2664,Shipping,Shipsanity: Cockle,"SHIPSANITY,SHIPSANITY_FISH", +2665,Shipping,Shipsanity: Crab,"SHIPSANITY,SHIPSANITY_FISH", +2666,Shipping,Shipsanity: Crayfish,"SHIPSANITY,SHIPSANITY_FISH", +2667,Shipping,Shipsanity: Crimsonfish,"SHIPSANITY,SHIPSANITY_FISH", +2668,Shipping,Shipsanity: Dorado,"SHIPSANITY,SHIPSANITY_FISH", +2669,Shipping,Shipsanity: Eel,"SHIPSANITY,SHIPSANITY_FISH", +2670,Shipping,Shipsanity: Flounder,"SHIPSANITY,SHIPSANITY_FISH", +2671,Shipping,Shipsanity: Ghostfish,"SHIPSANITY,SHIPSANITY_FISH", +2672,Shipping,Shipsanity: Glacierfish,"SHIPSANITY,SHIPSANITY_FISH", +2673,Shipping,Shipsanity: Halibut,"SHIPSANITY,SHIPSANITY_FISH", +2674,Shipping,Shipsanity: Herring,"SHIPSANITY,SHIPSANITY_FISH", +2675,Shipping,Shipsanity: Ice Pip,"SHIPSANITY,SHIPSANITY_FISH", +2676,Shipping,Shipsanity: Largemouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2677,Shipping,Shipsanity: Lava Eel,"SHIPSANITY,SHIPSANITY_FISH", +2678,Shipping,Shipsanity: Legend,"SHIPSANITY,SHIPSANITY_FISH", +2679,Shipping,Shipsanity: Lingcod,"SHIPSANITY,SHIPSANITY_FISH", +2680,Shipping,Shipsanity: Lobster,"SHIPSANITY,SHIPSANITY_FISH", +2681,Shipping,Shipsanity: Midnight Carp,"SHIPSANITY,SHIPSANITY_FISH", +2682,Shipping,Shipsanity: Midnight Squid,"SHIPSANITY,SHIPSANITY_FISH", +2683,Shipping,Shipsanity: Mussel,"SHIPSANITY,SHIPSANITY_FISH", +2684,Shipping,Shipsanity: Mutant Carp,"SHIPSANITY,SHIPSANITY_FISH", +2685,Shipping,Shipsanity: Octopus,"SHIPSANITY,SHIPSANITY_FISH", +2686,Shipping,Shipsanity: Oyster,"SHIPSANITY,SHIPSANITY_FISH", +2687,Shipping,Shipsanity: Perch,"SHIPSANITY,SHIPSANITY_FISH", +2688,Shipping,Shipsanity: Periwinkle,"SHIPSANITY,SHIPSANITY_FISH", +2689,Shipping,Shipsanity: Pike,"SHIPSANITY,SHIPSANITY_FISH", +2690,Shipping,Shipsanity: Pufferfish,"SHIPSANITY,SHIPSANITY_FISH", +2691,Shipping,Shipsanity: Rainbow Trout,"SHIPSANITY,SHIPSANITY_FISH", +2692,Shipping,Shipsanity: Red Mullet,"SHIPSANITY,SHIPSANITY_FISH", +2693,Shipping,Shipsanity: Red Snapper,"SHIPSANITY,SHIPSANITY_FISH", +2694,Shipping,Shipsanity: Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2695,Shipping,Shipsanity: Sandfish,"SHIPSANITY,SHIPSANITY_FISH", +2696,Shipping,Shipsanity: Sardine,"SHIPSANITY,SHIPSANITY_FISH", +2697,Shipping,Shipsanity: Scorpion Carp,"SHIPSANITY,SHIPSANITY_FISH", +2698,Shipping,Shipsanity: Sea Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2699,Shipping,Shipsanity: Shad,"SHIPSANITY,SHIPSANITY_FISH", +2700,Shipping,Shipsanity: Shrimp,"SHIPSANITY,SHIPSANITY_FISH", +2701,Shipping,Shipsanity: Slimejack,"SHIPSANITY,SHIPSANITY_FISH", +2702,Shipping,Shipsanity: Smallmouth Bass,"SHIPSANITY,SHIPSANITY_FISH", +2703,Shipping,Shipsanity: Snail,"SHIPSANITY,SHIPSANITY_FISH", +2704,Shipping,Shipsanity: Spook Fish,"SHIPSANITY,SHIPSANITY_FISH", +2705,Shipping,Shipsanity: Squid,"SHIPSANITY,SHIPSANITY_FISH", +2706,Shipping,Shipsanity: Stonefish,"SHIPSANITY,SHIPSANITY_FISH", +2707,Shipping,Shipsanity: Sturgeon,"SHIPSANITY,SHIPSANITY_FISH", +2708,Shipping,Shipsanity: Sunfish,"SHIPSANITY,SHIPSANITY_FISH", +2709,Shipping,Shipsanity: Super Cucumber,"SHIPSANITY,SHIPSANITY_FISH", +2710,Shipping,Shipsanity: Tiger Trout,"SHIPSANITY,SHIPSANITY_FISH", +2711,Shipping,Shipsanity: Tilapia,"SHIPSANITY,SHIPSANITY_FISH", +2712,Shipping,Shipsanity: Tuna,"SHIPSANITY,SHIPSANITY_FISH", +2713,Shipping,Shipsanity: Void Salmon,"SHIPSANITY,SHIPSANITY_FISH", +2714,Shipping,Shipsanity: Walleye,"SHIPSANITY,SHIPSANITY_FISH", +2715,Shipping,Shipsanity: Woodskip,"SHIPSANITY,SHIPSANITY_FISH", +2716,Shipping,Shipsanity: Blackberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2717,Shipping,Shipsanity: Cactus Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2718,Shipping,Shipsanity: Cave Carrot,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2719,Shipping,Shipsanity: Chanterelle,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2720,Shipping,Shipsanity: Clam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2721,Shipping,Shipsanity: Coconut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2722,Shipping,Shipsanity: Common Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2723,Shipping,Shipsanity: Coral,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2724,Shipping,Shipsanity: Crocus,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2725,Shipping,Shipsanity: Crystal Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2726,Shipping,Shipsanity: Daffodil,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2727,Shipping,Shipsanity: Dandelion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2728,Shipping,Shipsanity: Fiddlehead Fern,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2729,Shipping,Shipsanity: Hazelnut,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2730,Shipping,Shipsanity: Holly,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2731,Shipping,Shipsanity: Leek,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2732,Shipping,Shipsanity: Morel,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2733,Shipping,Shipsanity: Nautilus Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2734,Shipping,Shipsanity: Purple Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2735,Shipping,Shipsanity: Rainbow Shell,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2736,Shipping,Shipsanity: Red Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2737,Shipping,Shipsanity: Salmonberry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2738,Shipping,Shipsanity: Sea Urchin,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2739,Shipping,Shipsanity: Snow Yam,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2740,Shipping,Shipsanity: Spice Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2741,Shipping,Shipsanity: Spring Onion,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2742,Shipping,Shipsanity: Sweet Pea,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2743,Shipping,Shipsanity: Wild Horseradish,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2744,Shipping,Shipsanity: Wild Plum,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2745,Shipping,Shipsanity: Winter Root,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2746,Shipping,Shipsanity: Tea Set,SHIPSANITY, +2747,Shipping,Shipsanity: Battery Pack,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2748,Shipping,Shipsanity: Clay,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2749,Shipping,Shipsanity: Copper Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2750,Shipping,Shipsanity: Fiber,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2751,Shipping,Shipsanity: Gold Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2752,Shipping,Shipsanity: Hardwood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2753,Shipping,Shipsanity: Iridium Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2754,Shipping,Shipsanity: Iron Bar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2755,Shipping,Shipsanity: Oil,SHIPSANITY, +2756,Shipping,Shipsanity: Refined Quartz,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2757,Shipping,Shipsanity: Rice,SHIPSANITY, +2758,Shipping,Shipsanity: Sap,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2759,Shipping,Shipsanity: Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2760,Shipping,Shipsanity: Sugar,SHIPSANITY, +2761,Shipping,Shipsanity: Vinegar,SHIPSANITY, +2762,Shipping,Shipsanity: Wheat Flour,SHIPSANITY, +2763,Shipping,Shipsanity: Wood,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2764,Shipping,Shipsanity: Aerinite,SHIPSANITY, +2765,Shipping,Shipsanity: Alamite,SHIPSANITY, +2766,Shipping,Shipsanity: Amethyst,SHIPSANITY, +2767,Shipping,Shipsanity: Amphibian Fossil,SHIPSANITY, +2768,Shipping,Shipsanity: Aquamarine,SHIPSANITY, +2769,Shipping,Shipsanity: Baryte,SHIPSANITY, +2770,Shipping,Shipsanity: Basalt,SHIPSANITY, +2771,Shipping,Shipsanity: Bixite,SHIPSANITY, +2772,Shipping,Shipsanity: Calcite,SHIPSANITY, +2773,Shipping,Shipsanity: Celestine,SHIPSANITY, +2774,Shipping,Shipsanity: Coal,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2775,Shipping,Shipsanity: Copper Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2776,Shipping,Shipsanity: Diamond,SHIPSANITY, +2777,Shipping,Shipsanity: Dolomite,SHIPSANITY, +2778,Shipping,Shipsanity: Earth Crystal,SHIPSANITY, +2779,Shipping,Shipsanity: Emerald,SHIPSANITY, +2780,Shipping,Shipsanity: Esperite,SHIPSANITY, +2781,Shipping,Shipsanity: Fairy Stone,SHIPSANITY, +2782,Shipping,Shipsanity: Fire Opal,SHIPSANITY, +2783,Shipping,Shipsanity: Fire Quartz,SHIPSANITY, +2784,Shipping,Shipsanity: Fluorapatite,SHIPSANITY, +2785,Shipping,Shipsanity: Frozen Geode,SHIPSANITY, +2786,Shipping,Shipsanity: Frozen Tear,SHIPSANITY, +2787,Shipping,Shipsanity: Geminite,SHIPSANITY, +2788,Shipping,Shipsanity: Geode,SHIPSANITY, +2789,Shipping,Shipsanity: Ghost Crystal,SHIPSANITY, +2790,Shipping,Shipsanity: Gold Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2791,Shipping,Shipsanity: Granite,SHIPSANITY, +2792,Shipping,Shipsanity: Helvite,SHIPSANITY, +2793,Shipping,Shipsanity: Hematite,SHIPSANITY, +2794,Shipping,Shipsanity: Iridium Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2795,Shipping,Shipsanity: Iron Ore,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2796,Shipping,Shipsanity: Jade,SHIPSANITY, +2797,Shipping,Shipsanity: Jagoite,SHIPSANITY, +2798,Shipping,Shipsanity: Jamborite,SHIPSANITY, +2799,Shipping,Shipsanity: Jasper,SHIPSANITY, +2800,Shipping,Shipsanity: Kyanite,SHIPSANITY, +2801,Shipping,Shipsanity: Lemon Stone,SHIPSANITY, +2802,Shipping,Shipsanity: Limestone,SHIPSANITY, +2803,Shipping,Shipsanity: Lunarite,SHIPSANITY, +2804,Shipping,Shipsanity: Magma Geode,SHIPSANITY, +2805,Shipping,Shipsanity: Malachite,SHIPSANITY, +2806,Shipping,Shipsanity: Marble,SHIPSANITY, +2807,Shipping,Shipsanity: Mudstone,SHIPSANITY, +2808,Shipping,Shipsanity: Nautilus Fossil,SHIPSANITY, +2809,Shipping,Shipsanity: Nekoite,SHIPSANITY, +2810,Shipping,Shipsanity: Neptunite,SHIPSANITY, +2811,Shipping,Shipsanity: Obsidian,SHIPSANITY, +2812,Shipping,Shipsanity: Ocean Stone,SHIPSANITY, +2813,Shipping,Shipsanity: Omni Geode,SHIPSANITY, +2814,Shipping,Shipsanity: Opal,SHIPSANITY, +2815,Shipping,Shipsanity: Orpiment,SHIPSANITY, +2816,Shipping,Shipsanity: Palm Fossil,SHIPSANITY, +2817,Shipping,Shipsanity: Petrified Slime,SHIPSANITY, +2818,Shipping,Shipsanity: Prehistoric Rib,SHIPSANITY, +2819,Shipping,Shipsanity: Prehistoric Scapula,SHIPSANITY, +2820,Shipping,Shipsanity: Prehistoric Skull,SHIPSANITY, +2821,Shipping,Shipsanity: Prehistoric Tibia,SHIPSANITY, +2822,Shipping,Shipsanity: Prehistoric Vertebra,SHIPSANITY, +2823,Shipping,Shipsanity: Prismatic Shard,SHIPSANITY, +2824,Shipping,Shipsanity: Pyrite,SHIPSANITY, +2825,Shipping,Shipsanity: Quartz,SHIPSANITY, +2826,Shipping,Shipsanity: Ruby,SHIPSANITY, +2827,Shipping,Shipsanity: Sandstone,SHIPSANITY, +2828,Shipping,Shipsanity: Skeletal Hand,SHIPSANITY, +2829,Shipping,Shipsanity: Skeletal Tail,SHIPSANITY, +2830,Shipping,Shipsanity: Slate,SHIPSANITY, +2831,Shipping,Shipsanity: Soapstone,SHIPSANITY, +2832,Shipping,Shipsanity: Star Shards,SHIPSANITY, +2833,Shipping,Shipsanity: Thunder Egg,SHIPSANITY, +2834,Shipping,Shipsanity: Tigerseye,SHIPSANITY, +2835,Shipping,Shipsanity: Topaz,SHIPSANITY, +2836,Shipping,Shipsanity: Trilobite,SHIPSANITY, +2837,Shipping,Shipsanity: Bat Wing,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2838,Shipping,Shipsanity: Bone Fragment,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2839,Shipping,Shipsanity: Curiosity Lure,SHIPSANITY, +2840,Shipping,Shipsanity: Slime,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2841,Shipping,Shipsanity: Solar Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2842,Shipping,Shipsanity: Squid Ink,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2843,Shipping,Shipsanity: Void Essence,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2844,Shipping,Shipsanity: Bouquet,SHIPSANITY, +2845,Shipping,Shipsanity: Energy Tonic,SHIPSANITY, +2846,Shipping,Shipsanity: Golden Pumpkin,SHIPSANITY, +2847,Shipping,Shipsanity: Green Algae,SHIPSANITY, +2848,Shipping,Shipsanity: Hay,SHIPSANITY, +2849,Shipping,Shipsanity: Magic Rock Candy,SHIPSANITY, +2850,Shipping,Shipsanity: Muscle Remedy,SHIPSANITY, +2851,Shipping,Shipsanity: Pearl,SHIPSANITY, +2852,Shipping,Shipsanity: Rotten Plant,SHIPSANITY, +2853,Shipping,Shipsanity: Seaweed,SHIPSANITY, +2854,Shipping,Shipsanity: Void Ghost Pendant,SHIPSANITY, +2855,Shipping,Shipsanity: White Algae,SHIPSANITY, +2856,Shipping,Shipsanity: Wilted Bouquet,SHIPSANITY, +2857,Shipping,Shipsanity: Secret Note,SHIPSANITY, +2858,Shipping,Shipsanity: Acorn,SHIPSANITY, +2859,Shipping,Shipsanity: Amaranth Seeds,SHIPSANITY, +2860,Shipping,Shipsanity: Ancient Seeds,SHIPSANITY, +2861,Shipping,Shipsanity: Apple Sapling,SHIPSANITY, +2862,Shipping,Shipsanity: Apricot Sapling,SHIPSANITY, +2863,Shipping,Shipsanity: Artichoke Seeds,SHIPSANITY, +2864,Shipping,Shipsanity: Bean Starter,SHIPSANITY, +2865,Shipping,Shipsanity: Beet Seeds,SHIPSANITY, +2866,Shipping,Shipsanity: Blueberry Seeds,SHIPSANITY, +2867,Shipping,Shipsanity: Bok Choy Seeds,SHIPSANITY, +2868,Shipping,Shipsanity: Cactus Seeds,SHIPSANITY, +2869,Shipping,Shipsanity: Cauliflower Seeds,SHIPSANITY, +2870,Shipping,Shipsanity: Cherry Sapling,SHIPSANITY, +2871,Shipping,Shipsanity: Coffee Bean,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2872,Shipping,Shipsanity: Corn Seeds,SHIPSANITY, +2873,Shipping,Shipsanity: Cranberry Seeds,SHIPSANITY, +2874,Shipping,Shipsanity: Eggplant Seeds,SHIPSANITY, +2875,Shipping,Shipsanity: Fairy Seeds,SHIPSANITY, +2876,Shipping,Shipsanity: Fall Seeds,SHIPSANITY, +2877,Shipping,Shipsanity: Garlic Seeds,SHIPSANITY, +2878,Shipping,Shipsanity: Grape Starter,SHIPSANITY, +2879,Shipping,Shipsanity: Grass Starter,SHIPSANITY, +2880,Shipping,Shipsanity: Hops Starter,SHIPSANITY, +2881,Shipping,Shipsanity: Jazz Seeds,SHIPSANITY, +2882,Shipping,Shipsanity: Kale Seeds,SHIPSANITY, +2883,Shipping,Shipsanity: Mahogany Seed,SHIPSANITY, +2884,Shipping,Shipsanity: Maple Seed,SHIPSANITY, +2885,Shipping,Shipsanity: Melon Seeds,SHIPSANITY, +2886,Shipping,Shipsanity: Mixed Seeds,SHIPSANITY, +2887,Shipping,Shipsanity: Orange Sapling,SHIPSANITY, +2888,Shipping,Shipsanity: Parsnip Seeds,SHIPSANITY, +2889,Shipping,Shipsanity: Peach Sapling,SHIPSANITY, +2890,Shipping,Shipsanity: Pepper Seeds,SHIPSANITY, +2891,Shipping,Shipsanity: Pine Cone,SHIPSANITY, +2892,Shipping,Shipsanity: Pomegranate Sapling,SHIPSANITY, +2893,Shipping,Shipsanity: Poppy Seeds,SHIPSANITY, +2894,Shipping,Shipsanity: Potato Seeds,SHIPSANITY, +2895,Shipping,Shipsanity: Pumpkin Seeds,SHIPSANITY, +2896,Shipping,Shipsanity: Radish Seeds,SHIPSANITY, +2897,Shipping,Shipsanity: Rare Seed,SHIPSANITY, +2898,Shipping,Shipsanity: Red Cabbage Seeds,SHIPSANITY, +2899,Shipping,Shipsanity: Rhubarb Seeds,SHIPSANITY, +2900,Shipping,Shipsanity: Rice Shoot,SHIPSANITY, +2901,Shipping,Shipsanity: Spangle Seeds,SHIPSANITY, +2902,Shipping,Shipsanity: Spring Seeds,SHIPSANITY, +2903,Shipping,Shipsanity: Starfruit Seeds,SHIPSANITY, +2904,Shipping,Shipsanity: Strawberry Seeds,SHIPSANITY, +2905,Shipping,Shipsanity: Summer Seeds,SHIPSANITY, +2906,Shipping,Shipsanity: Sunflower Seeds,SHIPSANITY, +2907,Shipping,Shipsanity: Tea Sapling,SHIPSANITY, +2908,Shipping,Shipsanity: Tomato Seeds,SHIPSANITY, +2909,Shipping,Shipsanity: Tulip Bulb,SHIPSANITY, +2910,Shipping,Shipsanity: Wheat Seeds,SHIPSANITY, +2911,Shipping,Shipsanity: Winter Seeds,SHIPSANITY, +2912,Shipping,Shipsanity: Yam Seeds,SHIPSANITY, +2913,Shipping,Shipsanity: Broken CD,SHIPSANITY, +2914,Shipping,Shipsanity: Broken Glasses,SHIPSANITY, +2915,Shipping,Shipsanity: Driftwood,SHIPSANITY, +2916,Shipping,Shipsanity: Joja Cola,SHIPSANITY, +2917,Shipping,Shipsanity: Soggy Newspaper,SHIPSANITY, +2918,Shipping,Shipsanity: Trash,SHIPSANITY, +2919,Shipping,Shipsanity: Bug Meat,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2920,Shipping,Shipsanity: Golden Egg,SHIPSANITY, +2921,Shipping,Shipsanity: Ostrich Egg,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2922,Shipping,Shipsanity: Fossilized Leg,"GINGER_ISLAND,SHIPSANITY", +2923,Shipping,Shipsanity: Fossilized Ribs,"GINGER_ISLAND,SHIPSANITY", +2924,Shipping,Shipsanity: Fossilized Skull,"GINGER_ISLAND,SHIPSANITY", +2925,Shipping,Shipsanity: Fossilized Spine,"GINGER_ISLAND,SHIPSANITY", +2926,Shipping,Shipsanity: Fossilized Tail,"GINGER_ISLAND,SHIPSANITY", +2927,Shipping,Shipsanity: Mummified Bat,"GINGER_ISLAND,SHIPSANITY", +2928,Shipping,Shipsanity: Mummified Frog,"GINGER_ISLAND,SHIPSANITY", +2929,Shipping,Shipsanity: Snake Skull,"GINGER_ISLAND,SHIPSANITY", +2930,Shipping,Shipsanity: Snake Vertebrae,"GINGER_ISLAND,SHIPSANITY", +2931,Shipping,Shipsanity: Banana Pudding,"GINGER_ISLAND,SHIPSANITY", +2932,Shipping,Shipsanity: Ginger Ale,"GINGER_ISLAND,SHIPSANITY", +2933,Shipping,Shipsanity: Mango Sticky Rice,"GINGER_ISLAND,SHIPSANITY", +2934,Shipping,Shipsanity: Pina Colada,"GINGER_ISLAND,SHIPSANITY", +2935,Shipping,Shipsanity: Poi,"GINGER_ISLAND,SHIPSANITY", +2936,Shipping,Shipsanity: Tropical Curry,"GINGER_ISLAND,SHIPSANITY", +2937,Shipping,Shipsanity: Deluxe Fertilizer,"GINGER_ISLAND,SHIPSANITY", +2938,Shipping,Shipsanity: Deluxe Retaining Soil,"GINGER_ISLAND,SHIPSANITY", +2939,Shipping,Shipsanity: Fairy Dust,"GINGER_ISLAND,SHIPSANITY", +2940,Shipping,Shipsanity: Hyper Speed-Gro,"GINGER_ISLAND,SHIPSANITY", +2941,Shipping,Shipsanity: Magic Bait,"GINGER_ISLAND,SHIPSANITY", +2942,Shipping,Shipsanity: Banana,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2943,Shipping,Shipsanity: Mango,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2944,Shipping,Shipsanity: Pineapple,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2945,Shipping,Shipsanity: Qi Fruit,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,REQUIRES_QI_ORDERS", +2946,Shipping,Shipsanity: Taro Root,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2947,Shipping,Shipsanity: Blue Discus,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2948,Shipping,Shipsanity: Glacierfish Jr.,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2949,Shipping,Shipsanity: Legend II,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2950,Shipping,Shipsanity: Lionfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2951,Shipping,Shipsanity: Ms. Angler,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2952,Shipping,Shipsanity: Radioactive Carp,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2953,Shipping,Shipsanity: Son of Crimsonfish,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH,REQUIRES_QI_ORDERS", +2954,Shipping,Shipsanity: Stingray,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FISH", +2955,Shipping,Shipsanity: Ginger,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2956,Shipping,Shipsanity: Magma Cap,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT", +2957,Shipping,Shipsanity: Cinder Shard,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT", +2958,Shipping,Shipsanity: Dragon Tooth,"GINGER_ISLAND,SHIPSANITY", +2959,Shipping,Shipsanity: Qi Seasoning,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2960,Shipping,Shipsanity: Radioactive Bar,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2961,Shipping,Shipsanity: Radioactive Ore,"GINGER_ISLAND,SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,REQUIRES_QI_ORDERS", +2962,Shipping,Shipsanity: Enricher,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2963,Shipping,Shipsanity: Pressure Nozzle,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2964,Shipping,Shipsanity: Galaxy Soul,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2965,Shipping,Shipsanity: Tiger Slime Egg,"GINGER_ISLAND,SHIPSANITY", +2966,Shipping,Shipsanity: Movie Ticket,"SHIPSANITY", +2967,Shipping,Shipsanity: Journal Scrap,"GINGER_ISLAND,SHIPSANITY", +2968,Shipping,Shipsanity: Banana Sapling,"GINGER_ISLAND,SHIPSANITY", +2969,Shipping,Shipsanity: Mango Sapling,"GINGER_ISLAND,SHIPSANITY", +2970,Shipping,Shipsanity: Mushroom Tree Seed,"GINGER_ISLAND,SHIPSANITY,REQUIRES_QI_ORDERS", +2971,Shipping,Shipsanity: Pineapple Seeds,"GINGER_ISLAND,SHIPSANITY", +2972,Shipping,Shipsanity: Qi Bean,"GINGER_ISLAND,SHIPSANITY", +2973,Shipping,Shipsanity: Taro Tuber,"GINGER_ISLAND,SHIPSANITY", +3001,Adventurer's Guild,Monster Eradication: Slimes,"MONSTERSANITY,MONSTERSANITY_GOALS", +3002,Adventurer's Guild,Monster Eradication: Void Spirits,"MONSTERSANITY,MONSTERSANITY_GOALS", +3003,Adventurer's Guild,Monster Eradication: Bats,"MONSTERSANITY,MONSTERSANITY_GOALS", +3004,Adventurer's Guild,Monster Eradication: Skeletons,"MONSTERSANITY,MONSTERSANITY_GOALS", +3005,Adventurer's Guild,Monster Eradication: Cave Insects,"MONSTERSANITY,MONSTERSANITY_GOALS", +3006,Adventurer's Guild,Monster Eradication: Duggies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3007,Adventurer's Guild,Monster Eradication: Dust Sprites,"MONSTERSANITY,MONSTERSANITY_GOALS", +3008,Adventurer's Guild,Monster Eradication: Rock Crabs,"MONSTERSANITY,MONSTERSANITY_GOALS", +3009,Adventurer's Guild,Monster Eradication: Mummies,"MONSTERSANITY,MONSTERSANITY_GOALS", +3010,Adventurer's Guild,Monster Eradication: Pepper Rex,"MONSTERSANITY,MONSTERSANITY_GOALS,MONSTERSANITY_MONSTER", +3011,Adventurer's Guild,Monster Eradication: Serpents,"MONSTERSANITY,MONSTERSANITY_GOALS", +3012,Adventurer's Guild,Monster Eradication: Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_GOALS", +3020,Adventurer's Guild,Monster Eradication: 200 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3021,Adventurer's Guild,Monster Eradication: 400 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3022,Adventurer's Guild,Monster Eradication: 600 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3023,Adventurer's Guild,Monster Eradication: 800 Slimes,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3024,Adventurer's Guild,Monster Eradication: 30 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3025,Adventurer's Guild,Monster Eradication: 60 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3026,Adventurer's Guild,Monster Eradication: 90 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3027,Adventurer's Guild,Monster Eradication: 120 Void Spirits,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3028,Adventurer's Guild,Monster Eradication: 40 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3029,Adventurer's Guild,Monster Eradication: 80 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3030,Adventurer's Guild,Monster Eradication: 120 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3031,Adventurer's Guild,Monster Eradication: 160 Bats,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3032,Adventurer's Guild,Monster Eradication: 10 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3033,Adventurer's Guild,Monster Eradication: 20 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3034,Adventurer's Guild,Monster Eradication: 30 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3035,Adventurer's Guild,Monster Eradication: 40 Skeletons,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3036,Adventurer's Guild,Monster Eradication: 25 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3037,Adventurer's Guild,Monster Eradication: 50 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3038,Adventurer's Guild,Monster Eradication: 75 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3039,Adventurer's Guild,Monster Eradication: 100 Cave Insects,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3040,Adventurer's Guild,Monster Eradication: 6 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3041,Adventurer's Guild,Monster Eradication: 12 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3042,Adventurer's Guild,Monster Eradication: 18 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3043,Adventurer's Guild,Monster Eradication: 24 Duggies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3044,Adventurer's Guild,Monster Eradication: 100 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3045,Adventurer's Guild,Monster Eradication: 200 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3046,Adventurer's Guild,Monster Eradication: 300 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3047,Adventurer's Guild,Monster Eradication: 400 Dust Sprites,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3048,Adventurer's Guild,Monster Eradication: 12 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3049,Adventurer's Guild,Monster Eradication: 24 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3050,Adventurer's Guild,Monster Eradication: 36 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3051,Adventurer's Guild,Monster Eradication: 48 Rock Crabs,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3052,Adventurer's Guild,Monster Eradication: 20 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3053,Adventurer's Guild,Monster Eradication: 40 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3054,Adventurer's Guild,Monster Eradication: 60 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3055,Adventurer's Guild,Monster Eradication: 80 Mummies,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3056,Adventurer's Guild,Monster Eradication: 10 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3057,Adventurer's Guild,Monster Eradication: 20 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3058,Adventurer's Guild,Monster Eradication: 30 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3059,Adventurer's Guild,Monster Eradication: 40 Pepper Rex,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3060,Adventurer's Guild,Monster Eradication: 50 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3061,Adventurer's Guild,Monster Eradication: 100 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3062,Adventurer's Guild,Monster Eradication: 150 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3063,Adventurer's Guild,Monster Eradication: 200 Serpents,"MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3064,Adventurer's Guild,Monster Eradication: 30 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3065,Adventurer's Guild,Monster Eradication: 60 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3066,Adventurer's Guild,Monster Eradication: 90 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3067,Adventurer's Guild,Monster Eradication: 120 Magma Sprites,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_PROGRESSIVE_GOALS", +3101,Adventurer's Guild,Monster Eradication: Green Slime,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3102,Adventurer's Guild,Monster Eradication: Frost Jelly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3103,Adventurer's Guild,Monster Eradication: Sludge,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3104,Adventurer's Guild,Monster Eradication: Tiger Slime,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3105,Adventurer's Guild,Monster Eradication: Shadow Shaman,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3106,Adventurer's Guild,Monster Eradication: Shadow Brute,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3107,Adventurer's Guild,Monster Eradication: Shadow Sniper,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3108,Adventurer's Guild,Monster Eradication: Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3109,Adventurer's Guild,Monster Eradication: Frost Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3110,Adventurer's Guild,Monster Eradication: Lava Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3111,Adventurer's Guild,Monster Eradication: Iridium Bat,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3112,Adventurer's Guild,Monster Eradication: Skeleton,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3113,Adventurer's Guild,Monster Eradication: Skeleton Mage,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3114,Adventurer's Guild,Monster Eradication: Bug,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3115,Adventurer's Guild,Monster Eradication: Fly,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3116,Adventurer's Guild,Monster Eradication: Grub,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3117,Adventurer's Guild,Monster Eradication: Duggy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3118,Adventurer's Guild,Monster Eradication: Magma Duggy,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3119,Adventurer's Guild,Monster Eradication: Dust Sprite,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3120,Adventurer's Guild,Monster Eradication: Rock Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3121,Adventurer's Guild,Monster Eradication: Lava Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3122,Adventurer's Guild,Monster Eradication: Iridium Crab,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3123,Adventurer's Guild,Monster Eradication: Mummy,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3124,Adventurer's Guild,Monster Eradication: Serpent,"MONSTERSANITY,MONSTERSANITY_MONSTER", +3125,Adventurer's Guild,Monster Eradication: Royal Serpent,"GINGER_ISLAND,REQUIRES_QI_ORDERS,MONSTERSANITY,MONSTERSANITY_MONSTER", +3126,Adventurer's Guild,Monster Eradication: Magma Sprite,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3127,Adventurer's Guild,Monster Eradication: Magma Sparker,"GINGER_ISLAND,MONSTERSANITY,MONSTERSANITY_MONSTER", +3201,Kitchen,Cook Algae Soup,COOKSANITY, +3202,Kitchen,Cook Artichoke Dip,"COOKSANITY,COOKSANITY_QOS", +3203,Kitchen,Cook Autumn's Bounty,COOKSANITY, +3204,Kitchen,Cook Baked Fish,"COOKSANITY,COOKSANITY_QOS", +3205,Kitchen,Cook Banana Pudding,"COOKSANITY,GINGER_ISLAND", +3206,Kitchen,Cook Bean Hotpot,COOKSANITY, +3207,Kitchen,Cook Blackberry Cobbler,"COOKSANITY,COOKSANITY_QOS", +3208,Kitchen,Cook Blueberry Tart,COOKSANITY, +3209,Kitchen,Cook Bread,"COOKSANITY,COOKSANITY_QOS", +3210,Kitchen,Cook Bruschetta,"COOKSANITY,COOKSANITY_QOS", +3211,Kitchen,Cook Carp Surprise,"COOKSANITY,COOKSANITY_QOS", +3212,Kitchen,Cook Cheese Cauliflower,COOKSANITY, +3213,Kitchen,Cook Chocolate Cake,"COOKSANITY,COOKSANITY_QOS", +3214,Kitchen,Cook Chowder,COOKSANITY, +3215,Kitchen,Cook Coleslaw,"COOKSANITY,COOKSANITY_QOS", +3216,Kitchen,Cook Complete Breakfast,"COOKSANITY,COOKSANITY_QOS", +3217,Kitchen,Cook Cookies,COOKSANITY, +3218,Kitchen,Cook Crab Cakes,"COOKSANITY,COOKSANITY_QOS", +3219,Kitchen,Cook Cranberry Candy,"COOKSANITY,COOKSANITY_QOS", +3220,Kitchen,Cook Cranberry Sauce,COOKSANITY, +3221,Kitchen,Cook Crispy Bass,COOKSANITY, +3222,Kitchen,Cook Dish O' The Sea,COOKSANITY, +3223,Kitchen,Cook Eggplant Parmesan,COOKSANITY, +3224,Kitchen,Cook Escargot,COOKSANITY, +3225,Kitchen,Cook Farmer's Lunch,COOKSANITY, +3226,Kitchen,Cook Fiddlehead Risotto,"COOKSANITY,COOKSANITY_QOS", +3227,Kitchen,Cook Fish Stew,COOKSANITY, +3228,Kitchen,Cook Fish Taco,COOKSANITY, +3229,Kitchen,Cook Fried Calamari,COOKSANITY, +3230,Kitchen,Cook Fried Eel,COOKSANITY, +3231,Kitchen,Cook Fried Egg,COOKSANITY, +3232,Kitchen,Cook Fried Mushroom,COOKSANITY, +3233,Kitchen,Cook Fruit Salad,"COOKSANITY,COOKSANITY_QOS", +3234,Kitchen,Cook Ginger Ale,"COOKSANITY,GINGER_ISLAND", +3235,Kitchen,Cook Glazed Yams,"COOKSANITY,COOKSANITY_QOS", +3236,Kitchen,Cook Hashbrowns,"COOKSANITY,COOKSANITY_QOS", +3237,Kitchen,Cook Ice Cream,COOKSANITY, +3238,Kitchen,Cook Lobster Bisque,"COOKSANITY,COOKSANITY_QOS", +3239,Kitchen,Cook Lucky Lunch,"COOKSANITY,COOKSANITY_QOS", +3240,Kitchen,Cook Maki Roll,"COOKSANITY,COOKSANITY_QOS", +3241,Kitchen,Cook Mango Sticky Rice,"COOKSANITY,GINGER_ISLAND", +3242,Kitchen,Cook Maple Bar,"COOKSANITY,COOKSANITY_QOS", +3243,Kitchen,Cook Miner's Treat,COOKSANITY, +3244,Kitchen,Cook Omelet,"COOKSANITY,COOKSANITY_QOS", +3245,Kitchen,Cook Pale Broth,COOKSANITY, +3246,Kitchen,Cook Pancakes,"COOKSANITY,COOKSANITY_QOS", +3247,Kitchen,Cook Parsnip Soup,COOKSANITY, +3248,Kitchen,Cook Pepper Poppers,COOKSANITY, +3249,Kitchen,Cook Pink Cake,"COOKSANITY,COOKSANITY_QOS", +3250,Kitchen,Cook Pizza,"COOKSANITY,COOKSANITY_QOS", +3251,Kitchen,Cook Plum Pudding,"COOKSANITY,COOKSANITY_QOS", +3252,Kitchen,Cook Poi,"COOKSANITY,GINGER_ISLAND", +3253,Kitchen,Cook Poppyseed Muffin,"COOKSANITY,COOKSANITY_QOS", +3254,Kitchen,Cook Pumpkin Pie,"COOKSANITY,COOKSANITY_QOS", +3255,Kitchen,Cook Pumpkin Soup,COOKSANITY, +3256,Kitchen,Cook Radish Salad,"COOKSANITY,COOKSANITY_QOS", +3257,Kitchen,Cook Red Plate,COOKSANITY, +3258,Kitchen,Cook Rhubarb Pie,COOKSANITY, +3259,Kitchen,Cook Rice Pudding,COOKSANITY, +3260,Kitchen,Cook Roasted Hazelnuts,"COOKSANITY,COOKSANITY_QOS", +3261,Kitchen,Cook Roots Platter,COOKSANITY, +3262,Kitchen,Cook Salad,COOKSANITY, +3263,Kitchen,Cook Salmon Dinner,COOKSANITY, +3264,Kitchen,Cook Sashimi,COOKSANITY, +3265,Kitchen,Cook Seafoam Pudding,COOKSANITY, +3266,Kitchen,Cook Shrimp Cocktail,"COOKSANITY,COOKSANITY_QOS", +3267,Kitchen,Cook Spaghetti,COOKSANITY, +3268,Kitchen,Cook Spicy Eel,COOKSANITY, +3269,Kitchen,Cook Squid Ink Ravioli,COOKSANITY, +3270,Kitchen,Cook Stir Fry,"COOKSANITY,COOKSANITY_QOS", +3271,Kitchen,Cook Strange Bun,COOKSANITY, +3272,Kitchen,Cook Stuffing,COOKSANITY, +3273,Kitchen,Cook Super Meal,COOKSANITY, +3274,Kitchen,Cook Survival Burger,COOKSANITY, +3275,Kitchen,Cook Tom Kha Soup,COOKSANITY, +3276,Kitchen,Cook Tortilla,"COOKSANITY,COOKSANITY_QOS", +3277,Kitchen,Cook Triple Shot Espresso,COOKSANITY, +3278,Kitchen,Cook Tropical Curry,"COOKSANITY,GINGER_ISLAND", +3279,Kitchen,Cook Trout Soup,"COOKSANITY,COOKSANITY_QOS", +3280,Kitchen,Cook Vegetable Medley,COOKSANITY, +3301,Farm,Algae Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3302,The Queen of Sauce,Artichoke Dip Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3303,Farm,Autumn's Bounty Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3304,The Queen of Sauce,Baked Fish Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3305,Farm,Banana Pudding Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3306,Farm,Bean Hotpot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3307,The Queen of Sauce,Blackberry Cobbler Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3308,Farm,Blueberry Tart Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3309,The Queen of Sauce,Bread Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP,CHEFSANITY_PURCHASE", +3310,The Queen of Sauce,Bruschetta Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3311,The Queen of Sauce,Carp Surprise Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3312,Farm,Cheese Cauliflower Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3313,The Queen of Sauce,Chocolate Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3314,Farm,Chowder Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3315,The Queen of Sauce,Coleslaw Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3316,The Queen of Sauce,Complete Breakfast Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3317,Farm,Cookies Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3318,The Queen of Sauce,Crab Cakes Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3319,The Queen of Sauce,Cranberry Candy Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3320,Farm,Cranberry Sauce Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3321,Farm,Crispy Bass Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3322,Farm,Dish O' The Sea Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3323,Farm,Eggplant Parmesan Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3324,Farm,Escargot Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3325,Farm,Farmer's Lunch Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3326,The Queen of Sauce,Fiddlehead Risotto Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3327,Farm,Fish Stew Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3328,Farm,Fish Taco Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3329,Farm,Fried Calamari Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3330,Farm,Fried Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3331,Farm,Fried Egg Recipe,CHEFSANITY_STARTER, +3332,Farm,Fried Mushroom Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3333,The Queen of Sauce,Fruit Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3334,Farm,Ginger Ale Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3335,The Queen of Sauce,Glazed Yams Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3336,The Queen of Sauce,Hashbrowns Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3337,Farm,Ice Cream Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3338,The Queen of Sauce,Lobster Bisque Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_FRIENDSHIP", +3339,The Queen of Sauce,Lucky Lunch Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3340,The Queen of Sauce,Maki Roll Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3341,Farm,Mango Sticky Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3342,The Queen of Sauce,Maple Bar Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3343,Farm,Miner's Treat Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3344,The Queen of Sauce,Omelet Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3345,Farm,Pale Broth Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3346,The Queen of Sauce,Pancakes Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3347,Farm,Parsnip Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3348,Farm,Pepper Poppers Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3349,The Queen of Sauce,Pink Cake Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3350,The Queen of Sauce,Pizza Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3351,The Queen of Sauce,Plum Pudding Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3352,Farm,Poi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP,GINGER_ISLAND", +3353,The Queen of Sauce,Poppyseed Muffin Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3354,The Queen of Sauce,Pumpkin Pie Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3355,Farm,Pumpkin Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3356,The Queen of Sauce,Radish Salad Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3357,Farm,Red Plate Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3358,Farm,Rhubarb Pie Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3359,Farm,Rice Pudding Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3360,The Queen of Sauce,Roasted Hazelnuts Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3361,Farm,Roots Platter Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3362,Farm,Salad Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3363,Farm,Salmon Dinner Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3364,Farm,Sashimi Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3365,Farm,Seafoam Pudding Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3366,The Queen of Sauce,Shrimp Cocktail Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3367,Farm,Spaghetti Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3368,Farm,Spicy Eel Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3369,Farm,Squid Ink Ravioli Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3370,The Queen of Sauce,Stir Fry Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3371,Farm,Strange Bun Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3372,Farm,Stuffing Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3373,Farm,Super Meal Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3374,Farm,Survival Burger Recipe,"CHEFSANITY,CHEFSANITY_SKILL", +3375,Farm,Tom Kha Soup Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3376,The Queen of Sauce,Tortilla Recipe,"CHEFSANITY,CHEFSANITY_QOS,CHEFSANITY_PURCHASE", +3377,Saloon,Triple Shot Espresso Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE", +3378,Island Resort,Tropical Curry Recipe,"CHEFSANITY,GINGER_ISLAND,CHEFSANITY_PURCHASE", +3379,The Queen of Sauce,Trout Soup Recipe,"CHEFSANITY,CHEFSANITY_QOS", +3380,Farm,Vegetable Medley Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP", +3401,Farm,Craft Cherry Bomb,CRAFTSANITY, +3402,Farm,Craft Bomb,CRAFTSANITY, +3403,Farm,Craft Mega Bomb,CRAFTSANITY, +3404,Farm,Craft Gate,CRAFTSANITY, +3405,Farm,Craft Wood Fence,CRAFTSANITY, +3406,Farm,Craft Stone Fence,CRAFTSANITY, +3407,Farm,Craft Iron Fence,CRAFTSANITY, +3408,Farm,Craft Hardwood Fence,CRAFTSANITY, +3409,Farm,Craft Sprinkler,CRAFTSANITY, +3410,Farm,Craft Quality Sprinkler,CRAFTSANITY, +3411,Farm,Craft Iridium Sprinkler,CRAFTSANITY, +3412,Farm,Craft Bee House,CRAFTSANITY, +3413,Farm,Craft Cask,CRAFTSANITY, +3414,Farm,Craft Cheese Press,CRAFTSANITY, +3415,Farm,Craft Keg,CRAFTSANITY, +3416,Farm,Craft Loom,CRAFTSANITY, +3417,Farm,Craft Mayonnaise Machine,CRAFTSANITY, +3418,Farm,Craft Oil Maker,CRAFTSANITY, +3419,Farm,Craft Preserves Jar,CRAFTSANITY, +3420,Farm,Craft Basic Fertilizer,CRAFTSANITY, +3421,Farm,Craft Quality Fertilizer,CRAFTSANITY, +3422,Farm,Craft Deluxe Fertilizer,CRAFTSANITY, +3423,Farm,Craft Speed-Gro,CRAFTSANITY, +3424,Farm,Craft Deluxe Speed-Gro,CRAFTSANITY, +3425,Farm,Craft Hyper Speed-Gro,"CRAFTSANITY,GINGER_ISLAND", +3426,Farm,Craft Basic Retaining Soil,CRAFTSANITY, +3427,Farm,Craft Quality Retaining Soil,CRAFTSANITY, +3428,Farm,Craft Deluxe Retaining Soil,"CRAFTSANITY,GINGER_ISLAND", +3429,Farm,Craft Tree Fertilizer,CRAFTSANITY, +3430,Farm,Craft Spring Seeds,CRAFTSANITY, +3431,Farm,Craft Summer Seeds,CRAFTSANITY, +3432,Farm,Craft Fall Seeds,CRAFTSANITY, +3433,Farm,Craft Winter Seeds,CRAFTSANITY, +3434,Farm,Craft Ancient Seeds,CRAFTSANITY, +3435,Farm,Craft Grass Starter,CRAFTSANITY, +3436,Farm,Craft Tea Sapling,CRAFTSANITY, +3437,Farm,Craft Fiber Seeds,CRAFTSANITY, +3438,Farm,Craft Wood Floor,CRAFTSANITY, +3439,Farm,Craft Rustic Plank Floor,CRAFTSANITY, +3440,Farm,Craft Straw Floor,CRAFTSANITY, +3441,Farm,Craft Weathered Floor,CRAFTSANITY, +3442,Farm,Craft Crystal Floor,CRAFTSANITY, +3443,Farm,Craft Stone Floor,CRAFTSANITY, +3444,Farm,Craft Stone Walkway Floor,CRAFTSANITY, +3445,Farm,Craft Brick Floor,CRAFTSANITY, +3446,Farm,Craft Wood Path,CRAFTSANITY, +3447,Farm,Craft Gravel Path,CRAFTSANITY, +3448,Farm,Craft Cobblestone Path,CRAFTSANITY, +3449,Farm,Craft Stepping Stone Path,CRAFTSANITY, +3450,Farm,Craft Crystal Path,CRAFTSANITY, +3451,Farm,Craft Spinner,CRAFTSANITY, +3452,Farm,Craft Trap Bobber,CRAFTSANITY, +3453,Farm,Craft Cork Bobber,CRAFTSANITY, +3454,Farm,Craft Quality Bobber,CRAFTSANITY, +3455,Farm,Craft Treasure Hunter,CRAFTSANITY, +3456,Farm,Craft Dressed Spinner,CRAFTSANITY, +3457,Farm,Craft Barbed Hook,CRAFTSANITY, +3458,Farm,Craft Magnet,CRAFTSANITY, +3459,Farm,Craft Bait,CRAFTSANITY, +3460,Farm,Craft Wild Bait,CRAFTSANITY, +3461,Farm,Craft Magic Bait,"CRAFTSANITY,GINGER_ISLAND", +3462,Farm,Craft Crab Pot,CRAFTSANITY, +3463,Farm,Craft Sturdy Ring,CRAFTSANITY, +3464,Farm,Craft Warrior Ring,CRAFTSANITY, +3465,Farm,Craft Ring of Yoba,CRAFTSANITY, +3466,Farm,Craft Thorns Ring,"CRAFTSANITY,GINGER_ISLAND", +3467,Farm,Craft Glowstone Ring,CRAFTSANITY, +3468,Farm,Craft Iridium Band,CRAFTSANITY, +3469,Farm,Craft Wedding Ring,CRAFTSANITY, +3470,Farm,Craft Field Snack,CRAFTSANITY, +3471,Farm,Craft Bug Steak,CRAFTSANITY, +3472,Farm,Craft Life Elixir,CRAFTSANITY, +3473,Farm,Craft Oil of Garlic,CRAFTSANITY, +3474,Farm,Craft Monster Musk,CRAFTSANITY, +3475,Farm,Craft Fairy Dust,CRAFTSANITY, +3476,Farm,Craft Warp Totem: Beach,CRAFTSANITY, +3477,Farm,Craft Warp Totem: Mountains,CRAFTSANITY, +3478,Farm,Craft Warp Totem: Farm,CRAFTSANITY, +3479,Farm,Craft Warp Totem: Desert,CRAFTSANITY, +3480,Farm,Craft Warp Totem: Island,"CRAFTSANITY,GINGER_ISLAND", +3481,Farm,Craft Rain Totem,CRAFTSANITY, +3482,Farm,Craft Torch,CRAFTSANITY, +3483,Farm,Craft Campfire,CRAFTSANITY, +3484,Farm,Craft Wooden Brazier,CRAFTSANITY, +3485,Farm,Craft Stone Brazier,CRAFTSANITY, +3486,Farm,Craft Gold Brazier,CRAFTSANITY, +3487,Farm,Craft Carved Brazier,CRAFTSANITY, +3488,Farm,Craft Stump Brazier,CRAFTSANITY, +3489,Farm,Craft Barrel Brazier,CRAFTSANITY, +3490,Farm,Craft Skull Brazier,CRAFTSANITY, +3491,Farm,Craft Marble Brazier,CRAFTSANITY, +3492,Farm,Craft Wood Lamp-post,CRAFTSANITY, +3493,Farm,Craft Iron Lamp-post,CRAFTSANITY, +3494,Farm,Craft Jack-O-Lantern,CRAFTSANITY, +3495,Farm,Craft Bone Mill,CRAFTSANITY, +3496,Farm,Craft Charcoal Kiln,CRAFTSANITY, +3497,Farm,Craft Crystalarium,CRAFTSANITY, +3498,Farm,Craft Furnace,CRAFTSANITY, +3499,Farm,Craft Geode Crusher,CRAFTSANITY, +3500,Farm,Craft Heavy Tapper,"CRAFTSANITY,GINGER_ISLAND", +3501,Farm,Craft Lightning Rod,CRAFTSANITY, +3502,Farm,Craft Ostrich Incubator,"CRAFTSANITY,GINGER_ISLAND", +3503,Farm,Craft Recycling Machine,CRAFTSANITY, +3504,Farm,Craft Seed Maker,CRAFTSANITY, +3505,Farm,Craft Slime Egg-Press,CRAFTSANITY, +3506,Farm,Craft Slime Incubator,CRAFTSANITY, +3507,Farm,Craft Solar Panel,CRAFTSANITY, +3508,Farm,Craft Tapper,CRAFTSANITY, +3509,Farm,Craft Worm Bin,CRAFTSANITY, +3510,Farm,Craft Tub o' Flowers,CRAFTSANITY, +3511,Farm,Craft Wicked Statue,CRAFTSANITY, +3512,Farm,Craft Flute Block,CRAFTSANITY, +3513,Farm,Craft Drum Block,CRAFTSANITY, +3514,Farm,Craft Chest,CRAFTSANITY, +3515,Farm,Craft Stone Chest,CRAFTSANITY, +3516,Farm,Craft Wood Sign,CRAFTSANITY, +3517,Farm,Craft Stone Sign,CRAFTSANITY, +3518,Farm,Craft Dark Sign,CRAFTSANITY, +3519,Farm,Craft Garden Pot,CRAFTSANITY, +3520,Farm,Craft Scarecrow,CRAFTSANITY, +3521,Farm,Craft Deluxe Scarecrow,CRAFTSANITY, +3522,Farm,Craft Staircase,CRAFTSANITY, +3523,Farm,Craft Explosive Ammo,CRAFTSANITY, +3524,Farm,Craft Transmute (Fe),CRAFTSANITY, +3525,Farm,Craft Transmute (Au),CRAFTSANITY, +3526,Farm,Craft Mini-Jukebox,CRAFTSANITY, +3527,Farm,Craft Mini-Obelisk,CRAFTSANITY, +3528,Farm,Craft Farm Computer,CRAFTSANITY, +3529,Farm,Craft Hopper,"CRAFTSANITY,GINGER_ISLAND", +3530,Farm,Craft Cookout Kit,CRAFTSANITY, +3551,Pierre's General Store,Grass Starter Recipe,CRAFTSANITY, +3552,Carpenter Shop,Wood Floor Recipe,CRAFTSANITY, +3553,Carpenter Shop,Rustic Plank Floor Recipe,CRAFTSANITY, +3554,Carpenter Shop,Straw Floor Recipe,CRAFTSANITY, +3555,Mines Dwarf Shop,Weathered Floor Recipe,CRAFTSANITY, +3556,Sewer,Crystal Floor Recipe,CRAFTSANITY, +3557,Carpenter Shop,Stone Floor Recipe,CRAFTSANITY, +3558,Carpenter Shop,Stone Walkway Floor Recipe,CRAFTSANITY, +3559,Carpenter Shop,Brick Floor Recipe,CRAFTSANITY, +3560,Carpenter Shop,Stepping Stone Path Recipe,CRAFTSANITY, +3561,Carpenter Shop,Crystal Path Recipe,CRAFTSANITY, +3562,Traveling Cart,Wedding Ring Recipe,CRAFTSANITY, +3563,Volcano Dwarf Shop,Warp Totem: Island Recipe,"CRAFTSANITY,GINGER_ISLAND", +3564,Carpenter Shop,Wooden Brazier Recipe,CRAFTSANITY, +3565,Carpenter Shop,Stone Brazier Recipe,CRAFTSANITY, +3566,Carpenter Shop,Gold Brazier Recipe,CRAFTSANITY, +3567,Carpenter Shop,Carved Brazier Recipe,CRAFTSANITY, +3568,Carpenter Shop,Stump Brazier Recipe,CRAFTSANITY, +3569,Carpenter Shop,Barrel Brazier Recipe,CRAFTSANITY, +3570,Carpenter Shop,Skull Brazier Recipe,CRAFTSANITY, +3571,Carpenter Shop,Marble Brazier Recipe,CRAFTSANITY, +3572,Carpenter Shop,Wood Lamp-post Recipe,CRAFTSANITY, +3573,Carpenter Shop,Iron Lamp-post Recipe,CRAFTSANITY, +3574,Sewer,Wicked Statue Recipe,CRAFTSANITY, +3575,Desert,Warp Totem: Desert Recipe,"CRAFTSANITY", +3576,Island Trader,Deluxe Retaining Soil Recipe,"CRAFTSANITY,GINGER_ISLAND", +5001,Stardew Valley,Level 1 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5002,Stardew Valley,Level 2 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5003,Stardew Valley,Level 3 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5004,Stardew Valley,Level 4 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5005,Stardew Valley,Level 5 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5006,Stardew Valley,Level 6 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5007,Stardew Valley,Level 7 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5008,Stardew Valley,Level 8 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5009,Stardew Valley,Level 9 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5010,Stardew Valley,Level 10 Luck,"LUCK_LEVEL,SKILL_LEVEL",Luck Skill +5011,Stardew Valley,Level 1 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5012,Stardew Valley,Level 2 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5013,Stardew Valley,Level 3 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5014,Stardew Valley,Level 4 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5015,Stardew Valley,Level 5 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5016,Stardew Valley,Level 6 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5017,Stardew Valley,Level 7 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5018,Stardew Valley,Level 8 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5019,Stardew Valley,Level 9 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5020,Stardew Valley,Level 10 Socializing,"SKILL_LEVEL,SOCIALIZING_LEVEL",Socializing Skill +5021,Magic Altar,Level 1 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5022,Magic Altar,Level 2 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5023,Magic Altar,Level 3 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5024,Magic Altar,Level 4 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5025,Magic Altar,Level 5 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5026,Magic Altar,Level 6 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5027,Magic Altar,Level 7 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5028,Magic Altar,Level 8 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5029,Magic Altar,Level 9 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5030,Magic Altar,Level 10 Magic,"MAGIC_LEVEL,SKILL_LEVEL",Magic +5031,Town,Level 1 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5032,Town,Level 2 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5033,Town,Level 3 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5034,Town,Level 4 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5035,Town,Level 5 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5036,Town,Level 6 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5037,Town,Level 7 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5038,Town,Level 8 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5039,Town,Level 9 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5040,Town,Level 10 Binning,"BINNING_LEVEL,SKILL_LEVEL",Binning Skill +5041,Stardew Valley,Level 1 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5042,Stardew Valley,Level 2 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5043,Stardew Valley,Level 3 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5044,Stardew Valley,Level 4 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5045,Stardew Valley,Level 5 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5046,Stardew Valley,Level 6 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5047,Stardew Valley,Level 7 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5048,Stardew Valley,Level 8 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5049,Stardew Valley,Level 9 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5050,Stardew Valley,Level 10 Archaeology,"ARCHAEOLOGY_LEVEL,SKILL_LEVEL",Archaeology +5051,Stardew Valley,Level 1 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5052,Stardew Valley,Level 2 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5053,Stardew Valley,Level 3 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5054,Stardew Valley,Level 4 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5055,Stardew Valley,Level 5 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5056,Stardew Valley,Level 6 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5057,Stardew Valley,Level 7 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5058,Stardew Valley,Level 8 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5059,Stardew Valley,Level 9 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5060,Stardew Valley,Level 10 Cooking,"COOKING_LEVEL,SKILL_LEVEL",Cooking Skill +5501,Magic Altar,Analyze: Clear Debris,MANDATORY,Magic +5502,Magic Altar,Analyze: Till,MANDATORY,Magic +5503,Magic Altar,Analyze: Water,MANDATORY,Magic +5504,Magic Altar,Analyze All Toil School Locations,MANDATORY,Magic +5505,Magic Altar,Analyze: Evac,MANDATORY,Magic +5506,Magic Altar,Analyze: Haste,MANDATORY,Magic +5507,Magic Altar,Analyze: Heal,MANDATORY,Magic +5508,Magic Altar,Analyze All Life School Locations,MANDATORY,Magic +5509,Magic Altar,Analyze: Descend,MANDATORY,Magic +5510,Magic Altar,Analyze: Fireball,MANDATORY,Magic +5511,Magic Altar,Analyze: Frostbolt,MANDATORY,Magic +5512,Magic Altar,Analyze All Elemental School Locations,MANDATORY,Magic +5513,Magic Altar,Analyze: Lantern,MANDATORY,Magic +5514,Magic Altar,Analyze: Tendrils,MANDATORY,Magic +5515,Magic Altar,Analyze: Shockwave,MANDATORY,Magic +5516,Magic Altar,Analyze All Nature School Locations,MANDATORY,Magic +5517,Magic Altar,Analyze: Meteor,MANDATORY,Magic +5518,Magic Altar,Analyze: Lucksteal,MANDATORY,Magic +5519,Magic Altar,Analyze: Bloodmana,MANDATORY,Magic +5520,Magic Altar,Analyze All Eldritch School Locations,MANDATORY,Magic +5521,Magic Altar,Analyze Every Magic School Location,MANDATORY,Magic +6001,Museum,Friendsanity: Jasper 1 <3,FRIENDSANITY,Professor Jasper Thomas +6002,Museum,Friendsanity: Jasper 2 <3,FRIENDSANITY,Professor Jasper Thomas +6003,Museum,Friendsanity: Jasper 3 <3,FRIENDSANITY,Professor Jasper Thomas +6004,Museum,Friendsanity: Jasper 4 <3,FRIENDSANITY,Professor Jasper Thomas +6005,Museum,Friendsanity: Jasper 5 <3,FRIENDSANITY,Professor Jasper Thomas +6006,Museum,Friendsanity: Jasper 6 <3,FRIENDSANITY,Professor Jasper Thomas +6007,Museum,Friendsanity: Jasper 7 <3,FRIENDSANITY,Professor Jasper Thomas +6008,Museum,Friendsanity: Jasper 8 <3,FRIENDSANITY,Professor Jasper Thomas +6009,Museum,Friendsanity: Jasper 9 <3,FRIENDSANITY,Professor Jasper Thomas +6010,Museum,Friendsanity: Jasper 10 <3,FRIENDSANITY,Professor Jasper Thomas +6011,Museum,Friendsanity: Jasper 11 <3,FRIENDSANITY,Professor Jasper Thomas +6012,Museum,Friendsanity: Jasper 12 <3,FRIENDSANITY,Professor Jasper Thomas +6013,Museum,Friendsanity: Jasper 13 <3,FRIENDSANITY,Professor Jasper Thomas +6014,Museum,Friendsanity: Jasper 14 <3,FRIENDSANITY,Professor Jasper Thomas +6015,Yoba's Clearing,Friendsanity: Yoba 1 <3,FRIENDSANITY,Custom NPC - Yoba +6016,Yoba's Clearing,Friendsanity: Yoba 2 <3,FRIENDSANITY,Custom NPC - Yoba +6017,Yoba's Clearing,Friendsanity: Yoba 3 <3,FRIENDSANITY,Custom NPC - Yoba +6018,Yoba's Clearing,Friendsanity: Yoba 4 <3,FRIENDSANITY,Custom NPC - Yoba +6019,Yoba's Clearing,Friendsanity: Yoba 5 <3,FRIENDSANITY,Custom NPC - Yoba +6020,Yoba's Clearing,Friendsanity: Yoba 6 <3,FRIENDSANITY,Custom NPC - Yoba +6021,Yoba's Clearing,Friendsanity: Yoba 7 <3,FRIENDSANITY,Custom NPC - Yoba +6022,Yoba's Clearing,Friendsanity: Yoba 8 <3,FRIENDSANITY,Custom NPC - Yoba +6023,Yoba's Clearing,Friendsanity: Yoba 9 <3,FRIENDSANITY,Custom NPC - Yoba +6024,Yoba's Clearing,Friendsanity: Yoba 10 <3,FRIENDSANITY,Custom NPC - Yoba +6025,Marnie's Ranch,Friendsanity: Mr. Ginger 1 <3,FRIENDSANITY,Mister Ginger (cat npc) +6026,Marnie's Ranch,Friendsanity: Mr. Ginger 2 <3,FRIENDSANITY,Mister Ginger (cat npc) +6027,Marnie's Ranch,Friendsanity: Mr. Ginger 3 <3,FRIENDSANITY,Mister Ginger (cat npc) +6028,Marnie's Ranch,Friendsanity: Mr. Ginger 4 <3,FRIENDSANITY,Mister Ginger (cat npc) +6029,Marnie's Ranch,Friendsanity: Mr. Ginger 5 <3,FRIENDSANITY,Mister Ginger (cat npc) +6030,Marnie's Ranch,Friendsanity: Mr. Ginger 6 <3,FRIENDSANITY,Mister Ginger (cat npc) +6031,Marnie's Ranch,Friendsanity: Mr. Ginger 7 <3,FRIENDSANITY,Mister Ginger (cat npc) +6032,Marnie's Ranch,Friendsanity: Mr. Ginger 8 <3,FRIENDSANITY,Mister Ginger (cat npc) +6033,Marnie's Ranch,Friendsanity: Mr. Ginger 9 <3,FRIENDSANITY,Mister Ginger (cat npc) +6034,Marnie's Ranch,Friendsanity: Mr. Ginger 10 <3,FRIENDSANITY,Mister Ginger (cat npc) +6035,Town,Friendsanity: Ayeisha 1 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6036,Town,Friendsanity: Ayeisha 2 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6037,Town,Friendsanity: Ayeisha 3 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6038,Town,Friendsanity: Ayeisha 4 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6039,Town,Friendsanity: Ayeisha 5 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6040,Town,Friendsanity: Ayeisha 6 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6041,Town,Friendsanity: Ayeisha 7 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6042,Town,Friendsanity: Ayeisha 8 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6043,Town,Friendsanity: Ayeisha 9 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6044,Town,Friendsanity: Ayeisha 10 <3,FRIENDSANITY,Ayeisha - The Postal Worker (Custom NPC) +6045,Saloon,Friendsanity: Shiko 1 <3,FRIENDSANITY,Shiko - New Custom NPC +6046,Saloon,Friendsanity: Shiko 2 <3,FRIENDSANITY,Shiko - New Custom NPC +6047,Saloon,Friendsanity: Shiko 3 <3,FRIENDSANITY,Shiko - New Custom NPC +6048,Saloon,Friendsanity: Shiko 4 <3,FRIENDSANITY,Shiko - New Custom NPC +6049,Saloon,Friendsanity: Shiko 5 <3,FRIENDSANITY,Shiko - New Custom NPC +6050,Saloon,Friendsanity: Shiko 6 <3,FRIENDSANITY,Shiko - New Custom NPC +6051,Saloon,Friendsanity: Shiko 7 <3,FRIENDSANITY,Shiko - New Custom NPC +6052,Saloon,Friendsanity: Shiko 8 <3,FRIENDSANITY,Shiko - New Custom NPC +6053,Saloon,Friendsanity: Shiko 9 <3,FRIENDSANITY,Shiko - New Custom NPC +6054,Saloon,Friendsanity: Shiko 10 <3,FRIENDSANITY,Shiko - New Custom NPC +6055,Saloon,Friendsanity: Shiko 11 <3,FRIENDSANITY,Shiko - New Custom NPC +6056,Saloon,Friendsanity: Shiko 12 <3,FRIENDSANITY,Shiko - New Custom NPC +6057,Saloon,Friendsanity: Shiko 13 <3,FRIENDSANITY,Shiko - New Custom NPC +6058,Saloon,Friendsanity: Shiko 14 <3,FRIENDSANITY,Shiko - New Custom NPC +6059,Wizard Tower,Friendsanity: Wellwick 1 <3,FRIENDSANITY,'Prophet' Wellwick +6060,Wizard Tower,Friendsanity: Wellwick 2 <3,FRIENDSANITY,'Prophet' Wellwick +6061,Wizard Tower,Friendsanity: Wellwick 3 <3,FRIENDSANITY,'Prophet' Wellwick +6062,Wizard Tower,Friendsanity: Wellwick 4 <3,FRIENDSANITY,'Prophet' Wellwick +6063,Wizard Tower,Friendsanity: Wellwick 5 <3,FRIENDSANITY,'Prophet' Wellwick +6064,Wizard Tower,Friendsanity: Wellwick 6 <3,FRIENDSANITY,'Prophet' Wellwick +6065,Wizard Tower,Friendsanity: Wellwick 7 <3,FRIENDSANITY,'Prophet' Wellwick +6066,Wizard Tower,Friendsanity: Wellwick 8 <3,FRIENDSANITY,'Prophet' Wellwick +6067,Wizard Tower,Friendsanity: Wellwick 9 <3,FRIENDSANITY,'Prophet' Wellwick +6068,Wizard Tower,Friendsanity: Wellwick 10 <3,FRIENDSANITY,'Prophet' Wellwick +6069,Wizard Tower,Friendsanity: Wellwick 11 <3,FRIENDSANITY,'Prophet' Wellwick +6070,Wizard Tower,Friendsanity: Wellwick 12 <3,FRIENDSANITY,'Prophet' Wellwick +6071,Wizard Tower,Friendsanity: Wellwick 13 <3,FRIENDSANITY,'Prophet' Wellwick +6072,Wizard Tower,Friendsanity: Wellwick 14 <3,FRIENDSANITY,'Prophet' Wellwick +6073,Forest,Friendsanity: Delores 1 <3,FRIENDSANITY,Delores - Custom NPC +6074,Forest,Friendsanity: Delores 2 <3,FRIENDSANITY,Delores - Custom NPC +6075,Forest,Friendsanity: Delores 3 <3,FRIENDSANITY,Delores - Custom NPC +6076,Forest,Friendsanity: Delores 4 <3,FRIENDSANITY,Delores - Custom NPC +6077,Forest,Friendsanity: Delores 5 <3,FRIENDSANITY,Delores - Custom NPC +6078,Forest,Friendsanity: Delores 6 <3,FRIENDSANITY,Delores - Custom NPC +6079,Forest,Friendsanity: Delores 7 <3,FRIENDSANITY,Delores - Custom NPC +6080,Forest,Friendsanity: Delores 8 <3,FRIENDSANITY,Delores - Custom NPC +6081,Forest,Friendsanity: Delores 9 <3,FRIENDSANITY,Delores - Custom NPC +6082,Forest,Friendsanity: Delores 10 <3,FRIENDSANITY,Delores - Custom NPC +6083,Forest,Friendsanity: Delores 11 <3,FRIENDSANITY,Delores - Custom NPC +6084,Forest,Friendsanity: Delores 12 <3,FRIENDSANITY,Delores - Custom NPC +6085,Forest,Friendsanity: Delores 13 <3,FRIENDSANITY,Delores - Custom NPC +6086,Forest,Friendsanity: Delores 14 <3,FRIENDSANITY,Delores - Custom NPC +6087,Alec's Pet Shop,Friendsanity: Alec 1 <3,FRIENDSANITY,Alec Revisited +6088,Alec's Pet Shop,Friendsanity: Alec 2 <3,FRIENDSANITY,Alec Revisited +6089,Alec's Pet Shop,Friendsanity: Alec 3 <3,FRIENDSANITY,Alec Revisited +6090,Alec's Pet Shop,Friendsanity: Alec 4 <3,FRIENDSANITY,Alec Revisited +6091,Alec's Pet Shop,Friendsanity: Alec 5 <3,FRIENDSANITY,Alec Revisited +6092,Alec's Pet Shop,Friendsanity: Alec 6 <3,FRIENDSANITY,Alec Revisited +6093,Alec's Pet Shop,Friendsanity: Alec 7 <3,FRIENDSANITY,Alec Revisited +6094,Alec's Pet Shop,Friendsanity: Alec 8 <3,FRIENDSANITY,Alec Revisited +6095,Alec's Pet Shop,Friendsanity: Alec 9 <3,FRIENDSANITY,Alec Revisited +6096,Alec's Pet Shop,Friendsanity: Alec 10 <3,FRIENDSANITY,Alec Revisited +6097,Alec's Pet Shop,Friendsanity: Alec 11 <3,FRIENDSANITY,Alec Revisited +6098,Alec's Pet Shop,Friendsanity: Alec 12 <3,FRIENDSANITY,Alec Revisited +6099,Alec's Pet Shop,Friendsanity: Alec 13 <3,FRIENDSANITY,Alec Revisited +6100,Alec's Pet Shop,Friendsanity: Alec 14 <3,FRIENDSANITY,Alec Revisited +6101,Eugene's Garden,Friendsanity: Eugene 1 <3,FRIENDSANITY,Custom NPC Eugene +6102,Eugene's Garden,Friendsanity: Eugene 2 <3,FRIENDSANITY,Custom NPC Eugene +6103,Eugene's Garden,Friendsanity: Eugene 3 <3,FRIENDSANITY,Custom NPC Eugene +6104,Eugene's Garden,Friendsanity: Eugene 4 <3,FRIENDSANITY,Custom NPC Eugene +6105,Eugene's Garden,Friendsanity: Eugene 5 <3,FRIENDSANITY,Custom NPC Eugene +6106,Eugene's Garden,Friendsanity: Eugene 6 <3,FRIENDSANITY,Custom NPC Eugene +6107,Eugene's Garden,Friendsanity: Eugene 7 <3,FRIENDSANITY,Custom NPC Eugene +6108,Eugene's Garden,Friendsanity: Eugene 8 <3,FRIENDSANITY,Custom NPC Eugene +6109,Eugene's Garden,Friendsanity: Eugene 9 <3,FRIENDSANITY,Custom NPC Eugene +6110,Eugene's Garden,Friendsanity: Eugene 10 <3,FRIENDSANITY,Custom NPC Eugene +6111,Eugene's Garden,Friendsanity: Eugene 11 <3,FRIENDSANITY,Custom NPC Eugene +6112,Eugene's Garden,Friendsanity: Eugene 12 <3,FRIENDSANITY,Custom NPC Eugene +6113,Eugene's Garden,Friendsanity: Eugene 13 <3,FRIENDSANITY,Custom NPC Eugene +6114,Eugene's Garden,Friendsanity: Eugene 14 <3,FRIENDSANITY,Custom NPC Eugene +6115,Forest,Friendsanity: Juna 1 <3,FRIENDSANITY,Juna - Roommate NPC +6116,Forest,Friendsanity: Juna 2 <3,FRIENDSANITY,Juna - Roommate NPC +6117,Forest,Friendsanity: Juna 3 <3,FRIENDSANITY,Juna - Roommate NPC +6118,Forest,Friendsanity: Juna 4 <3,FRIENDSANITY,Juna - Roommate NPC +6119,Forest,Friendsanity: Juna 5 <3,FRIENDSANITY,Juna - Roommate NPC +6120,Forest,Friendsanity: Juna 6 <3,FRIENDSANITY,Juna - Roommate NPC +6121,Forest,Friendsanity: Juna 7 <3,FRIENDSANITY,Juna - Roommate NPC +6122,Forest,Friendsanity: Juna 8 <3,FRIENDSANITY,Juna - Roommate NPC +6123,Forest,Friendsanity: Juna 9 <3,FRIENDSANITY,Juna - Roommate NPC +6124,Forest,Friendsanity: Juna 10 <3,FRIENDSANITY,Juna - Roommate NPC +6125,Riley's House,Friendsanity: Riley 1 <3,FRIENDSANITY,Custom NPC - Riley +6126,Riley's House,Friendsanity: Riley 2 <3,FRIENDSANITY,Custom NPC - Riley +6127,Riley's House,Friendsanity: Riley 3 <3,FRIENDSANITY,Custom NPC - Riley +6128,Riley's House,Friendsanity: Riley 4 <3,FRIENDSANITY,Custom NPC - Riley +6129,Riley's House,Friendsanity: Riley 5 <3,FRIENDSANITY,Custom NPC - Riley +6130,Riley's House,Friendsanity: Riley 6 <3,FRIENDSANITY,Custom NPC - Riley +6131,Riley's House,Friendsanity: Riley 7 <3,FRIENDSANITY,Custom NPC - Riley +6132,Riley's House,Friendsanity: Riley 8 <3,FRIENDSANITY,Custom NPC - Riley +6133,Riley's House,Friendsanity: Riley 9 <3,FRIENDSANITY,Custom NPC - Riley +6134,Riley's House,Friendsanity: Riley 10 <3,FRIENDSANITY,Custom NPC - Riley +6135,Riley's House,Friendsanity: Riley 11 <3,FRIENDSANITY,Custom NPC - Riley +6136,Riley's House,Friendsanity: Riley 12 <3,FRIENDSANITY,Custom NPC - Riley +6137,Riley's House,Friendsanity: Riley 13 <3,FRIENDSANITY,Custom NPC - Riley +6138,Riley's House,Friendsanity: Riley 14 <3,FRIENDSANITY,Custom NPC - Riley +6139,JojaMart,Friendsanity: Claire 1 <3,FRIENDSANITY,Stardew Valley Expanded +6140,JojaMart,Friendsanity: Claire 2 <3,FRIENDSANITY,Stardew Valley Expanded +6141,JojaMart,Friendsanity: Claire 3 <3,FRIENDSANITY,Stardew Valley Expanded +6142,JojaMart,Friendsanity: Claire 4 <3,FRIENDSANITY,Stardew Valley Expanded +6143,JojaMart,Friendsanity: Claire 5 <3,FRIENDSANITY,Stardew Valley Expanded +6144,JojaMart,Friendsanity: Claire 6 <3,FRIENDSANITY,Stardew Valley Expanded +6145,JojaMart,Friendsanity: Claire 7 <3,FRIENDSANITY,Stardew Valley Expanded +6146,JojaMart,Friendsanity: Claire 8 <3,FRIENDSANITY,Stardew Valley Expanded +6147,JojaMart,Friendsanity: Claire 9 <3,FRIENDSANITY,Stardew Valley Expanded +6148,JojaMart,Friendsanity: Claire 10 <3,FRIENDSANITY,Stardew Valley Expanded +6149,JojaMart,Friendsanity: Claire 11 <3,FRIENDSANITY,Stardew Valley Expanded +6150,JojaMart,Friendsanity: Claire 12 <3,FRIENDSANITY,Stardew Valley Expanded +6151,JojaMart,Friendsanity: Claire 13 <3,FRIENDSANITY,Stardew Valley Expanded +6152,JojaMart,Friendsanity: Claire 14 <3,FRIENDSANITY,Stardew Valley Expanded +6153,Galmoran Outpost,Friendsanity: Lance 1 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6154,Galmoran Outpost,Friendsanity: Lance 2 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6155,Galmoran Outpost,Friendsanity: Lance 3 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6156,Galmoran Outpost,Friendsanity: Lance 4 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6157,Galmoran Outpost,Friendsanity: Lance 5 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6158,Galmoran Outpost,Friendsanity: Lance 6 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6159,Galmoran Outpost,Friendsanity: Lance 7 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6160,Galmoran Outpost,Friendsanity: Lance 8 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6161,Galmoran Outpost,Friendsanity: Lance 9 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6162,Galmoran Outpost,Friendsanity: Lance 10 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6163,Galmoran Outpost,Friendsanity: Lance 11 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6164,Galmoran Outpost,Friendsanity: Lance 12 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6165,Galmoran Outpost,Friendsanity: Lance 13 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6166,Galmoran Outpost,Friendsanity: Lance 14 <3,"FRIENDSANITY,GINGER_ISLAND",Stardew Valley Expanded +6167,Jenkins' Residence,Friendsanity: Olivia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6168,Jenkins' Residence,Friendsanity: Olivia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6169,Jenkins' Residence,Friendsanity: Olivia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6170,Jenkins' Residence,Friendsanity: Olivia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6171,Jenkins' Residence,Friendsanity: Olivia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6172,Jenkins' Residence,Friendsanity: Olivia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6173,Jenkins' Residence,Friendsanity: Olivia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6174,Jenkins' Residence,Friendsanity: Olivia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6175,Jenkins' Residence,Friendsanity: Olivia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6176,Jenkins' Residence,Friendsanity: Olivia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6177,Jenkins' Residence,Friendsanity: Olivia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6178,Jenkins' Residence,Friendsanity: Olivia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6179,Jenkins' Residence,Friendsanity: Olivia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6180,Jenkins' Residence,Friendsanity: Olivia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6181,Wizard Tower,Friendsanity: Wizard 11 <3,FRIENDSANITY,Stardew Valley Expanded +6182,Wizard Tower,Friendsanity: Wizard 12 <3,FRIENDSANITY,Stardew Valley Expanded +6183,Wizard Tower,Friendsanity: Wizard 13 <3,FRIENDSANITY,Stardew Valley Expanded +6184,Wizard Tower,Friendsanity: Wizard 14 <3,FRIENDSANITY,Stardew Valley Expanded +6185,Blue Moon Vineyard,Friendsanity: Sophia 1 <3,FRIENDSANITY,Stardew Valley Expanded +6186,Blue Moon Vineyard,Friendsanity: Sophia 2 <3,FRIENDSANITY,Stardew Valley Expanded +6187,Blue Moon Vineyard,Friendsanity: Sophia 3 <3,FRIENDSANITY,Stardew Valley Expanded +6188,Blue Moon Vineyard,Friendsanity: Sophia 4 <3,FRIENDSANITY,Stardew Valley Expanded +6189,Blue Moon Vineyard,Friendsanity: Sophia 5 <3,FRIENDSANITY,Stardew Valley Expanded +6190,Blue Moon Vineyard,Friendsanity: Sophia 6 <3,FRIENDSANITY,Stardew Valley Expanded +6191,Blue Moon Vineyard,Friendsanity: Sophia 7 <3,FRIENDSANITY,Stardew Valley Expanded +6192,Blue Moon Vineyard,Friendsanity: Sophia 8 <3,FRIENDSANITY,Stardew Valley Expanded +6193,Blue Moon Vineyard,Friendsanity: Sophia 9 <3,FRIENDSANITY,Stardew Valley Expanded +6194,Blue Moon Vineyard,Friendsanity: Sophia 10 <3,FRIENDSANITY,Stardew Valley Expanded +6195,Blue Moon Vineyard,Friendsanity: Sophia 11 <3,FRIENDSANITY,Stardew Valley Expanded +6196,Blue Moon Vineyard,Friendsanity: Sophia 12 <3,FRIENDSANITY,Stardew Valley Expanded +6197,Blue Moon Vineyard,Friendsanity: Sophia 13 <3,FRIENDSANITY,Stardew Valley Expanded +6198,Blue Moon Vineyard,Friendsanity: Sophia 14 <3,FRIENDSANITY,Stardew Valley Expanded +6199,Jenkins' Residence,Friendsanity: Victor 1 <3,FRIENDSANITY,Stardew Valley Expanded +6200,Jenkins' Residence,Friendsanity: Victor 2 <3,FRIENDSANITY,Stardew Valley Expanded +6201,Jenkins' Residence,Friendsanity: Victor 3 <3,FRIENDSANITY,Stardew Valley Expanded +6202,Jenkins' Residence,Friendsanity: Victor 4 <3,FRIENDSANITY,Stardew Valley Expanded +6203,Jenkins' Residence,Friendsanity: Victor 5 <3,FRIENDSANITY,Stardew Valley Expanded +6204,Jenkins' Residence,Friendsanity: Victor 6 <3,FRIENDSANITY,Stardew Valley Expanded +6205,Jenkins' Residence,Friendsanity: Victor 7 <3,FRIENDSANITY,Stardew Valley Expanded +6206,Jenkins' Residence,Friendsanity: Victor 8 <3,FRIENDSANITY,Stardew Valley Expanded +6207,Jenkins' Residence,Friendsanity: Victor 9 <3,FRIENDSANITY,Stardew Valley Expanded +6208,Jenkins' Residence,Friendsanity: Victor 10 <3,FRIENDSANITY,Stardew Valley Expanded +6209,Jenkins' Residence,Friendsanity: Victor 11 <3,FRIENDSANITY,Stardew Valley Expanded +6210,Jenkins' Residence,Friendsanity: Victor 12 <3,FRIENDSANITY,Stardew Valley Expanded +6211,Jenkins' Residence,Friendsanity: Victor 13 <3,FRIENDSANITY,Stardew Valley Expanded +6212,Jenkins' Residence,Friendsanity: Victor 14 <3,FRIENDSANITY,Stardew Valley Expanded +6213,Fairhaven Farm,Friendsanity: Andy 1 <3,FRIENDSANITY,Stardew Valley Expanded +6214,Fairhaven Farm,Friendsanity: Andy 2 <3,FRIENDSANITY,Stardew Valley Expanded +6215,Fairhaven Farm,Friendsanity: Andy 3 <3,FRIENDSANITY,Stardew Valley Expanded +6216,Fairhaven Farm,Friendsanity: Andy 4 <3,FRIENDSANITY,Stardew Valley Expanded +6217,Fairhaven Farm,Friendsanity: Andy 5 <3,FRIENDSANITY,Stardew Valley Expanded +6218,Fairhaven Farm,Friendsanity: Andy 6 <3,FRIENDSANITY,Stardew Valley Expanded +6219,Fairhaven Farm,Friendsanity: Andy 7 <3,FRIENDSANITY,Stardew Valley Expanded +6220,Fairhaven Farm,Friendsanity: Andy 8 <3,FRIENDSANITY,Stardew Valley Expanded +6221,Fairhaven Farm,Friendsanity: Andy 9 <3,FRIENDSANITY,Stardew Valley Expanded +6222,Fairhaven Farm,Friendsanity: Andy 10 <3,FRIENDSANITY,Stardew Valley Expanded +6223,Aurora Vineyard,Friendsanity: Apples 1 <3,FRIENDSANITY,Stardew Valley Expanded +6224,Aurora Vineyard,Friendsanity: Apples 2 <3,FRIENDSANITY,Stardew Valley Expanded +6225,Aurora Vineyard,Friendsanity: Apples 3 <3,FRIENDSANITY,Stardew Valley Expanded +6226,Aurora Vineyard,Friendsanity: Apples 4 <3,FRIENDSANITY,Stardew Valley Expanded +6227,Aurora Vineyard,Friendsanity: Apples 5 <3,FRIENDSANITY,Stardew Valley Expanded +6228,Aurora Vineyard,Friendsanity: Apples 6 <3,FRIENDSANITY,Stardew Valley Expanded +6229,Aurora Vineyard,Friendsanity: Apples 7 <3,FRIENDSANITY,Stardew Valley Expanded +6230,Aurora Vineyard,Friendsanity: Apples 8 <3,FRIENDSANITY,Stardew Valley Expanded +6231,Aurora Vineyard,Friendsanity: Apples 9 <3,FRIENDSANITY,Stardew Valley Expanded +6232,Aurora Vineyard,Friendsanity: Apples 10 <3,FRIENDSANITY,Stardew Valley Expanded +6233,Museum,Friendsanity: Gunther 1 <3,FRIENDSANITY,Stardew Valley Expanded +6234,Museum,Friendsanity: Gunther 2 <3,FRIENDSANITY,Stardew Valley Expanded +6235,Museum,Friendsanity: Gunther 3 <3,FRIENDSANITY,Stardew Valley Expanded +6236,Museum,Friendsanity: Gunther 4 <3,FRIENDSANITY,Stardew Valley Expanded +6237,Museum,Friendsanity: Gunther 5 <3,FRIENDSANITY,Stardew Valley Expanded +6238,Museum,Friendsanity: Gunther 6 <3,FRIENDSANITY,Stardew Valley Expanded +6239,Museum,Friendsanity: Gunther 7 <3,FRIENDSANITY,Stardew Valley Expanded +6240,Museum,Friendsanity: Gunther 8 <3,FRIENDSANITY,Stardew Valley Expanded +6241,Museum,Friendsanity: Gunther 9 <3,FRIENDSANITY,Stardew Valley Expanded +6242,Museum,Friendsanity: Gunther 10 <3,FRIENDSANITY,Stardew Valley Expanded +6243,JojaMart,Friendsanity: Martin 1 <3,FRIENDSANITY,Stardew Valley Expanded +6244,JojaMart,Friendsanity: Martin 2 <3,FRIENDSANITY,Stardew Valley Expanded +6245,JojaMart,Friendsanity: Martin 3 <3,FRIENDSANITY,Stardew Valley Expanded +6246,JojaMart,Friendsanity: Martin 4 <3,FRIENDSANITY,Stardew Valley Expanded +6247,JojaMart,Friendsanity: Martin 5 <3,FRIENDSANITY,Stardew Valley Expanded +6248,JojaMart,Friendsanity: Martin 6 <3,FRIENDSANITY,Stardew Valley Expanded +6249,JojaMart,Friendsanity: Martin 7 <3,FRIENDSANITY,Stardew Valley Expanded +6250,JojaMart,Friendsanity: Martin 8 <3,FRIENDSANITY,Stardew Valley Expanded +6251,JojaMart,Friendsanity: Martin 9 <3,FRIENDSANITY,Stardew Valley Expanded +6252,JojaMart,Friendsanity: Martin 10 <3,FRIENDSANITY,Stardew Valley Expanded +6253,Adventurer's Guild,Friendsanity: Marlon 1 <3,FRIENDSANITY,Stardew Valley Expanded +6254,Adventurer's Guild,Friendsanity: Marlon 2 <3,FRIENDSANITY,Stardew Valley Expanded +6255,Adventurer's Guild,Friendsanity: Marlon 3 <3,FRIENDSANITY,Stardew Valley Expanded +6256,Adventurer's Guild,Friendsanity: Marlon 4 <3,FRIENDSANITY,Stardew Valley Expanded +6257,Adventurer's Guild,Friendsanity: Marlon 5 <3,FRIENDSANITY,Stardew Valley Expanded +6258,Adventurer's Guild,Friendsanity: Marlon 6 <3,FRIENDSANITY,Stardew Valley Expanded +6259,Adventurer's Guild,Friendsanity: Marlon 7 <3,FRIENDSANITY,Stardew Valley Expanded +6260,Adventurer's Guild,Friendsanity: Marlon 8 <3,FRIENDSANITY,Stardew Valley Expanded +6261,Adventurer's Guild,Friendsanity: Marlon 9 <3,FRIENDSANITY,Stardew Valley Expanded +6262,Adventurer's Guild,Friendsanity: Marlon 10 <3,FRIENDSANITY,Stardew Valley Expanded +6263,Wizard Tower,Friendsanity: Morgan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6264,Wizard Tower,Friendsanity: Morgan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6265,Wizard Tower,Friendsanity: Morgan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6266,Wizard Tower,Friendsanity: Morgan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6267,Wizard Tower,Friendsanity: Morgan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6268,Wizard Tower,Friendsanity: Morgan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6269,Wizard Tower,Friendsanity: Morgan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6270,Wizard Tower,Friendsanity: Morgan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6271,Wizard Tower,Friendsanity: Morgan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6272,Wizard Tower,Friendsanity: Morgan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6273,Scarlett's House,Friendsanity: Scarlett 1 <3,FRIENDSANITY,Stardew Valley Expanded +6274,Scarlett's House,Friendsanity: Scarlett 2 <3,FRIENDSANITY,Stardew Valley Expanded +6275,Scarlett's House,Friendsanity: Scarlett 3 <3,FRIENDSANITY,Stardew Valley Expanded +6276,Scarlett's House,Friendsanity: Scarlett 4 <3,FRIENDSANITY,Stardew Valley Expanded +6277,Scarlett's House,Friendsanity: Scarlett 5 <3,FRIENDSANITY,Stardew Valley Expanded +6278,Scarlett's House,Friendsanity: Scarlett 6 <3,FRIENDSANITY,Stardew Valley Expanded +6279,Scarlett's House,Friendsanity: Scarlett 7 <3,FRIENDSANITY,Stardew Valley Expanded +6280,Scarlett's House,Friendsanity: Scarlett 8 <3,FRIENDSANITY,Stardew Valley Expanded +6281,Scarlett's House,Friendsanity: Scarlett 9 <3,FRIENDSANITY,Stardew Valley Expanded +6282,Scarlett's House,Friendsanity: Scarlett 10 <3,FRIENDSANITY,Stardew Valley Expanded +6283,Susan's House,Friendsanity: Susan 1 <3,FRIENDSANITY,Stardew Valley Expanded +6284,Susan's House,Friendsanity: Susan 2 <3,FRIENDSANITY,Stardew Valley Expanded +6285,Susan's House,Friendsanity: Susan 3 <3,FRIENDSANITY,Stardew Valley Expanded +6286,Susan's House,Friendsanity: Susan 4 <3,FRIENDSANITY,Stardew Valley Expanded +6287,Susan's House,Friendsanity: Susan 5 <3,FRIENDSANITY,Stardew Valley Expanded +6288,Susan's House,Friendsanity: Susan 6 <3,FRIENDSANITY,Stardew Valley Expanded +6289,Susan's House,Friendsanity: Susan 7 <3,FRIENDSANITY,Stardew Valley Expanded +6290,Susan's House,Friendsanity: Susan 8 <3,FRIENDSANITY,Stardew Valley Expanded +6291,Susan's House,Friendsanity: Susan 9 <3,FRIENDSANITY,Stardew Valley Expanded +6292,Susan's House,Friendsanity: Susan 10 <3,FRIENDSANITY,Stardew Valley Expanded +6293,JojaMart,Friendsanity: Morris 1 <3,FRIENDSANITY,Stardew Valley Expanded +6294,JojaMart,Friendsanity: Morris 2 <3,FRIENDSANITY,Stardew Valley Expanded +6295,JojaMart,Friendsanity: Morris 3 <3,FRIENDSANITY,Stardew Valley Expanded +6296,JojaMart,Friendsanity: Morris 4 <3,FRIENDSANITY,Stardew Valley Expanded +6297,JojaMart,Friendsanity: Morris 5 <3,FRIENDSANITY,Stardew Valley Expanded +6298,JojaMart,Friendsanity: Morris 6 <3,FRIENDSANITY,Stardew Valley Expanded +6299,JojaMart,Friendsanity: Morris 7 <3,FRIENDSANITY,Stardew Valley Expanded +6300,JojaMart,Friendsanity: Morris 8 <3,FRIENDSANITY,Stardew Valley Expanded +6301,JojaMart,Friendsanity: Morris 9 <3,FRIENDSANITY,Stardew Valley Expanded +6302,JojaMart,Friendsanity: Morris 10 <3,FRIENDSANITY,Stardew Valley Expanded +6303,Witch's Swamp,Friendsanity: Zic 1 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6304,Witch's Swamp,Friendsanity: Zic 2 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6305,Witch's Swamp,Friendsanity: Zic 3 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6306,Witch's Swamp,Friendsanity: Zic 4 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6307,Witch's Swamp,Friendsanity: Zic 5 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6308,Witch's Swamp,Friendsanity: Zic 6 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6309,Witch's Swamp,Friendsanity: Zic 7 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6310,Witch's Swamp,Friendsanity: Zic 8 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6311,Witch's Swamp,Friendsanity: Zic 9 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6312,Witch's Swamp,Friendsanity: Zic 10 <3,FRIENDSANITY,Distant Lands - Witch Swamp Overhaul +6313,Witch's Attic,Friendsanity: Alecto 1 <3,FRIENDSANITY,Alecto the Witch +6314,Witch's Attic,Friendsanity: Alecto 2 <3,FRIENDSANITY,Alecto the Witch +6315,Witch's Attic,Friendsanity: Alecto 3 <3,FRIENDSANITY,Alecto the Witch +6316,Witch's Attic,Friendsanity: Alecto 4 <3,FRIENDSANITY,Alecto the Witch +6317,Witch's Attic,Friendsanity: Alecto 5 <3,FRIENDSANITY,Alecto the Witch +6318,Witch's Attic,Friendsanity: Alecto 6 <3,FRIENDSANITY,Alecto the Witch +6319,Witch's Attic,Friendsanity: Alecto 7 <3,FRIENDSANITY,Alecto the Witch +6320,Witch's Attic,Friendsanity: Alecto 8 <3,FRIENDSANITY,Alecto the Witch +6321,Witch's Attic,Friendsanity: Alecto 9 <3,FRIENDSANITY,Alecto the Witch +6322,Witch's Attic,Friendsanity: Alecto 10 <3,FRIENDSANITY,Alecto the Witch +6323,Mouse House,Friendsanity: Lacey 1 <3,FRIENDSANITY,Hat Mouse Lacey +6324,Mouse House,Friendsanity: Lacey 2 <3,FRIENDSANITY,Hat Mouse Lacey +6325,Mouse House,Friendsanity: Lacey 3 <3,FRIENDSANITY,Hat Mouse Lacey +6326,Mouse House,Friendsanity: Lacey 4 <3,FRIENDSANITY,Hat Mouse Lacey +6327,Mouse House,Friendsanity: Lacey 5 <3,FRIENDSANITY,Hat Mouse Lacey +6328,Mouse House,Friendsanity: Lacey 6 <3,FRIENDSANITY,Hat Mouse Lacey +6329,Mouse House,Friendsanity: Lacey 7 <3,FRIENDSANITY,Hat Mouse Lacey +6330,Mouse House,Friendsanity: Lacey 8 <3,FRIENDSANITY,Hat Mouse Lacey +6331,Mouse House,Friendsanity: Lacey 9 <3,FRIENDSANITY,Hat Mouse Lacey +6332,Mouse House,Friendsanity: Lacey 10 <3,FRIENDSANITY,Hat Mouse Lacey +6333,Mouse House,Friendsanity: Lacey 11 <3,FRIENDSANITY,Hat Mouse Lacey +6334,Mouse House,Friendsanity: Lacey 12 <3,FRIENDSANITY,Hat Mouse Lacey +6335,Mouse House,Friendsanity: Lacey 13 <3,FRIENDSANITY,Hat Mouse Lacey +6336,Mouse House,Friendsanity: Lacey 14 <3,FRIENDSANITY,Hat Mouse Lacey +6337,Boarding House - First Floor,Friendsanity: Joel 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6338,Boarding House - First Floor,Friendsanity: Joel 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6339,Boarding House - First Floor,Friendsanity: Joel 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6340,Boarding House - First Floor,Friendsanity: Joel 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6341,Boarding House - First Floor,Friendsanity: Joel 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6342,Boarding House - First Floor,Friendsanity: Joel 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6343,Boarding House - First Floor,Friendsanity: Joel 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6344,Boarding House - First Floor,Friendsanity: Joel 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6345,Boarding House - First Floor,Friendsanity: Joel 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6346,Boarding House - First Floor,Friendsanity: Joel 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6347,Boarding House - First Floor,Friendsanity: Sheila 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6348,Boarding House - First Floor,Friendsanity: Sheila 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6349,Boarding House - First Floor,Friendsanity: Sheila 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6350,Boarding House - First Floor,Friendsanity: Sheila 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6351,Boarding House - First Floor,Friendsanity: Sheila 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6352,Boarding House - First Floor,Friendsanity: Sheila 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6353,Boarding House - First Floor,Friendsanity: Sheila 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6354,Boarding House - First Floor,Friendsanity: Sheila 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6355,Boarding House - First Floor,Friendsanity: Sheila 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6356,Boarding House - First Floor,Friendsanity: Sheila 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6357,Boarding House - First Floor,Friendsanity: Sheila 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6358,Boarding House - First Floor,Friendsanity: Sheila 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6359,Boarding House - First Floor,Friendsanity: Sheila 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6360,Boarding House - First Floor,Friendsanity: Sheila 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6361,The Lost Valley,Friendsanity: Gregory 1 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6362,The Lost Valley,Friendsanity: Gregory 2 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6363,The Lost Valley,Friendsanity: Gregory 3 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6364,The Lost Valley,Friendsanity: Gregory 4 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6365,The Lost Valley,Friendsanity: Gregory 5 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6366,The Lost Valley,Friendsanity: Gregory 6 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6367,The Lost Valley,Friendsanity: Gregory 7 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6368,The Lost Valley,Friendsanity: Gregory 8 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6369,The Lost Valley,Friendsanity: Gregory 9 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6370,The Lost Valley,Friendsanity: Gregory 10 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6371,The Lost Valley,Friendsanity: Gregory 11 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6372,The Lost Valley,Friendsanity: Gregory 12 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6373,The Lost Valley,Friendsanity: Gregory 13 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +6374,The Lost Valley,Friendsanity: Gregory 14 <3,FRIENDSANITY,Boarding House and Bus Stop Extension +7001,Pierre's General Store,Premium Pack,BACKPACK,Bigger Backpack +7002,Carpenter Shop,Tractor Garage Blueprint,BUILDING_BLUEPRINT,Tractor Mod +7003,The Deep Woods Depth 100,Pet the Deep Woods Unicorn,MANDATORY,DeepWoods +7004,The Deep Woods Depth 50,Breaking Up Deep Woods Gingerbread House,MANDATORY,DeepWoods +7005,The Deep Woods Depth 50,Drinking From Deep Woods Fountain,MANDATORY,DeepWoods +7006,The Deep Woods Depth 100,Deep Woods Treasure Chest,MANDATORY,DeepWoods +7007,The Deep Woods Depth 100,Deep Woods Trash Bin,MANDATORY,DeepWoods +7008,The Deep Woods Depth 50,Chop Down a Deep Woods Iridium Tree,MANDATORY,DeepWoods +7009,The Deep Woods Depth 10,The Deep Woods: Depth 10,ELEVATOR,DeepWoods +7010,The Deep Woods Depth 20,The Deep Woods: Depth 20,ELEVATOR,DeepWoods +7011,The Deep Woods Depth 30,The Deep Woods: Depth 30,ELEVATOR,DeepWoods +7012,The Deep Woods Depth 40,The Deep Woods: Depth 40,ELEVATOR,DeepWoods +7013,The Deep Woods Depth 50,The Deep Woods: Depth 50,ELEVATOR,DeepWoods +7014,The Deep Woods Depth 60,The Deep Woods: Depth 60,ELEVATOR,DeepWoods +7015,The Deep Woods Depth 70,The Deep Woods: Depth 70,ELEVATOR,DeepWoods +7016,The Deep Woods Depth 80,The Deep Woods: Depth 80,ELEVATOR,DeepWoods +7017,The Deep Woods Depth 90,The Deep Woods: Depth 90,ELEVATOR,DeepWoods +7018,The Deep Woods Depth 100,The Deep Woods: Depth 100,ELEVATOR,DeepWoods +7019,The Deep Woods Depth 50,Purify an Infested Lichtung,MANDATORY,DeepWoods +7020,Skull Cavern Floor 25,Skull Cavern: Floor 25,ELEVATOR,Skull Cavern Elevator +7021,Skull Cavern Floor 50,Skull Cavern: Floor 50,ELEVATOR,Skull Cavern Elevator +7022,Skull Cavern Floor 75,Skull Cavern: Floor 75,ELEVATOR,Skull Cavern Elevator +7023,Skull Cavern Floor 100,Skull Cavern: Floor 100,ELEVATOR,Skull Cavern Elevator +7024,Skull Cavern Floor 125,Skull Cavern: Floor 125,ELEVATOR,Skull Cavern Elevator +7025,Skull Cavern Floor 150,Skull Cavern: Floor 150,ELEVATOR,Skull Cavern Elevator +7026,Skull Cavern Floor 175,Skull Cavern: Floor 175,ELEVATOR,Skull Cavern Elevator +7027,Skull Cavern Floor 200,Skull Cavern: Floor 200,ELEVATOR,Skull Cavern Elevator +7028,The Deep Woods Depth 100,The Sword in the Stone,MANDATORY,DeepWoods +7051,Abandoned Mines - 1A,Abandoned Treasure - Floor 1A,MANDATORY,Boarding House and Bus Stop Extension +7052,Abandoned Mines - 1B,Abandoned Treasure - Floor 1B,MANDATORY,Boarding House and Bus Stop Extension +7053,Abandoned Mines - 2A,Abandoned Treasure - Floor 2A,MANDATORY,Boarding House and Bus Stop Extension +7054,Abandoned Mines - 2B,Abandoned Treasure - Floor 2B,MANDATORY,Boarding House and Bus Stop Extension +7055,Abandoned Mines - 3,Abandoned Treasure - Floor 3,MANDATORY,Boarding House and Bus Stop Extension +7056,Abandoned Mines - 4,Abandoned Treasure - Floor 4,MANDATORY,Boarding House and Bus Stop Extension +7057,Abandoned Mines - 5,Abandoned Treasure - Floor 5,MANDATORY,Boarding House and Bus Stop Extension +7401,Farm,Cook Magic Elixir,COOKSANITY,Magic +7402,Farm,Craft Travel Core,CRAFTSANITY,Magic +7403,Farm,Craft Haste Elixir,CRAFTSANITY,Stardew Valley Expanded +7404,Farm,Craft Hero Elixir,CRAFTSANITY,Stardew Valley Expanded +7405,Farm,Craft Armor Elixir,CRAFTSANITY,Stardew Valley Expanded +7406,Witch's Swamp,Craft Ginger Tincture,"CRAFTSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +7407,Farm,Craft Glass Path,CRAFTSANITY,Archaeology +7408,Farm,Craft Glass Bazier,CRAFTSANITY,Archaeology +7409,Farm,Craft Glass Fence,CRAFTSANITY,Archaeology +7410,Farm,Craft Bone Path,CRAFTSANITY,Archaeology +7411,Farm,Craft Water Shifter,CRAFTSANITY,Archaeology +7412,Farm,Craft Wooden Display,CRAFTSANITY,Archaeology +7413,Farm,Craft Hardwood Display,CRAFTSANITY,Archaeology +7414,Farm,Craft Dwarf Gadget: Infinite Volcano Simulation,"CRAFTSANITY,GINGER_ISLAND",Archaeology +7415,Farm,Craft Grinder,CRAFTSANITY,Archaeology +7416,Farm,Craft Preservation Chamber,CRAFTSANITY,Archaeology +7417,Farm,Craft Hardwood Preservation Chamber,CRAFTSANITY,Archaeology +7418,Farm,Craft Ancient Battery Production Station,CRAFTSANITY,Archaeology +7419,Farm,Craft Neanderthal Skeleton,CRAFTSANITY,Boarding House and Bus Stop Extension +7420,Farm,Craft Pterodactyl Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension +7421,Farm,Craft Pterodactyl Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension +7422,Farm,Craft Pterodactyl Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension +7423,Farm,Craft T-Rex Skeleton L,CRAFTSANITY,Boarding House and Bus Stop Extension +7424,Farm,Craft T-Rex Skeleton M,CRAFTSANITY,Boarding House and Bus Stop Extension +7425,Farm,Craft T-Rex Skeleton R,CRAFTSANITY,Boarding House and Bus Stop Extension +7451,Adventurer's Guild,Magic Elixir Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Magic +7452,Adventurer's Guild,Travel Core Recipe,CRAFTSANITY,Magic +7453,Alesia Shop,Haste Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7454,Isaac Shop,Hero Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7455,Alesia Shop,Armor Elixir Recipe,CRAFTSANITY,Stardew Valley Expanded +7501,Mountain,Missing Envelope,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) +7502,Forest,Lost Emerald Ring,"STORY_QUEST",Ayeisha - The Postal Worker (Custom NPC) +7503,Forest,Mr.Ginger's request,"STORY_QUEST",Mister Ginger (cat npc) +7504,Forest,Juna's Drink Request,"STORY_QUEST",Juna - Roommate NPC +7505,Forest,Juna's BFF Request,"STORY_QUEST",Juna - Roommate NPC +7506,Forest,Juna's Monster Mash,SPECIAL_ORDER_BOARD,Juna - Roommate NPC +7507,Adventurer's Guild,Marlon's Boat,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7508,Railroad,The Railroad Boulder,"STORY_QUEST",Stardew Valley Expanded +7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded +7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded +7511,Lance's House Main,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded +7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded +7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7516,Sophia's House,Fairy Garden,"SPECIAL_ORDER_BOARD,GINGER_ISLAND",Stardew Valley Expanded +7517,Susan's House,Homemade Fertilizer,SPECIAL_ORDER_BOARD,Stardew Valley Expanded +7519,Witch's Swamp,Corrupted Crops Task,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +7520,Witch's Swamp,A New Pot,STORY_QUEST,Distant Lands - Witch Swamp Overhaul +7521,Witch's Swamp,Fancy Blanket Task,STORY_QUEST,Distant Lands - Witch Swamp Overhaul +7522,Witch's Swamp,Witch's order,GINGER_ISLAND,Distant Lands - Witch Swamp Overhaul +7523,Boarding House - First Floor,Pumpkin Soup,STORY_QUEST,Boarding House and Bus Stop Extension +7524,Museum,Geode Order,SPECIAL_ORDER_BOARD,Professor Jasper Thomas +7525,Museum,Dwarven Scrolls,SPECIAL_ORDER_BOARD,Professor Jasper Thomas +7526,Mouse House,Hats for the Hat Mouse,STORY_QUEST,Hat Mouse Lacey +7551,Kitchen,Cook Baked Berry Oatmeal,COOKSANITY,Stardew Valley Expanded +7552,Kitchen,Cook Flower Cookie,COOKSANITY,Stardew Valley Expanded +7553,Kitchen,Cook Big Bark Burger,COOKSANITY,Stardew Valley Expanded +7554,Kitchen,Cook Frog Legs,COOKSANITY,Stardew Valley Expanded +7555,Kitchen,Cook Glazed Butterfish,COOKSANITY,Stardew Valley Expanded +7556,Kitchen,Cook Mixed Berry Pie,COOKSANITY,Stardew Valley Expanded +7557,Kitchen,Cook Mushroom Berry Rice,COOKSANITY,Stardew Valley Expanded +7558,Kitchen,Cook Seaweed Salad,COOKSANITY,Stardew Valley Expanded +7559,Kitchen,Cook Void Delight,COOKSANITY,Stardew Valley Expanded +7560,Kitchen,Cook Void Salmon Sushi,COOKSANITY,Stardew Valley Expanded +7561,Kitchen,Cook Mushroom Kebab,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7562,Kitchen,Cook Crayfish Soup,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7563,Kitchen,Cook Pemmican,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7564,Kitchen,Cook Void Mint Tea,COOKSANITY,Distant Lands - Witch Swamp Overhaul +7565,Kitchen,Cook Special Pumpkin Soup,COOKSANITY,Boarding House and Bus Stop Extension +7601,Bear Shop,Baked Berry Oatmeal Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7602,Bear Shop,Flower Cookie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7603,Saloon,Big Bark Burger Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7604,Adventurer's Guild,Frog Legs Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7605,Saloon,Glazed Butterfish Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7606,Saloon,Mixed Berry Pie Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7607,Adventurer's Guild,Mushroom Berry Rice Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7608,Adventurer's Guild,Seaweed Salad Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7609,Sewer,Void Delight Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Stardew Valley Expanded +7610,Sewer,Void Salmon Sushi Recipe,"CHEFSANITY,CHEFSANITY_PURCHASE",Stardew Valley Expanded +7611,Witch's Swamp,Mushroom Kebab Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7613,Witch's Swamp,Pemmican Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7614,Witch's Swamp,Void Mint Tea Recipe,"CHEFSANITY,CHEFSANITY_FRIENDSHIP",Distant Lands - Witch Swamp Overhaul +7616,Mines Dwarf Shop,Neanderthal Skeleton Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7617,Mines Dwarf Shop,Pterodactyl Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7618,Mines Dwarf Shop,Pterodactyl Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7619,Mines Dwarf Shop,Pterodactyl Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7620,Mines Dwarf Shop,T-Rex Skeleton L Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7621,Mines Dwarf Shop,T-Rex Skeleton M Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7622,Mines Dwarf Shop,T-Rex Skeleton R Recipe,CRAFTSANITY,Boarding House and Bus Stop Extension +7651,Alesia Shop,Tempered Galaxy Dagger,MANDATORY,Stardew Valley Expanded +7652,Isaac Shop,Tempered Galaxy Sword,MANDATORY,Stardew Valley Expanded +7653,Isaac Shop,Tempered Galaxy Hammer,MANDATORY,Stardew Valley Expanded +7701,Island South,Fishsanity: Baby Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7702,Crimson Badlands,Fishsanity: Bonefish,FISHSANITY,Stardew Valley Expanded +7703,Forest,Fishsanity: Bull Trout,FISHSANITY,Stardew Valley Expanded +7704,Forest West,Fishsanity: Butterfish,FISHSANITY,Stardew Valley Expanded +7705,Island South,Fishsanity: Clownfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7706,Highlands Outside,Fishsanity: Daggerfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7707,Mountain,Fishsanity: Frog,FISHSANITY,Stardew Valley Expanded +7708,Highlands Outside,Fishsanity: Gemfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7709,Sprite Spring,Fishsanity: Goldenfish,FISHSANITY,Stardew Valley Expanded +7710,Secret Woods,Fishsanity: Grass Carp,FISHSANITY,Stardew Valley Expanded +7711,Forest West,Fishsanity: King Salmon,FISHSANITY,Stardew Valley Expanded +7712,Island West,Fishsanity: Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7713,Sprite Spring,Fishsanity: Meteor Carp,FISHSANITY,Stardew Valley Expanded +7714,Town,Fishsanity: Minnow,FISHSANITY,Stardew Valley Expanded +7715,Forest West,Fishsanity: Puppyfish,FISHSANITY,Stardew Valley Expanded +7716,Sewer,Fishsanity: Radioactive Bass,FISHSANITY,Stardew Valley Expanded +7717,Island West,Fishsanity: Seahorse,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7718,Island West,Fishsanity: Sea Sponge,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7719,Island South,Fishsanity: Shiny Lunaloo,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7720,Mutant Bug Lair,Fishsanity: Snatcher Worm,FISHSANITY,Stardew Valley Expanded +7721,Beach,Fishsanity: Starfish,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7722,Fable Reef,Fishsanity: Torpedo Trout,"FISHSANITY,GINGER_ISLAND",Stardew Valley Expanded +7723,Witch's Swamp,Fishsanity: Void Eel,FISHSANITY,Stardew Valley Expanded +7724,Mutant Bug Lair,Fishsanity: Water Grub,FISHSANITY,Stardew Valley Expanded +7725,Crimson Badlands,Fishsanity: Undeadfish,FISHSANITY,Stardew Valley Expanded +7726,Shearwater Bridge,Fishsanity: Kittyfish,FISHSANITY,Stardew Valley Expanded +7727,Blue Moon Vineyard,Fishsanity: Dulse Seaweed,FISHSANITY,Stardew Valley Expanded +7728,Witch's Swamp,Fishsanity: Void Minnow,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7729,Witch's Swamp,Fishsanity: Swamp Leech,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7730,Witch's Swamp,Fishsanity: Giant Horsehoe Crab,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7731,Witch's Swamp,Fishsanity: Purple Algae,FISHSANITY,Distant Lands - Witch Swamp Overhaul +7901,Farm,Harvest Monster Fruit,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7902,Farm,Harvest Salal Berry,CROPSANITY,Stardew Valley Expanded +7903,Farm,Harvest Slime Berry,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7904,Farm,Harvest Ancient Fiber,CROPSANITY,Stardew Valley Expanded +7905,Farm,Harvest Monster Mushroom,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7906,Farm,Harvest Void Root,"CROPSANITY,GINGER_ISLAND",Stardew Valley Expanded +7907,Farm,Harvest Void Mint Leaves,CROPSANITY,Distant Lands - Witch Swamp Overhaul +7908,Farm,Harvest Vile Ancient Fruit,CROPSANITY,Distant Lands - Witch Swamp Overhaul +8001,Shipping,Shipsanity: Magic Elixir,SHIPSANITY,Magic +8002,Shipping,Shipsanity: Travel Core,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Magic +8003,Shipping,Shipsanity: Aegis Elixir,SHIPSANITY,Stardew Valley Expanded +8004,Shipping,Shipsanity: Aged Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8005,Shipping,Shipsanity: Ancient Ferns Seed,SHIPSANITY,Stardew Valley Expanded +8006,Shipping,Shipsanity: Ancient Fiber,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8007,Shipping,Shipsanity: Armor Elixir,SHIPSANITY,Stardew Valley Expanded +8008,Shipping,Shipsanity: Baby Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8009,Shipping,Shipsanity: Baked Berry Oatmeal,SHIPSANITY,Stardew Valley Expanded +8010,Shipping,Shipsanity: Barbarian Elixir,SHIPSANITY,Stardew Valley Expanded +8011,Shipping,Shipsanity: Bearberrys,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8012,Shipping,Shipsanity: Big Bark Burger,SHIPSANITY,Stardew Valley Expanded +8013,Shipping,Shipsanity: Big Conch,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8014,Shipping,Shipsanity: Blue Moon Wine,SHIPSANITY,Stardew Valley Expanded +8015,Shipping,Shipsanity: Bonefish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8016,Shipping,Shipsanity: Bull Trout,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8017,Shipping,Shipsanity: Butterfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8018,Shipping,Shipsanity: Clownfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8019,Shipping,Shipsanity: Daggerfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8020,Shipping,Shipsanity: Dewdrop Berry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8021,Shipping,Shipsanity: Dried Sand Dollar,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8022,Shipping,Shipsanity: Dulse Seaweed,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8023,Shipping,Shipsanity: Ferngill Primrose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8024,Shipping,Shipsanity: Flower Cookie,SHIPSANITY,Stardew Valley Expanded +8025,Shipping,Shipsanity: Frog,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8026,Shipping,Shipsanity: Frog Legs,SHIPSANITY,Stardew Valley Expanded +8027,Shipping,Shipsanity: Fungus Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8029,Shipping,Shipsanity: Gemfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8030,Shipping,Shipsanity: Glazed Butterfish,"SHIPSANITY",Stardew Valley Expanded +8031,Shipping,Shipsanity: Golden Ocean Flower,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8032,Shipping,Shipsanity: Goldenfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8033,Shipping,Shipsanity: Goldenrod,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8034,Shipping,Shipsanity: Grampleton Orange Chicken,SHIPSANITY,Stardew Valley Expanded +8035,Shipping,Shipsanity: Grass Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8036,Shipping,Shipsanity: Gravity Elixir,SHIPSANITY,Stardew Valley Expanded +8037,Shipping,Shipsanity: Green Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8038,Shipping,Shipsanity: Haste Elixir,SHIPSANITY,Stardew Valley Expanded +8039,Shipping,Shipsanity: Hero Elixir,SHIPSANITY,Stardew Valley Expanded +8040,Shipping,Shipsanity: King Salmon,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8050,Shipping,Shipsanity: Kittyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8051,Shipping,Shipsanity: Lightning Elixir,SHIPSANITY,Stardew Valley Expanded +8052,Shipping,Shipsanity: Lucky Four Leaf Clover,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8053,Shipping,Shipsanity: Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded +8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8062,Shipping,Shipsanity: Poison Mushroom,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8063,Shipping,Shipsanity: Puppyfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8064,Shipping,Shipsanity: Radioactive Bass,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8065,Shipping,Shipsanity: Red Baneberry,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8066,Shipping,Shipsanity: Rusty Blade,SHIPSANITY,Stardew Valley Expanded +8067,Shipping,Shipsanity: Salal Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8068,Shipping,Shipsanity: Sea Sponge,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8069,Shipping,Shipsanity: Seahorse,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8070,Shipping,Shipsanity: Seaweed Salad,SHIPSANITY,Stardew Valley Expanded +8071,Shipping,Shipsanity: Shiny Lunaloo,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8072,Shipping,Shipsanity: Shrub Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8073,Shipping,Shipsanity: Slime Berry,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8074,Shipping,Shipsanity: Slime Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8075,Shipping,Shipsanity: Smelly Rafflesia,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8076,Shipping,Shipsanity: Sports Drink,SHIPSANITY,Stardew Valley Expanded +8077,Shipping,Shipsanity: Stalk Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8078,Shipping,Shipsanity: Stamina Capsule,SHIPSANITY,Stardew Valley Expanded +8079,Shipping,Shipsanity: Starfish,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8080,Shipping,Shipsanity: Swirl Stone,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8081,Shipping,Shipsanity: Thistle,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8082,Shipping,Shipsanity: Torpedo Trout,"SHIPSANITY,SHIPSANITY_FISH,GINGER_ISLAND",Stardew Valley Expanded +8083,Shipping,Shipsanity: Undeadfish,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8084,Shipping,Shipsanity: Void Delight,SHIPSANITY,Stardew Valley Expanded +8085,Shipping,Shipsanity: Void Eel,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8086,Shipping,Shipsanity: Void Pebble,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8087,Shipping,Shipsanity: Void Root,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8088,Shipping,Shipsanity: Void Salmon Sushi,SHIPSANITY,Stardew Valley Expanded +8089,Shipping,Shipsanity: Void Seed,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded +8090,Shipping,Shipsanity: Void Shard,SHIPSANITY,Stardew Valley Expanded +8091,Shipping,Shipsanity: Void Soul,SHIPSANITY,Stardew Valley Expanded +8092,Shipping,Shipsanity: Water Grub,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded +8093,Shipping,Shipsanity: Winter Star Rose,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8094,Shipping,Shipsanity: Wooden Display: Amphibian Fossil,SHIPSANITY,Archaeology +8095,Shipping,Shipsanity: Hardwood Display: Amphibian Fossil,SHIPSANITY,Archaeology +8096,Shipping,Shipsanity: Wooden Display: Anchor,SHIPSANITY,Archaeology +8097,Shipping,Shipsanity: Hardwood Display: Anchor,SHIPSANITY,Archaeology +8098,Shipping,Shipsanity: Wooden Display: Ancient Doll,SHIPSANITY,Archaeology +8099,Shipping,Shipsanity: Hardwood Display: Ancient Doll,SHIPSANITY,Archaeology +8100,Shipping,Shipsanity: Wooden Display: Ancient Drum,SHIPSANITY,Archaeology +8101,Shipping,Shipsanity: Hardwood Display: Ancient Drum,SHIPSANITY,Archaeology +8102,Shipping,Shipsanity: Wooden Display: Ancient Seed,SHIPSANITY,Archaeology +8103,Shipping,Shipsanity: Hardwood Display: Ancient Seed,SHIPSANITY,Archaeology +8104,Shipping,Shipsanity: Wooden Display: Ancient Sword,SHIPSANITY,Archaeology +8105,Shipping,Shipsanity: Hardwood Display: Ancient Sword,SHIPSANITY,Archaeology +8106,Shipping,Shipsanity: Wooden Display: Arrowhead,SHIPSANITY,Archaeology +8107,Shipping,Shipsanity: Hardwood Display: Arrowhead,SHIPSANITY,Archaeology +8108,Shipping,Shipsanity: Wooden Display: Bone Flute,SHIPSANITY,Archaeology +8109,Shipping,Shipsanity: Hardwood Display: Bone Flute,SHIPSANITY,Archaeology +8110,Shipping,Shipsanity: Wooden Display: Chewing Stick,SHIPSANITY,Archaeology +8111,Shipping,Shipsanity: Hardwood Display: Chewing Stick,SHIPSANITY,Archaeology +8112,Shipping,Shipsanity: Wooden Display: Chicken Statue,SHIPSANITY,Archaeology +8113,Shipping,Shipsanity: Hardwood Display: Chicken Statue,SHIPSANITY,Archaeology +8114,Shipping,Shipsanity: Wooden Display: Chipped Amphora,SHIPSANITY,Archaeology +8115,Shipping,Shipsanity: Hardwood Display: Chipped Amphora,SHIPSANITY,Archaeology +8116,Shipping,Shipsanity: Wooden Display: Dinosaur Egg,SHIPSANITY,Archaeology +8117,Shipping,Shipsanity: Hardwood Display: Dinosaur Egg,SHIPSANITY,Archaeology +8118,Shipping,Shipsanity: Wooden Display: Dried Starfish,SHIPSANITY,Archaeology +8119,Shipping,Shipsanity: Hardwood Display: Dried Starfish,SHIPSANITY,Archaeology +8120,Shipping,Shipsanity: Wooden Display: Dwarf Gadget,SHIPSANITY,Archaeology +8121,Shipping,Shipsanity: Hardwood Display: Dwarf Gadget,SHIPSANITY,Archaeology +8122,Shipping,Shipsanity: Wooden Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8123,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll I,SHIPSANITY,Archaeology +8124,Shipping,Shipsanity: Wooden Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8125,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll II,SHIPSANITY,Archaeology +8126,Shipping,Shipsanity: Wooden Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8127,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll III,SHIPSANITY,Archaeology +8128,Shipping,Shipsanity: Wooden Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8129,Shipping,Shipsanity: Hardwood Display: Dwarf Scroll IV,SHIPSANITY,Archaeology +8130,Shipping,Shipsanity: Wooden Display: Dwarvish Helm,SHIPSANITY,Archaeology +8131,Shipping,Shipsanity: Hardwood Display: Dwarvish Helm,SHIPSANITY,Archaeology +8132,Shipping,Shipsanity: Wooden Display: Elvish Jewelry,SHIPSANITY,Archaeology +8133,Shipping,Shipsanity: Hardwood Display: Elvish Jewelry,SHIPSANITY,Archaeology +8134,Shipping,Shipsanity: Wooden Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8135,Shipping,Shipsanity: Hardwood Display: Fossilized Leg,"SHIPSANITY,GINGER_ISLAND",Archaeology +8136,Shipping,Shipsanity: Wooden Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8137,Shipping,Shipsanity: Hardwood Display: Fossilized Ribs,"SHIPSANITY,GINGER_ISLAND",Archaeology +8138,Shipping,Shipsanity: Wooden Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8139,Shipping,Shipsanity: Hardwood Display: Fossilized Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8140,Shipping,Shipsanity: Wooden Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8141,Shipping,Shipsanity: Hardwood Display: Fossilized Spine,"SHIPSANITY,GINGER_ISLAND",Archaeology +8142,Shipping,Shipsanity: Wooden Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8143,Shipping,Shipsanity: Hardwood Display: Fossilized Tail,"SHIPSANITY,GINGER_ISLAND",Archaeology +8144,Shipping,Shipsanity: Wooden Display: Glass Shards,SHIPSANITY,Archaeology +8145,Shipping,Shipsanity: Hardwood Display: Glass Shards,SHIPSANITY,Archaeology +8146,Shipping,Shipsanity: Wooden Display: Golden Mask,SHIPSANITY,Archaeology +8147,Shipping,Shipsanity: Hardwood Display: Golden Mask,SHIPSANITY,Archaeology +8148,Shipping,Shipsanity: Wooden Display: Golden Relic,SHIPSANITY,Archaeology +8149,Shipping,Shipsanity: Hardwood Display: Golden Relic,SHIPSANITY,Archaeology +8150,Shipping,Shipsanity: Wooden Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8151,Shipping,Shipsanity: Hardwood Display: Mummified Bat,"SHIPSANITY,GINGER_ISLAND",Archaeology +8152,Shipping,Shipsanity: Wooden Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8153,Shipping,Shipsanity: Hardwood Display: Mummified Frog,"SHIPSANITY,GINGER_ISLAND",Archaeology +8154,Shipping,Shipsanity: Wooden Display: Nautilus Fossil,SHIPSANITY,Archaeology +8155,Shipping,Shipsanity: Hardwood Display: Nautilus Fossil,SHIPSANITY,Archaeology +8156,Shipping,Shipsanity: Wooden Display: Ornamental Fan,SHIPSANITY,Archaeology +8157,Shipping,Shipsanity: Hardwood Display: Ornamental Fan,SHIPSANITY,Archaeology +8158,Shipping,Shipsanity: Wooden Display: Palm Fossil,SHIPSANITY,Archaeology +8159,Shipping,Shipsanity: Hardwood Display: Palm Fossil,SHIPSANITY,Archaeology +8160,Shipping,Shipsanity: Wooden Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8161,Shipping,Shipsanity: Hardwood Display: Prehistoric Handaxe,SHIPSANITY,Archaeology +8162,Shipping,Shipsanity: Wooden Display: Prehistoric Rib,SHIPSANITY,Archaeology +8163,Shipping,Shipsanity: Hardwood Display: Prehistoric Rib,SHIPSANITY,Archaeology +8164,Shipping,Shipsanity: Wooden Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8165,Shipping,Shipsanity: Hardwood Display: Prehistoric Scapula,SHIPSANITY,Archaeology +8166,Shipping,Shipsanity: Wooden Display: Prehistoric Skull,SHIPSANITY,Archaeology +8167,Shipping,Shipsanity: Hardwood Display: Prehistoric Skull,SHIPSANITY,Archaeology +8168,Shipping,Shipsanity: Wooden Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8169,Shipping,Shipsanity: Hardwood Display: Prehistoric Tibia,SHIPSANITY,Archaeology +8170,Shipping,Shipsanity: Wooden Display: Prehistoric Tool,SHIPSANITY,Archaeology +8171,Shipping,Shipsanity: Hardwood Display: Prehistoric Tool,SHIPSANITY,Archaeology +8172,Shipping,Shipsanity: Wooden Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8173,Shipping,Shipsanity: Hardwood Display: Prehistoric Vertebra,SHIPSANITY,Archaeology +8174,Shipping,Shipsanity: Wooden Display: Rare Disc,SHIPSANITY,Archaeology +8175,Shipping,Shipsanity: Hardwood Display: Rare Disc,SHIPSANITY,Archaeology +8176,Shipping,Shipsanity: Wooden Display: Rusty Cog,SHIPSANITY,Archaeology +8177,Shipping,Shipsanity: Hardwood Display: Rusty Cog,SHIPSANITY,Archaeology +8178,Shipping,Shipsanity: Wooden Display: Rusty Spoon,SHIPSANITY,Archaeology +8179,Shipping,Shipsanity: Hardwood Display: Rusty Spoon,SHIPSANITY,Archaeology +8180,Shipping,Shipsanity: Wooden Display: Rusty Spur,SHIPSANITY,Archaeology +8181,Shipping,Shipsanity: Hardwood Display: Rusty Spur,SHIPSANITY,Archaeology +8182,Shipping,Shipsanity: Wooden Display: Skeletal Hand,SHIPSANITY,Archaeology +8183,Shipping,Shipsanity: Hardwood Display: Skeletal Hand,SHIPSANITY,Archaeology +8184,Shipping,Shipsanity: Wooden Display: Skeletal Tail,SHIPSANITY,Archaeology +8185,Shipping,Shipsanity: Hardwood Display: Skeletal Tail,SHIPSANITY,Archaeology +8186,Shipping,Shipsanity: Wooden Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8187,Shipping,Shipsanity: Hardwood Display: Snake Skull,"SHIPSANITY,GINGER_ISLAND",Archaeology +8188,Shipping,Shipsanity: Wooden Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8189,Shipping,Shipsanity: Hardwood Display: Snake Vertebrae,"SHIPSANITY,GINGER_ISLAND",Archaeology +8190,Shipping,Shipsanity: Wooden Display: Strange Doll (Green),SHIPSANITY,Archaeology +8191,Shipping,Shipsanity: Hardwood Display: Strange Doll (Green),SHIPSANITY,Archaeology +8192,Shipping,Shipsanity: Wooden Display: Strange Doll,SHIPSANITY,Archaeology +8193,Shipping,Shipsanity: Hardwood Display: Strange Doll,SHIPSANITY,Archaeology +8194,Shipping,Shipsanity: Wooden Display: Trilobite Fossil,SHIPSANITY,Archaeology +8195,Shipping,Shipsanity: Hardwood Display: Trilobite Fossil,SHIPSANITY,Archaeology +8196,Shipping,Shipsanity: Bone Path,SHIPSANITY,Archaeology +8197,Shipping,Shipsanity: Glass Fence,SHIPSANITY,Archaeology +8198,Shipping,Shipsanity: Glass Path,SHIPSANITY,Archaeology +8199,Shipping,Shipsanity: Hardwood Display,SHIPSANITY,Archaeology +8200,Shipping,Shipsanity: Wooden Display,SHIPSANITY,Archaeology +8201,Shipping,Shipsanity: Dwarf Gadget: Infinite Volcano Simulation,"SHIPSANITY,GINGER_ISLAND",Archaeology +8202,Shipping,Shipsanity: Water Shifter,SHIPSANITY,Archaeology +8203,Shipping,Shipsanity: Brown Amanita,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8204,Shipping,Shipsanity: Swamp Herb,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8205,Shipping,Shipsanity: Void Mint Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8206,Shipping,Shipsanity: Vile Ancient Fruit Seeds,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8207,Shipping,Shipsanity: Void Mint Leaves,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8208,Shipping,Shipsanity: Vile Ancient Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Distant Lands - Witch Swamp Overhaul +8209,Shipping,Shipsanity: Void Minnow,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8210,Shipping,Shipsanity: Swamp Leech,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8211,Shipping,Shipsanity: Purple Algae,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8212,Shipping,Shipsanity: Giant Horsehoe Crab,"SHIPSANITY,SHIPSANITY_FISH",Distant Lands - Witch Swamp Overhaul +8213,Shipping,Shipsanity: Mushroom Kebab,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8214,Shipping,Shipsanity: Crayfish Soup,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8215,Shipping,Shipsanity: Pemmican,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8216,Shipping,Shipsanity: Void Mint Tea,SHIPSANITY,Distant Lands - Witch Swamp Overhaul +8217,Shipping,Shipsanity: Ginger Tincture,"SHIPSANITY,GINGER_ISLAND",Distant Lands - Witch Swamp Overhaul +8218,Shipping,Shipsanity: Neanderthal Limb Bones,SHIPSANITY,Boarding House and Bus Stop Extension +8219,Shipping,Shipsanity: Dinosaur Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8220,Shipping,Shipsanity: Special Pumpkin Soup,SHIPSANITY,Boarding House and Bus Stop Extension +8221,Shipping,Shipsanity: Pterodactyl L Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension +8222,Shipping,Shipsanity: Dinosaur Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8223,Shipping,Shipsanity: Dinosaur Tooth,SHIPSANITY,Boarding House and Bus Stop Extension +8224,Shipping,Shipsanity: Pterodactyl Egg,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Boarding House and Bus Stop Extension +8225,Shipping,Shipsanity: Pterodactyl Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8226,Shipping,Shipsanity: Dinosaur Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8227,Shipping,Shipsanity: Neanderthal Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8228,Shipping,Shipsanity: Dinosaur Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8229,Shipping,Shipsanity: Dinosaur Ribs,SHIPSANITY,Boarding House and Bus Stop Extension +8230,Shipping,Shipsanity: Pterodactyl Phalange,SHIPSANITY,Boarding House and Bus Stop Extension +8231,Shipping,Shipsanity: Pterodactyl Vertebra,SHIPSANITY,Boarding House and Bus Stop Extension +8232,Shipping,Shipsanity: Neanderthal Pelvis,SHIPSANITY,Boarding House and Bus Stop Extension +8233,Shipping,Shipsanity: Pterodactyl Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8234,Shipping,Shipsanity: Dinosaur Femur,SHIPSANITY,Boarding House and Bus Stop Extension +8235,Shipping,Shipsanity: Pterodactyl Claw,SHIPSANITY,Boarding House and Bus Stop Extension +8236,Shipping,Shipsanity: Neanderthal Skull,SHIPSANITY,Boarding House and Bus Stop Extension +8237,Shipping,Shipsanity: Pterodactyl R Wing Bone,SHIPSANITY,Boarding House and Bus Stop Extension From 037d72139b8b9007ff93fc6b3177177ae25411be Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 24 Jan 2024 19:29:10 -0500 Subject: [PATCH 462/482] - Don't count Victory as a progression item to be counted --- worlds/stardew_valley/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 24419d9dd3f4..f15287e76c0e 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -268,7 +268,7 @@ def create_item(self, item: Union[str, ItemData], override_classification: ItemC if override_classification is None: override_classification = item.classification - if override_classification == ItemClassification.progression: + if override_classification == ItemClassification.progression and item.name != Event.victory: self.total_progression_items += 1 return StardewItem(item.name, override_classification, item.code, self.player) From b0073fa6f367ba3bda598d25ad34e4987e1bc646 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 24 Jan 2024 20:11:25 -0500 Subject: [PATCH 463/482] - Removed furnace recipe as it doesn't fit the current scheme --- worlds/stardew_valley/data/items.csv | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index afc45afc5dcb..cfcb6adea203 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -430,7 +430,6 @@ id,name,classification,groups,mod_name 454,Marble Brazier Recipe,progression,CRAFTSANITY, 455,Wood Lamp-post Recipe,progression,CRAFTSANITY, 456,Iron Lamp-post Recipe,progression,CRAFTSANITY, -457,Furnace Recipe,progression,CRAFTSANITY, 458,Wicked Statue Recipe,progression,CRAFTSANITY, 459,Chest Recipe,progression,CRAFTSANITY, 460,Wood Sign Recipe,progression,CRAFTSANITY, From cbdf663219886ee305e689e163ca23a753566f2e Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 24 Jan 2024 20:32:23 -0500 Subject: [PATCH 464/482] - Fixed where Lacey lives --- worlds/stardew_valley/data/villagers_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/data/villagers_data.py b/worlds/stardew_valley/data/villagers_data.py index 6c8943abb67e..e2479fe0440f 100644 --- a/worlds/stardew_valley/data/villagers_data.py +++ b/worlds/stardew_valley/data/villagers_data.py @@ -427,7 +427,7 @@ def register_villager_modification(mod_name: str, npc: Villager, modification_fu riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley) zic = villager(ModNPC.goblin, False, witch_swamp, Season.fall, void_mayonnaise, False, ModNames.distant_lands) alecto = villager(ModNPC.alecto, False, witch_attic, Generic.any, universal_loves, False, ModNames.alecto) -lacey = villager(ModNPC.lacey, True, hat_house, Season.spring, universal_loves, True, ModNames.lacey) +lacey = villager(ModNPC.lacey, True, forest, Season.spring, universal_loves, True, ModNames.lacey) # Boarding House Villagers gregory = villager(ModNPC.gregory, True, the_lost_valley, Season.fall, universal_loves, False, ModNames.boarding_house) From 33e9e9753f186a7698f2decb6d2ed9e6e45acae2 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 24 Jan 2024 20:38:43 -0500 Subject: [PATCH 465/482] - Fixed an error with the furnace recipe --- worlds/stardew_valley/data/craftable_data.py | 2 +- worlds/stardew_valley/logic/skill_logic.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/craftable_data.py b/worlds/stardew_valley/data/craftable_data.py index 0fa041551c2f..bfb2d25ec6b8 100644 --- a/worlds/stardew_valley/data/craftable_data.py +++ b/worlds/stardew_valley/data/craftable_data.py @@ -224,7 +224,7 @@ def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, bone_mill = special_order_recipe(Machine.bone_mill, SpecialOrder.fragments_of_the_past, {Fossil.bone_fragment: 10, Material.clay: 3, Material.stone: 20}) charcoal_kiln = skill_recipe(Machine.charcoal_kiln, Skill.foraging, 4, {Material.wood: 20, MetalBar.copper: 2}) crystalarium = skill_recipe(Machine.crystalarium, Skill.mining, 9, {Material.stone: 99, MetalBar.gold: 5, MetalBar.iridium: 2, ArtisanGood.battery_pack: 1}) -furnace = starter_recipe(Machine.furnace, {Ore.copper: 20, Material.stone: 25}) +furnace = skill_recipe(Machine.furnace, Skill.mining, 1, {Ore.copper: 20, Material.stone: 25}) geode_crusher = special_order_recipe(Machine.geode_crusher, SpecialOrder.cave_patrol, {MetalBar.gold: 2, Material.stone: 50, Mineral.diamond: 1}) heavy_tapper = ap_recipe(Machine.heavy_tapper, {Material.hardwood: 30, MetalBar.radioactive: 1}) lightning_rod = skill_recipe(Machine.lightning_rod, Skill.foraging, 6, {MetalBar.iron: 1, MetalBar.quartz: 1, Loot.bat_wing: 5}) diff --git a/worlds/stardew_valley/logic/skill_logic.py b/worlds/stardew_valley/logic/skill_logic.py index 77a1ec72225f..ff14e77d53d7 100644 --- a/worlds/stardew_valley/logic/skill_logic.py +++ b/worlds/stardew_valley/logic/skill_logic.py @@ -55,12 +55,13 @@ def can_earn_level(self, skill: str, level: int) -> StardewRule: tool_material) | self.logic.magic.can_use_clear_debris_instead_of_tool_level( tool_level) elif skill == Skill.mining: - xp_rule = self.logic.tool.has_tool(Tool.pickaxe, - tool_material) | self.logic.magic.can_use_clear_debris_instead_of_tool_level( - tool_level) + xp_rule = self.logic.tool.has_tool(Tool.pickaxe, tool_material) |\ + self.logic.magic.can_use_clear_debris_instead_of_tool_level(tool_level) + xp_rule = xp_rule & self.logic.region.can_reach(Region.mines_floor_5) elif skill == Skill.combat: combat_tier = Performance.tiers[tool_level] xp_rule = self.logic.combat.can_fight_at_level(combat_tier) + xp_rule = xp_rule & self.logic.region.can_reach(Region.mines_floor_5) else: raise Exception(f"Unknown skill: {skill}") From 1566bb6d8d619ea3ad56755bb2e1c60eab8416e8 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 12:43:36 -0500 Subject: [PATCH 466/482] - Don't create regions or entrances for Ginger Island stuff when island is excluded - Related refactoring and fixes to also not create related rules of course --- worlds/stardew_valley/mods/mod_regions.py | 6 +- worlds/stardew_valley/region_classes.py | 4 + worlds/stardew_valley/regions.py | 84 +++-- worlds/stardew_valley/rules.py | 328 ++++++++---------- worlds/stardew_valley/stardew_rule/state.py | 2 + worlds/stardew_valley/test/TestOptions.py | 2 +- worlds/stardew_valley/test/TestRegions.py | 31 +- .../test/checks/world_checks.py | 22 +- worlds/stardew_valley/test/mods/TestMods.py | 13 +- 9 files changed, 252 insertions(+), 240 deletions(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 7d99d663fc6a..9e87da685db2 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -1,3 +1,5 @@ +from typing import Dict, List + from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, LaceyEntrance, BoardingHouseEntrance, \ JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance, AlectoEntrance from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, BoardingHouseRegion, \ @@ -219,7 +221,7 @@ ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside), + ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp), @@ -350,7 +352,7 @@ ] -vanilla_connections_to_remove_by_mod = { +vanilla_connections_to_remove_by_mod: Dict[str, List[ConnectionData]] = { ModNames.sve: [ConnectionData(Entrance.mountain_to_the_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.mountain_to_adventurer_guild, Region.adventurer_guild, diff --git a/worlds/stardew_valley/region_classes.py b/worlds/stardew_valley/region_classes.py index 41ff65d1294a..eaabcfa5fd36 100644 --- a/worlds/stardew_valley/region_classes.py +++ b/worlds/stardew_valley/region_classes.py @@ -34,6 +34,10 @@ def get_merged_with(self, exits: List[str]): merged_exits = list(set(merged_exits)) return RegionData(self.name, merged_exits) + def get_without_exit(self, exit_to_remove: str): + exits = [exit for exit in self.exits if exit != exit_to_remove] + return RegionData(self.name, exits) + def get_clone(self): return self.get_merged_with(None) diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index 20d8a5b0e88a..e0c9aae4a1fd 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -256,7 +256,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.enter_slime_hutch, Region.slime_hutch), ConnectionData(Entrance.shipping, Region.shipping), ConnectionData(Entrance.use_desert_obelisk, Region.desert), - ConnectionData(Entrance.use_island_obelisk, Region.island_south), + ConnectionData(Entrance.use_island_obelisk, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.use_farm_obelisk, Region.farm), ConnectionData(Entrance.backwoods_to_mountain, Region.mountain), ConnectionData(Entrance.bus_stop_to_town, Region.town), @@ -352,7 +352,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(Entrance.fish_shop_to_boat_tunnel, Region.boat_tunnel, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.boat_to_ginger_island, Region.island_south), + ConnectionData(Entrance.boat_to_ginger_island, Region.island_south, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.enter_tide_pools, Region.tide_pools), ConnectionData(Entrance.fishing, Region.fishing), ConnectionData(Entrance.mountain_to_the_mines, Region.mines, @@ -413,7 +413,7 @@ def __call__(self, name: str, regions: Iterable[str]) -> Region: ConnectionData(Entrance.island_south_to_east, Region.island_east, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_south_to_southeast, Region.island_south_east, flag=RandomizationFlag.GINGER_ISLAND), - ConnectionData(Entrance.use_island_resort, Region.island_resort), + ConnectionData(Entrance.use_island_resort, Region.island_resort, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_west_to_islandfarmhouse, Region.island_farmhouse, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(Entrance.island_cooking, Region.kitchen), @@ -488,19 +488,37 @@ def create_final_regions(world_options) -> List[RegionData]: return final_regions -def create_final_connections(world_options) -> List[ConnectionData]: - final_connections = [] - final_connections.extend(vanilla_connections) - if world_options.mods is None: - return final_connections - for mod in world_options.mods.value: +def create_final_connections_and_regions(world_options) -> Tuple[Dict[str, ConnectionData], Dict[str, RegionData]]: + regions_data: Dict[str, RegionData] = {region.name: region for region in create_final_regions(world_options)} + connections = {connection.name: connection for connection in vanilla_connections} + connections = modify_connections_for_mods(connections, world_options.mods) + include_island = world_options.exclude_ginger_island == ExcludeGingerIsland.option_false + return remove_ginger_island_regions_and_connections(regions_data, connections, include_island) + + +def remove_ginger_island_regions_and_connections(regions_by_name: Dict[str, RegionData], connections: Dict[str, ConnectionData], include_island: bool): + if include_island: + return connections, regions_by_name + for connection_name in list(connections): + connection = connections[connection_name] + if connection.flag & RandomizationFlag.GINGER_ISLAND: + regions_by_name.pop(connection.destination, None) + connections.pop(connection_name) + regions_by_name = {name: regions_by_name[name].get_without_exit(connection_name) for name in regions_by_name} + return connections, regions_by_name + + +def modify_connections_for_mods(connections: Dict[str, ConnectionData], mods) -> Dict[str, ConnectionData]: + if mods is None: + return connections + for mod in mods.value: if mod not in ModDataList: continue if mod in vanilla_connections_to_remove_by_mod: for connection_data in vanilla_connections_to_remove_by_mod[mod]: - final_connections.remove(connection_data) - final_connections.extend(ModDataList[mod].connections) - return final_connections + connections.pop(connection_data.name) + connections.update({connection.name: connection for connection in ModDataList[mod].connections}) + return connections def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionData) -> RegionData: @@ -516,36 +534,34 @@ def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionD def create_regions(region_factory: RegionFactory, random: Random, world_options: StardewValleyOptions) -> Tuple[ Dict[str, Region], Dict[str, str]]: - final_regions = create_final_regions(world_options) - regions: Dict[str: Region] = {region.name: region_factory(region.name, region.exits) for region in final_regions} - entrances: Dict[str: Entrance] = {entrance.name: entrance for region in regions.values() for entrance in region.exits} + entrances_data, regions_data = create_final_connections_and_regions(world_options) + regions_by_name: Dict[str: Region] = {region_name: region_factory(region_name, regions_data[region_name].exits) for region_name in regions_data} + entrances_by_name: Dict[str: Entrance] = {entrance.name: entrance for region in regions_by_name.values() for entrance in region.exits + if entrance.name in entrances_data} - regions_by_name: Dict[str, RegionData] = {region.name: region for region in final_regions} - connections, randomized_data = randomize_connections(random, world_options, regions_by_name) + connections, randomized_data = randomize_connections(random, world_options, regions_data, entrances_data) for connection in connections: - if connection.name in entrances: - entrances[connection.name].connect(regions[connection.destination]) - return regions, randomized_data + if connection.name in entrances_by_name: + entrances_by_name[connection.name].connect(regions_by_name[connection.destination]) + return regions_by_name, randomized_data -def randomize_connections(random: Random, world_options: StardewValleyOptions, regions_by_name: Dict[str, RegionData])\ - -> Tuple[List[ConnectionData], Dict[str, str]]: +def randomize_connections(random: Random, world_options: StardewValleyOptions, regions_by_name: Dict[str, RegionData], + connections_by_name: Dict[str, ConnectionData]) -> Tuple[List[ConnectionData], Dict[str, str]]: connections_to_randomize: List[ConnectionData] = [] - final_connections = create_final_connections(world_options) - connections_by_name: Dict[str, ConnectionData] = {connection.name: connection for connection in final_connections} if world_options.entrance_randomization == EntranceRandomization.option_pelican_town: - connections_to_randomize = [connection for connection in final_connections if - RandomizationFlag.PELICAN_TOWN in connection.flag] + connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if + RandomizationFlag.PELICAN_TOWN in connections_by_name[connection].flag] elif world_options.entrance_randomization == EntranceRandomization.option_non_progression: - connections_to_randomize = [connection for connection in final_connections if - RandomizationFlag.NON_PROGRESSION in connection.flag] + connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if + RandomizationFlag.NON_PROGRESSION in connections_by_name[connection].flag] elif world_options.entrance_randomization == EntranceRandomization.option_buildings: - connections_to_randomize = [connection for connection in final_connections if - RandomizationFlag.BUILDINGS in connection.flag] + connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if + RandomizationFlag.BUILDINGS in connections_by_name[connection].flag] elif world_options.entrance_randomization == EntranceRandomization.option_chaos: - connections_to_randomize = [connection for connection in final_connections if - RandomizationFlag.BUILDINGS in connection.flag] + connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if + RandomizationFlag.BUILDINGS in connections_by_name[connection].flag] connections_to_randomize = remove_excluded_entrances(connections_to_randomize, world_options) # On Chaos, we just add the connections to randomize, unshuffled, and the client does it every day @@ -553,7 +569,7 @@ def randomize_connections(random: Random, world_options: StardewValleyOptions, r for connection in connections_to_randomize: randomized_data_for_mod[connection.name] = connection.name randomized_data_for_mod[connection.reverse] = connection.reverse - return final_connections, randomized_data_for_mod + return list(connections_by_name.values()), randomized_data_for_mod connections_to_randomize = remove_excluded_entrances(connections_to_randomize, world_options) random.shuffle(connections_to_randomize) @@ -561,7 +577,7 @@ def randomize_connections(random: Random, world_options: StardewValleyOptions, r random.shuffle(destination_pool) randomized_connections = randomize_chosen_connections(connections_to_randomize, destination_pool) - add_non_randomized_connections(final_connections, connections_to_randomize, randomized_connections) + add_non_randomized_connections(list(connections_by_name.values()), connections_to_randomize, randomized_connections) swap_connections_until_valid(regions_by_name, connections_by_name, randomized_connections, connections_to_randomize, random) randomized_connections_for_generation = create_connections_for_generation(randomized_connections) diff --git a/worlds/stardew_valley/rules.py b/worlds/stardew_valley/rules.py index 72d907f42ee7..b9ca581d04df 100644 --- a/worlds/stardew_valley/rules.py +++ b/worlds/stardew_valley/rules.py @@ -1,5 +1,5 @@ import itertools -from typing import List +from typing import List, Dict from BaseClasses import MultiWorld from worlds.generic import Rules as MultiWorldRules @@ -12,6 +12,7 @@ from .locations import LocationTags from .logic.logic import StardewLogic from .logic.tool_logic import tool_upgrade_prices +from .logic.time_logic import MAX_MONTHS from .mods.mod_data import ModNames from .options import StardewValleyOptions, Friendsanity from .options import ToolProgression, BuildingProgression, ExcludeGingerIsland, SpecialOrderLocations, Museumsanity, BackpackProgression, Shipsanity, \ @@ -20,26 +21,26 @@ from .strings.ap_names.event_names import Event from .strings.ap_names.mods.mod_items import SVEQuestItem, SVERunes from .strings.ap_names.transport_names import Transportation -from .strings.ap_names.mods.mod_items import SVELocation from .strings.artisan_good_names import ArtisanGood from .strings.building_names import Building from .strings.bundle_names import CCRoom from .strings.calendar_names import Weekday from .strings.craftable_names import Bomb from .strings.crop_names import Fruit -from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, MagicEntrance, \ +from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, \ SVEEntrance, LaceyEntrance, BoardingHouseEntrance from .strings.generic_names import Generic from .strings.material_names import Material from .strings.metal_names import MetalBar -from .strings.quest_names import Quest, ModQuest -from .strings.region_names import Region, SVERegion +from .strings.quest_names import Quest +from .strings.region_names import Region from .strings.season_names import Season from .strings.skill_names import ModSkill, Skill from .strings.tool_names import Tool, ToolMaterial from .strings.tv_channel_names import Channel from .strings.villager_names import NPC, ModNPC from .strings.wallet_item_names import Wallet +from ..generic.Rules import CollectionRule def set_rules(world): @@ -189,91 +190,69 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S set_blacksmith_entrance_rules(logic, multiworld, player) set_skill_entrance_rules(logic, multiworld, player) set_traveling_merchant_day_rules(logic, multiworld, player) - - dangerous_mine_rule = logic.mine.has_mine_elevator_to_floor(120) & logic.region.can_reach(Region.qi_walnut_room) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_20, player), - dangerous_mine_rule) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_60, player), - dangerous_mine_rule) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_to_dangerous_mines_100, player), - dangerous_mine_rule) - - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_tide_pools, player), - logic.received("Beach Bridge") | (logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_quarry, player), - logic.received("Bridge Repair") | (logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_secret_woods, player), - logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_sewer, player), - logic.wallet.has_rusty_key()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.town_to_sewer, player), - logic.wallet.has_rusty_key()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_abandoned_jojamart, player), - logic.has_abandoned_jojamart()) + set_dangerous_mine_rules(logic, multiworld, player, world_options) + + set_entrance_rule(multiworld, player, Entrance.enter_tide_pools, logic.received("Beach Bridge") | (logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, Entrance.enter_quarry, logic.received("Bridge Repair") | (logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, Entrance.enter_secret_woods, logic.tool.has_tool(Tool.axe, "Iron") | (logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, Entrance.forest_to_sewer, logic.wallet.has_rusty_key()) + set_entrance_rule(multiworld, player, Entrance.town_to_sewer, logic.wallet.has_rusty_key()) + set_entrance_rule(multiworld, player, Entrance.enter_abandoned_jojamart, logic.has_abandoned_jojamart()) movie_theater_rule = logic.has_movie_theater() - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_movie_theater, player), - movie_theater_rule) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.purchase_movie_ticket, player), - movie_theater_rule) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.take_bus_to_desert, player), - logic.received("Bus Repair")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_skull_cavern, player), - logic.received(Wallet.skull_key)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_dangerous_skull_cavern, player), - (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room))) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_mines_dwarf, player), - logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.buy_from_traveling_merchant, player), - logic.traveling_merchant.has_days()) - - set_farm_buildings_entrance_rules(logic, multiworld, player) - - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_railroad, player), - logic.received("Railroad Boulder Removed")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_warp_cave, player), - logic.quest.has_dark_talisman() | (logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_witch_hut, player), - (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_mutant_bug_lair, player), - (logic.received(Event.start_dark_talisman_quest) & logic.relationship.can_meet(NPC.krobus)) | logic.mod.magic.can_blink()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_casino, player), - logic.quest.has_club_card()) + set_entrance_rule(multiworld, player, Entrance.enter_movie_theater, movie_theater_rule) + set_entrance_rule(multiworld, player, Entrance.purchase_movie_ticket, movie_theater_rule) + set_entrance_rule(multiworld, player, Entrance.take_bus_to_desert, logic.received("Bus Repair")) + set_entrance_rule(multiworld, player, Entrance.enter_skull_cavern, logic.received(Wallet.skull_key)) + set_entrance_rule(multiworld, player, Entrance.talk_to_mines_dwarf, logic.wallet.can_speak_dwarf() & logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron)) + set_entrance_rule(multiworld, player, Entrance.buy_from_traveling_merchant, logic.traveling_merchant.has_days()) + + set_farm_buildings_entrance_rules(logic, multiworld, player, world_options) + + set_entrance_rule(multiworld, player, Entrance.mountain_to_railroad, logic.received("Railroad Boulder Removed")) + set_entrance_rule(multiworld, player, Entrance.enter_witch_warp_cave, logic.quest.has_dark_talisman() | (logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, Entrance.enter_witch_hut, (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, Entrance.enter_mutant_bug_lair, (logic.received(Event.start_dark_talisman_quest) & logic.relationship.can_meet(NPC.krobus)) | logic.mod.magic.can_blink()) + set_entrance_rule(multiworld, player, Entrance.enter_casino, logic.quest.has_club_card()) set_bedroom_entrance_rules(logic, multiworld, player, world_options) set_festival_entrance_rules(logic, multiworld, player) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_cooking, player), logic.cooking.can_cook_in_kitchen) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farmhouse_cooking, player), logic.cooking.can_cook_in_kitchen) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.shipping, player), logic.shipping.can_use_shipping_bin) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.watch_queen_of_sauce, player), logic.action.can_watch(Channel.queen_of_sauce)) + set_island_entrance_rule(multiworld, player, Entrance.island_cooking, logic.cooking.can_cook_in_kitchen, world_options) + set_entrance_rule(multiworld, player, Entrance.farmhouse_cooking, logic.cooking.can_cook_in_kitchen) + set_entrance_rule(multiworld, player, Entrance.shipping, logic.shipping.can_use_shipping_bin) + set_entrance_rule(multiworld, player, Entrance.watch_queen_of_sauce, logic.action.can_watch(Channel.queen_of_sauce)) -def set_farm_buildings_entrance_rules(logic, multiworld, player): - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_desert_obelisk, player), logic.can_use_obelisk(Transportation.desert_obelisk)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_obelisk, player), logic.can_use_obelisk(Transportation.island_obelisk)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_farm_obelisk, player), logic.can_use_obelisk(Transportation.farm_obelisk)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_greenhouse, player), logic.received("Greenhouse")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_coop, player), logic.building.has_building(Building.coop)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_barn, player), logic.building.has_building(Building.barn)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_shed, player), logic.building.has_building(Building.shed)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_slime_hutch, player), logic.building.has_building(Building.slime_hutch)) +def set_dangerous_mine_rules(logic, multiworld, player, world_options: StardewValleyOptions): + if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: + return + dangerous_mine_rule = logic.mine.has_mine_elevator_to_floor(120) & logic.region.can_reach(Region.qi_walnut_room) + set_entrance_rule(multiworld, player, Entrance.dig_to_dangerous_mines_20, dangerous_mine_rule) + set_entrance_rule(multiworld, player, Entrance.dig_to_dangerous_mines_60, dangerous_mine_rule) + set_entrance_rule(multiworld, player, Entrance.dig_to_dangerous_mines_100, dangerous_mine_rule) + set_entrance_rule(multiworld, player, Entrance.enter_dangerous_skull_cavern, (logic.received(Wallet.skull_key) & logic.region.can_reach(Region.qi_walnut_room))) + + +def set_farm_buildings_entrance_rules(logic, multiworld, player, world_options): + set_entrance_rule(multiworld, player, Entrance.use_desert_obelisk, logic.can_use_obelisk(Transportation.desert_obelisk)) + set_entrance_rule(multiworld, player, Entrance.enter_greenhouse, logic.received("Greenhouse")) + set_entrance_rule(multiworld, player, Entrance.enter_coop, logic.building.has_building(Building.coop)) + set_entrance_rule(multiworld, player, Entrance.enter_barn, logic.building.has_building(Building.barn)) + set_entrance_rule(multiworld, player, Entrance.enter_shed, logic.building.has_building(Building.shed)) + set_entrance_rule(multiworld, player, Entrance.enter_slime_hutch, logic.building.has_building(Building.slime_hutch)) def set_bedroom_entrance_rules(logic, multiworld, player, world_options: StardewValleyOptions): - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_harvey_room, player), logic.relationship.has_hearts(NPC.harvey, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_maru_room, player), logic.relationship.has_hearts(NPC.maru, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sebastian_room, player), - (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.forest_to_leah_cottage, player), logic.relationship.has_hearts(NPC.leah, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_elliott_house, player), logic.relationship.has_hearts(NPC.elliott, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_sunroom, player), logic.relationship.has_hearts(NPC.caroline, 2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.enter_wizard_basement, player), logic.relationship.has_hearts(NPC.wizard, 4)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.mountain_to_leo_treehouse, player), logic.received("Treehouse")) + set_entrance_rule(multiworld, player, Entrance.enter_harvey_room, logic.relationship.has_hearts(NPC.harvey, 2)) + set_entrance_rule(multiworld, player, Entrance.mountain_to_maru_room, logic.relationship.has_hearts(NPC.maru, 2)) + set_entrance_rule(multiworld, player, Entrance.enter_sebastian_room, (logic.relationship.has_hearts(NPC.sebastian, 2) | logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, Entrance.forest_to_leah_cottage, logic.relationship.has_hearts(NPC.leah, 2)) + set_entrance_rule(multiworld, player, Entrance.enter_elliott_house, logic.relationship.has_hearts(NPC.elliott, 2)) + set_entrance_rule(multiworld, player, Entrance.enter_sunroom, logic.relationship.has_hearts(NPC.caroline, 2)) + set_entrance_rule(multiworld, player, Entrance.enter_wizard_basement, logic.relationship.has_hearts(NPC.wizard, 4)) if ModNames.alec in world_options.mods: - MultiWorldRules.set_rule(multiworld.get_entrance(AlecEntrance.petshop_to_bedroom, player), - (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink())) + set_entrance_rule(multiworld, player, AlecEntrance.petshop_to_bedroom, (logic.relationship.has_hearts(ModNPC.alec, 2) | logic.mod.magic.can_blink())) if ModNames.lacey in world_options.mods: - MultiWorldRules.set_rule(multiworld.get_entrance(LaceyEntrance.forest_to_hat_house, player), - logic.relationship.has_hearts(ModNPC.lacey, 2)) + set_entrance_rule(multiworld, player, LaceyEntrance.forest_to_hat_house, logic.relationship.has_hearts(ModNPC.lacey, 2)) def set_mines_floor_entrance_rules(logic, multiworld, player): @@ -302,10 +281,8 @@ def set_blacksmith_entrance_rules(logic, multiworld, player): def set_skill_entrance_rules(logic, multiworld, player): - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.farming, player), - logic.skill.can_get_farming_xp) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fishing, player), - logic.skill.can_get_fishing_xp) + set_entrance_rule(multiworld, player, Entrance.farming, logic.skill.can_get_farming_xp) + set_entrance_rule(multiworld, player, Entrance.fishing, logic.skill.can_get_fishing_xp) def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, item_name: str, tool_material: str): @@ -315,22 +292,22 @@ def set_blacksmith_upgrade_rule(logic, multiworld, player, entrance_name: str, i def set_festival_entrance_rules(logic, multiworld, player): - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_egg_festival, player), logic.season.has(Season.spring)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_flower_dance, player), logic.season.has(Season.spring)) + set_entrance_rule(multiworld, player, Entrance.attend_egg_festival, logic.season.has(Season.spring)) + set_entrance_rule(multiworld, player, Entrance.attend_flower_dance, logic.season.has(Season.spring)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_luau, player), logic.season.has(Season.summer)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_moonlight_jellies, player), logic.season.has(Season.summer)) + set_entrance_rule(multiworld, player, Entrance.attend_luau, logic.season.has(Season.summer)) + set_entrance_rule(multiworld, player, Entrance.attend_moonlight_jellies, logic.season.has(Season.summer)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_fair, player), logic.season.has(Season.fall)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_spirit_eve, player), logic.season.has(Season.fall)) + set_entrance_rule(multiworld, player, Entrance.attend_fair, logic.season.has(Season.fall)) + set_entrance_rule(multiworld, player, Entrance.attend_spirit_eve, logic.season.has(Season.fall)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_festival_of_ice, player), logic.season.has(Season.winter)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_night_market, player), logic.season.has(Season.winter)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.attend_winter_star, player), logic.season.has(Season.winter)) + set_entrance_rule(multiworld, player, Entrance.attend_festival_of_ice, logic.season.has(Season.winter)) + set_entrance_rule(multiworld, player, Entrance.attend_night_market, logic.season.has(Season.winter)) + set_entrance_rule(multiworld, player, Entrance.attend_winter_star, logic.season.has(Season.winter)) def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): - set_island_entrances_rules(logic, multiworld, player) + set_island_entrances_rules(logic, multiworld, player, world_options) if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return @@ -351,43 +328,31 @@ def set_boat_repair_rules(logic: StardewLogic, multiworld, player): logic.has(ArtisanGood.battery_pack)) -def set_island_entrances_rules(logic: StardewLogic, multiworld, player): +def set_island_entrances_rules(logic: StardewLogic, multiworld, player, world_options: StardewValleyOptions): boat_repaired = logic.received(Transportation.boat_repair) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.fish_shop_to_boat_tunnel, player), - boat_repaired) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.boat_to_ginger_island, player), - boat_repaired) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_west, player), - logic.received("Island West Turtle")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_north, player), - logic.received("Island North Turtle")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_islandfarmhouse, player), - logic.received("Island Farmhouse")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_gourmand_cave, player), - logic.received("Island Farmhouse")) dig_site_rule = logic.received("Dig Site Bridge") - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_dig_site, player), dig_site_rule) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.dig_site_to_professor_snail_cave, player), - logic.received("Open Professor Snail Cave")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_island_trader, player), - logic.received("Island Trader")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_south_to_southeast, player), - logic.received("Island Resort")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.use_island_resort, player), - logic.received("Island Resort")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_west_to_qi_walnut_room, player), - logic.received("Qi Walnut Room")) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.island_north_to_volcano, player), - (logic.tool.can_water(0) | logic.received("Volcano Bridge") | - logic.mod.magic.can_blink())) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.volcano_to_secret_beach, player), - logic.tool.can_water(2)) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_5, player), - (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.talk_to_volcano_dwarf, player), - logic.wallet.can_speak_dwarf()) - MultiWorldRules.set_rule(multiworld.get_entrance(Entrance.climb_to_volcano_10, player), - (logic.ability.can_mine_perfectly() & logic.tool.can_water(1))) + entrance_rules = { + Entrance.use_island_obelisk: logic.can_use_obelisk(Transportation.island_obelisk), + Entrance.use_farm_obelisk: logic.can_use_obelisk(Transportation.farm_obelisk), + Entrance.fish_shop_to_boat_tunnel: boat_repaired, + Entrance.boat_to_ginger_island: boat_repaired, + Entrance.island_south_to_west: logic.received("Island West Turtle"), + Entrance.island_south_to_north: logic.received("Island North Turtle"), + Entrance.island_west_to_islandfarmhouse: logic.received("Island Farmhouse"), + Entrance.island_west_to_gourmand_cave: logic.received("Island Farmhouse"), + Entrance.island_north_to_dig_site: dig_site_rule, + Entrance.dig_site_to_professor_snail_cave: logic.received("Open Professor Snail Cave"), + Entrance.talk_to_island_trader: logic.received("Island Trader"), + Entrance.island_south_to_southeast: logic.received("Island Resort"), + Entrance.use_island_resort: logic.received("Island Resort"), + Entrance.island_west_to_qi_walnut_room: logic.received("Qi Walnut Room"), + Entrance.island_north_to_volcano: logic.tool.can_water(0) | logic.received("Volcano Bridge") | logic.mod.magic.can_blink(), + Entrance.volcano_to_secret_beach: logic.tool.can_water(2), + Entrance.climb_to_volcano_5: logic.ability.can_mine_perfectly() & logic.tool.can_water(1), + Entrance.talk_to_volcano_dwarf: logic.wallet.can_speak_dwarf(), + Entrance.climb_to_volcano_10: logic.ability.can_mine_perfectly() & logic.tool.can_water(1), + Entrance.mountain_to_leo_treehouse: logic.received("Treehouse"), + } parrots = [Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_jungle_to_volcano, Entrance.parrot_express_dig_site_to_volcano, Entrance.parrot_express_docks_to_dig_site, Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_volcano_to_dig_site, @@ -398,9 +363,11 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player): parrot_express_to_dig_site_rule = dig_site_rule & parrot_express_rule for parrot in parrots: if "Dig Site" in parrot: - MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), parrot_express_to_dig_site_rule) + entrance_rules[parrot] = parrot_express_to_dig_site_rule else: - MultiWorldRules.set_rule(multiworld.get_entrance(parrot, player), parrot_express_rule) + entrance_rules[parrot] = parrot_express_rule + + set_many_island_entrances_rules(multiworld, player, entrance_rules, world_options) def set_island_parrot_rules(logic: StardewLogic, multiworld, player): @@ -672,7 +639,7 @@ def set_monstersanity_progressive_category_rule(all_location_names: List[str], l if goal_index < 3: rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category], goal_index + 1) else: - rule = logic.monster.can_kill_all(logic.monster.all_monsters_by_category[monster_category], goal_index * 2) + rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category], goal_index * 2) MultiWorldRules.set_rule(location, rule) @@ -693,7 +660,7 @@ def set_monstersanity_category_rules(all_location_names: List[str], logic: Stard if monstersanity_option == Monstersanity.option_one_per_category: rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category]) else: - rule = logic.monster.can_kill_all(logic.monster.all_monsters_by_category[monster_category], 4) + rule = logic.monster.can_kill_any(logic.monster.all_monsters_by_category[monster_category], MAX_MONTHS) MultiWorldRules.set_rule(location, rule) @@ -765,7 +732,7 @@ def set_traveling_merchant_day_rules(logic: StardewLogic, multiworld: MultiWorld for day in Weekday.all_days: item_for_day = f"Traveling Merchant: {day}" entrance_name = f"Buy from Traveling Merchant {day}" - MultiWorldRules.set_rule(multiworld.get_entrance(entrance_name, player), logic.received(item_for_day)) + set_entrance_rule(multiworld, player, entrance_name, logic.received(item_for_day)) def set_arcade_machine_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): @@ -822,11 +789,9 @@ def set_deepwoods_rules(logic: StardewLogic, multiworld: MultiWorld, player: int logic.tool.has_tool(Tool.axe, "Gold")) MultiWorldRules.add_rule(multiworld.get_location("Chop Down a Deep Woods Iridium Tree", player), logic.tool.has_tool(Tool.axe, "Iridium")) - MultiWorldRules.set_rule(multiworld.get_entrance(DeepWoodsEntrance.use_woods_obelisk, player), - logic.received("Woods Obelisk")) + set_entrance_rule(multiworld, player, DeepWoodsEntrance.use_woods_obelisk, logic.received("Woods Obelisk")) for depth in range(10, 100 + 10, 10): - MultiWorldRules.set_rule(multiworld.get_entrance(move_to_woods_depth(depth), player), - logic.mod.deepwoods.can_chop_to_depth(depth)) + set_entrance_rule(multiworld, player, move_to_woods_depth(depth), logic.mod.deepwoods.can_chop_to_depth(depth)) MultiWorldRules.add_rule(multiworld.get_location("The Sword in the Stone", player), logic.mod.deepwoods.can_pull_sword() & logic.mod.deepwoods.can_chop_to_depth(100)) @@ -893,46 +858,26 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.sve not in world_options.mods: return - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_to_lost_woods, player), - logic.bundle.can_complete_community_center) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.enter_summit, player), - logic.mod.sve.has_iridium_bomb()) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.backwoods_to_grove, player), - logic.mod.sve.has_any_rune()) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.badlands_to_cave, player), - logic.has("Aegis Elixir")) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.forest_west_to_spring, player), - logic.quest.can_complete_quest(Quest.magic_ink)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.railroad_to_grampleton_station, player), - logic.received(SVEQuestItem.scarlett_job_offer)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.secret_woods_to_west, player), - logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_shed_to_interior, player), - logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.aurora_warp_to_aurora, player), - logic.received(SVERunes.nexus_aurora)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.farm_warp_to_farm, player), - logic.received(SVERunes.nexus_farm)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.guild_warp_to_guild, player), - logic.received(SVERunes.nexus_guild)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.junimo_warp_to_junimo, player), - logic.received(SVERunes.nexus_junimo)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.spring_warp_to_spring, player), - logic.received(SVERunes.nexus_spring)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.outpost_warp_to_outpost, player), - logic.received(SVERunes.nexus_outpost)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_warp_to_wizard, player), - logic.received(SVERunes.nexus_wizard)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_purple_junimo, player), - logic.relationship.has_hearts(ModNPC.apples, 10)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.grandpa_interior_to_upstairs, player), - logic.received(SVEQuestItem.grandpa_shed)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.use_bear_shop, player), - (logic.mod.sve.can_buy_bear_recipe())) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.railroad_to_grampleton_station, player), - logic.received(SVEQuestItem.scarlett_job_offer)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.museum_to_gunther_bedroom, player), - logic.relationship.has_hearts(ModNPC.gunther, 2)) + set_entrance_rule(multiworld, player, SVEEntrance.forest_to_lost_woods, logic.bundle.can_complete_community_center) + set_entrance_rule(multiworld, player, SVEEntrance.enter_summit, logic.mod.sve.has_iridium_bomb()) + set_entrance_rule(multiworld, player, SVEEntrance.backwoods_to_grove, logic.mod.sve.has_any_rune()) + set_entrance_rule(multiworld, player, SVEEntrance.badlands_to_cave, logic.has("Aegis Elixir")) + set_entrance_rule(multiworld, player, SVEEntrance.forest_west_to_spring, logic.quest.can_complete_quest(Quest.magic_ink)) + set_entrance_rule(multiworld, player, SVEEntrance.railroad_to_grampleton_station, logic.received(SVEQuestItem.scarlett_job_offer)) + set_entrance_rule(multiworld, player, SVEEntrance.secret_woods_to_west, logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) + set_entrance_rule(multiworld, player, SVEEntrance.grandpa_shed_to_interior, logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) + set_entrance_rule(multiworld, player, SVEEntrance.aurora_warp_to_aurora, logic.received(SVERunes.nexus_aurora)) + set_entrance_rule(multiworld, player, SVEEntrance.farm_warp_to_farm, logic.received(SVERunes.nexus_farm)) + set_entrance_rule(multiworld, player, SVEEntrance.guild_warp_to_guild, logic.received(SVERunes.nexus_guild)) + set_entrance_rule(multiworld, player, SVEEntrance.junimo_warp_to_junimo, logic.received(SVERunes.nexus_junimo)) + set_entrance_rule(multiworld, player, SVEEntrance.spring_warp_to_spring, logic.received(SVERunes.nexus_spring)) + set_entrance_rule(multiworld, player, SVEEntrance.outpost_warp_to_outpost, logic.received(SVERunes.nexus_outpost)) + set_entrance_rule(multiworld, player, SVEEntrance.wizard_warp_to_wizard, logic.received(SVERunes.nexus_wizard)) + set_entrance_rule(multiworld, player, SVEEntrance.use_purple_junimo, logic.relationship.has_hearts(ModNPC.apples, 10)) + set_entrance_rule(multiworld, player, SVEEntrance.grandpa_interior_to_upstairs, logic.received(SVEQuestItem.grandpa_shed)) + set_entrance_rule(multiworld, player, SVEEntrance.use_bear_shop, (logic.mod.sve.can_buy_bear_recipe())) + set_entrance_rule(multiworld, player, SVEEntrance.railroad_to_grampleton_station, logic.received(SVEQuestItem.scarlett_job_offer)) + set_entrance_rule(multiworld, player, SVEEntrance.museum_to_gunther_bedroom, logic.relationship.has_hearts(ModNPC.gunther, 2)) logic.mod.sve.initialize_rules() for location in logic.registry.sve_location_rules: MultiWorldRules.set_rule(multiworld.get_location(location, player), @@ -944,16 +889,29 @@ def set_sve_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, worl def set_sve_ginger_island_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: return - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.summit_to_highlands, player), - logic.received(SVEQuestItem.marlon_boat_paddle)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.wizard_to_fable_reef, player), - logic.received(SVEQuestItem.fable_reef_portal)) - MultiWorldRules.set_rule(multiworld.get_entrance(SVEEntrance.highlands_to_cave, player), - logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) + set_entrance_rule(multiworld, player, SVEEntrance.summit_to_highlands, logic.received(SVEQuestItem.marlon_boat_paddle)) + set_entrance_rule(multiworld, player, SVEEntrance.wizard_to_fable_reef, logic.received(SVEQuestItem.fable_reef_portal)) + set_entrance_rule(multiworld, player, SVEEntrance.highlands_to_cave, logic.tool.has_tool(Tool.pickaxe, ToolMaterial.iron) & logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) def set_boarding_house_rules(logic: StardewLogic, multiworld: MultiWorld, player: int, world_options: StardewValleyOptions): if ModNames.boarding_house not in world_options.mods: return - MultiWorldRules.set_rule(multiworld.get_entrance(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, player), - logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) + set_entrance_rule(multiworld, player, BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, logic.tool.has_tool(Tool.axe, ToolMaterial.iron)) + + +def set_entrance_rule(multiworld, player, entrance: str, rule: CollectionRule): + MultiWorldRules.set_rule(multiworld.get_entrance(entrance, player), rule) + + +def set_island_entrance_rule(multiworld, player, entrance: str, rule: CollectionRule, world_options: StardewValleyOptions): + if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: + return + set_entrance_rule(multiworld, player, entrance, rule) + + +def set_many_island_entrances_rules(multiworld, player, entrance_rules: Dict[str, CollectionRule], world_options: StardewValleyOptions): + if world_options.exclude_ginger_island == ExcludeGingerIsland.option_true: + return + for entrance, rule in entrance_rules.items(): + set_entrance_rule(multiworld, player, entrance, rule) diff --git a/worlds/stardew_valley/stardew_rule/state.py b/worlds/stardew_valley/stardew_rule/state.py index 34b519bb89b9..159a20ac2cee 100644 --- a/worlds/stardew_valley/stardew_rule/state.py +++ b/worlds/stardew_valley/stardew_rule/state.py @@ -91,6 +91,8 @@ class Reach(BaseStardewRule): player: int def __call__(self, state: CollectionState) -> bool: + if self.resolution_hint == 'Region' and self.spot not in state.multiworld.regions.region_cache[self.player]: + return False return state.can_reach(self.spot, self.resolution_hint, self.player) def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: diff --git a/worlds/stardew_valley/test/TestOptions.py b/worlds/stardew_valley/test/TestOptions.py index 61f49ed67c2e..11329b82da29 100644 --- a/worlds/stardew_valley/test/TestOptions.py +++ b/worlds/stardew_valley/test/TestOptions.py @@ -40,7 +40,7 @@ class TestGenerateDynamicOptions(SVTestCase): def test_given_special_range_when_generate_then_basic_checks(self): options = StardewValleyWorld.options_dataclass.type_hints for option_name, option in options.items(): - if not isinstance(option, NamedRange): + if not issubclass(option, NamedRange): continue for value in option.special_range_names: with self.subTest(f"{option_name}: {value}"): diff --git a/worlds/stardew_valley/test/TestRegions.py b/worlds/stardew_valley/test/TestRegions.py index c975798906e3..91c67f2c956a 100644 --- a/worlds/stardew_valley/test/TestRegions.py +++ b/worlds/stardew_valley/test/TestRegions.py @@ -8,7 +8,7 @@ from . import SVTestCase, setup_solo_multiworld from .. import StardewValleyWorld from ..options import EntranceRandomization, ExcludeGingerIsland, StardewValleyOptions -from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag, create_final_regions +from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag, create_final_regions, create_final_connections_and_regions from ..strings.entrance_names import Entrance as EntranceName from ..strings.region_names import Region as RegionName @@ -69,9 +69,10 @@ def test_entrance_randomization(self): world_options = {EntranceRandomization.internal_name: option, ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false} multiworld = setup_solo_multiworld(world_options) - regions_by_name = {region.name: region for region in vanilla_regions} + sv_options = multiworld.worlds[1].options + entrances, regions = create_final_connections_and_regions(sv_options) - _, randomized_connections = randomize_connections(rand, multiworld.worlds[1].options, regions_by_name) + _, randomized_connections = randomize_connections(rand, sv_options, regions, entrances) for connection in vanilla_connections: if flag in connection.flag: @@ -95,9 +96,10 @@ def test_entrance_randomization_without_island(self): world_options = {EntranceRandomization.internal_name: option, ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true} multiworld = setup_solo_multiworld(world_options) - regions_by_name = {region.name: region for region in vanilla_regions} + sv_options = multiworld.worlds[1].options + entrances, regions = create_final_connections_and_regions(sv_options) - _, randomized_connections = randomize_connections(rand, multiworld.worlds[1].options, regions_by_name) + _, randomized_connections = randomize_connections(rand, sv_options, regions, entrances) for connection in vanilla_connections: if flag in connection.flag: @@ -131,14 +133,13 @@ def test_cannot_put_island_access_on_island(self): seed = random.randrange(sys.maxsize) with self.subTest(msg=f"Seed: {seed}"): rand = random.Random(seed) - final_regions = create_final_regions(world_options) - regions_by_name = {region.name: region for region in final_regions} - randomized_connections, randomized_data = randomize_connections(rand, world_options, regions_by_name) + entrances, regions = create_final_connections_and_regions(world_options) + randomized_connections, randomized_data = randomize_connections(rand, world_options, regions, entrances) connections_by_name = {connection.name: connection for connection in randomized_connections} blocked_entrances = {EntranceName.use_island_obelisk, EntranceName.boat_to_ginger_island} required_regions = {RegionName.wizard_tower, RegionName.boat_tunnel} - self.assert_can_reach_any_region_before_blockers(required_regions, blocked_entrances, connections_by_name, regions_by_name) + self.assert_can_reach_any_region_before_blockers(required_regions, blocked_entrances, connections_by_name, regions) def assert_can_reach_any_region_before_blockers(self, required_regions, blocked_entrances, connections_by_name, regions_by_name): explored_regions = explore_connections_tree_up_to_blockers(blocked_entrances, connections_by_name, regions_by_name) @@ -163,3 +164,15 @@ def test_non_progression_are_all_accessible_with_empty_inventory(self): if sv_world.randomized_entrances[randomized_entrance] in ap_entrances: ap_entrance_destination = multiworld.get_entrance(sv_world.randomized_entrances[randomized_entrance], 1) self.assertTrue(ap_entrance_destination.access_rule(multiworld.state)) + + def test_no_ginger_island_entrances_when_excluded(self): + seed = random.randrange(sys.maxsize) + multiworld_options = {EntranceRandomization.internal_name: EntranceRandomization.option_disabled, + ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true} + multiworld = setup_solo_multiworld(multiworld_options, seed) + ap_entrances = {entrance.name: entrance for entrance in multiworld.get_entrances()} + entrance_data_by_name = {entrance.name: entrance for entrance in vanilla_connections} + for entrance_name in ap_entrances: + entrance_data = entrance_data_by_name[entrance_name] + with self.subTest(f"{entrance_name}: {entrance_data.flag}"): + self.assertFalse(entrance_data.flag & RandomizationFlag.GINGER_ISLAND) diff --git a/worlds/stardew_valley/test/checks/world_checks.py b/worlds/stardew_valley/test/checks/world_checks.py index d99bc628c45a..e2b5d9b7b392 100644 --- a/worlds/stardew_valley/test/checks/world_checks.py +++ b/worlds/stardew_valley/test/checks/world_checks.py @@ -27,15 +27,9 @@ def assert_can_reach_victory(tester: unittest.TestCase, multiworld: MultiWorld): tester.assertTrue(*can_reach_victory(multiworld)) -def collect_all_then_assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): - for item in multiworld.get_items(): - multiworld.state.collect(item) - assert_can_reach_victory(tester, multiworld) - - def assert_can_win(tester: unittest.TestCase, multiworld: MultiWorld): assert_victory_exists(tester, multiworld) - collect_all_then_assert_can_win(tester, multiworld) + assert_can_reach_victory(tester, multiworld) def assert_same_number_items_locations(tester: unittest.TestCase, multiworld: MultiWorld): @@ -43,6 +37,18 @@ def assert_same_number_items_locations(tester: unittest.TestCase, multiworld: Mu tester.assertEqual(len(multiworld.itempool), len(non_event_locations)) +def assert_can_reach_everything(tester: unittest.TestCase, multiworld: MultiWorld): + for location in multiworld.get_locations(): + can_reach = location.can_reach(multiworld.state) + if hasattr(location.access_rule, "explain"): + tester.assertTrue(can_reach, location.access_rule.explain(multiworld.state)) + else: + tester.assertTrue(can_reach) + + def basic_checks(tester: unittest.TestCase, multiworld: MultiWorld): - assert_can_win(tester, multiworld) assert_same_number_items_locations(tester, multiworld) + for item in multiworld.get_items(): + multiworld.state.collect(item) + assert_can_win(tester, multiworld) + assert_can_reach_everything(tester, multiworld) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index a2a26d8a4ebe..331836cf96f5 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -6,7 +6,7 @@ from typing import List, Union from BaseClasses import MultiWorld -from .. import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_without_mods +from .. import setup_solo_multiworld, SVTestBase, SVTestCase, allsanity_options_without_mods, allsanity_options_with_mods from ..TestOptions import basic_checks from ... import items, Group, ItemClassification from ...items import item_table, items_by_group @@ -49,6 +49,17 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi # if self.skip_extra_tests: # return # assume the rest will work as well + def test_allsanity_all_mods_when_generate_then_basic_checks(self): + multi_world = setup_solo_multiworld(allsanity_options_with_mods()) + basic_checks(self, multi_world) + + def test_allsanity_all_mods_exclude_island_when_generate_then_basic_checks(self): + options = allsanity_options_with_mods() + options = {key: options[key] for key in options} + options.update({ExcludeGingerIsland: ExcludeGingerIsland.option_true}) + multi_world = setup_solo_multiworld(options) + basic_checks(self, multi_world) + class TestBaseLocationDependencies(SVTestBase): options = { From 2987e535d96c000320853cbb3d95b8f88e025daa Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 12:45:38 -0500 Subject: [PATCH 467/482] - Fixed mod tests for the new structure --- worlds/stardew_valley/test/mods/TestMods.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 331836cf96f5..16ca5d09d8b9 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -1,8 +1,6 @@ import random import sys import unittest -from collections import Counter -from itertools import chain, combinations from typing import List, Union from BaseClasses import MultiWorld @@ -14,7 +12,7 @@ from ...mods.mod_data import all_mods from ...options import Mods, EntranceRandomization, Friendsanity, SeasonRandomization, SpecialOrderLocations, ExcludeGingerIsland, TrapItems, Chefsanity, \ Shipsanity, Craftsanity, ToolProgression -from ...regions import RandomizationFlag, create_final_connections, randomize_connections, create_final_regions +from ...regions import RandomizationFlag, randomize_connections, create_final_connections_and_regions def check_stray_mod_items(chosen_mods: Union[List[str], str], tester: unittest.TestCase, multiworld: MultiWorld): @@ -141,18 +139,17 @@ def test_mod_entrance_randomization(self): Mods.internal_name: all_mods} multiworld = setup_solo_multiworld(world_options) world = multiworld.worlds[1] - final_regions = create_final_regions(world.options) - final_connections = create_final_connections(world.options) + final_connections, final_regions = create_final_connections_and_regions(world.options) - regions_by_name = {region.name: region for region in final_regions} - _, randomized_connections = randomize_connections(rand, world.options, regions_by_name) + _, randomized_connections = randomize_connections(rand, world.options, final_regions, final_connections) - for connection in final_connections: + for connection_name in final_connections: + connection = final_connections[connection_name] if flag in connection.flag: - connection_in_randomized = connection.name in randomized_connections + connection_in_randomized = connection_name in randomized_connections reverse_in_randomized = connection.reverse in randomized_connections self.assertTrue(connection_in_randomized, - f"Connection {connection.name} should be randomized but it is not in the output. Seed = {seed}") + f"Connection {connection_name} should be randomized but it is not in the output. Seed = {seed}") self.assertTrue(reverse_in_randomized, f"Connection {connection.reverse} should be randomized but it is not in the output. Seed = {seed}") From 070d4b942b968e4abba10d591dba47d0e56f9b4d Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 12:51:45 -0500 Subject: [PATCH 468/482] - Remove the ginger island flag until albrekka can fix all of them --- worlds/stardew_valley/mods/mod_regions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 9e87da685db2..17cfb5a280ba 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -221,7 +221,7 @@ ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside), ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp), From 83e073764b78e7491c37eea812356c535d76b7ee Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 12:54:41 -0500 Subject: [PATCH 469/482] - Update expected location counts --- worlds/stardew_valley/test/TestGeneration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/test/TestGeneration.py b/worlds/stardew_valley/test/TestGeneration.py index 16a12dd11b1f..20c5894911b2 100644 --- a/worlds/stardew_valley/test/TestGeneration.py +++ b/worlds/stardew_valley/test/TestGeneration.py @@ -422,7 +422,7 @@ def test_minsanity_has_fewer_than_locations(self): f"\n\t\tActual: {number_locations}") def test_default_settings_has_exactly_locations(self): - expected_locations = 421 + expected_locations = 422 multiworld = setup_solo_multiworld(default_options()) real_locations = get_real_locations(self, multiworld) number_locations = len(real_locations) @@ -434,7 +434,7 @@ def test_default_settings_has_exactly_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_without_mods_has_at_least_locations(self): - expected_locations = 1954 + expected_locations = 1956 allsanity_options = allsanity_options_without_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) @@ -448,7 +448,7 @@ def test_allsanity_without_mods_has_at_least_locations(self): f"\n\t\tActual: {number_locations}") def test_allsanity_with_mods_has_at_least_locations(self): - expected_locations = 2695 + expected_locations = 2804 allsanity_options = allsanity_options_with_mods() multiworld = setup_solo_multiworld(allsanity_options) real_locations = get_real_locations(self, multiworld) From bd822b0f61eb2686477fef280b12640ab420a060 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 19:23:35 -0500 Subject: [PATCH 470/482] - Fix some edge cases that could fail, including indirect connections on qi orders --- BaseClasses.py | 2 + worlds/stardew_valley/__init__.py | 16 ++++- worlds/stardew_valley/data/crops.csv | 62 +++++++++---------- worlds/stardew_valley/items.py | 1 + worlds/stardew_valley/logic/logic.py | 2 +- worlds/stardew_valley/logic/money_logic.py | 2 +- worlds/stardew_valley/regions.py | 4 +- .../strings/ap_names/event_names.py | 1 + .../test/long/TestOptionsLong.py | 20 ++++-- 9 files changed, 68 insertions(+), 42 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index b35b53b7904f..654d56100af6 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -656,6 +656,8 @@ def update_reachable_regions(self, player: int): queue = deque(self.blocked_connections[player]) start = self.multiworld.get_region('Menu', player) + rrp_at_start = len(rrp) + # init on first call - this can't be done on construction since the regions don't exist yet if start not in rrp: rrp.add(start) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index f15287e76c0e..f2be4d5a23a3 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -22,6 +22,7 @@ from .strings.ap_names.event_names import Event from .strings.goal_names import Goal as GoalName from .strings.region_names import Region as RegionName +from .strings.entrance_names import Entrance as EntranceName client_version = 0 @@ -117,7 +118,7 @@ def create_region(name: str, exits: Iterable[str]) -> Region: region.exits = [Entrance(self.player, exit_name, region) for exit_name in exits] return region - world_regions, self.randomized_entrances = create_regions(create_region, self.multiworld.random, self.options) + world_regions, world_entrances, self.randomized_entrances = create_regions(create_region, self.multiworld.random, self.options) def add_location(name: str, code: Optional[int], region: str): region = world_regions[region] @@ -127,6 +128,17 @@ def add_location(name: str, code: Optional[int], region: str): create_locations(add_location, self.modified_bundles, self.options, self.multiworld.random) self.multiworld.regions.extend(world_regions.values()) + self.register_indirect_connections(world_regions, world_entrances) + + def register_indirect_connections(self, world_regions, world_entrances): + if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true: + return + walnut_room = world_regions[RegionName.qi_walnut_room] + self.multiworld.register_indirect_condition(walnut_room, world_entrances[EntranceName.dig_to_dangerous_mines_20]) + self.multiworld.register_indirect_condition(walnut_room, world_entrances[EntranceName.dig_to_dangerous_mines_60]) + self.multiworld.register_indirect_condition(walnut_room, world_entrances[EntranceName.dig_to_dangerous_mines_100]) + self.multiworld.register_indirect_condition(walnut_room, world_entrances[EntranceName.enter_dangerous_skull_cavern]) + def create_items(self): self.total_progression_items = 0 self.precollect_starting_season() @@ -189,6 +201,8 @@ def setup_quest_events(self): def setup_action_events(self): can_ship_event = LocationData(None, RegionName.shipping, Event.can_ship_items) self.create_event_location(can_ship_event, True_(), Event.can_ship_items) + can_shop_pierre_event = LocationData(None, RegionName.pierre_store, Event.can_shop_at_pierre) + self.create_event_location(can_shop_pierre_event, True_(), Event.can_shop_at_pierre) def setup_victory(self): if self.options.goal == Goal.option_community_center: diff --git a/worlds/stardew_valley/data/crops.csv b/worlds/stardew_valley/data/crops.csv index 51524f63e957..0bf43a76764e 100644 --- a/worlds/stardew_valley/data/crops.csv +++ b/worlds/stardew_valley/data/crops.csv @@ -1,41 +1,41 @@ crop,farm_growth_seasons,seed,seed_seasons,seed_regions,requires_island -Amaranth,Fall,Amaranth Seeds,Fall,"Pierre's General Store,JojaMart",False -Artichoke,Fall,Artichoke Seeds,Fall,"Pierre's General Store,JojaMart",False +Amaranth,Fall,Amaranth Seeds,Fall,"Pierre's General Store",False +Artichoke,Fall,Artichoke Seeds,Fall,"Pierre's General Store",False Beet,Fall,Beet Seeds,Fall,Oasis,False -Blue Jazz,Spring,Jazz Seeds,Spring,"Pierre's General Store,JojaMart",False -Blueberry,Summer,Blueberry Seeds,Summer,"Pierre's General Store,JojaMart",False -Bok Choy,Fall,Bok Choy Seeds,Fall,"Pierre's General Store,JojaMart",False +Blue Jazz,Spring,Jazz Seeds,Spring,"Pierre's General Store",False +Blueberry,Summer,Blueberry Seeds,Summer,"Pierre's General Store",False +Bok Choy,Fall,Bok Choy Seeds,Fall,"Pierre's General Store",False Cactus Fruit,,Cactus Seeds,,Oasis,False -Cauliflower,Spring,Cauliflower Seeds,Spring,"Pierre's General Store,JojaMart",False +Cauliflower,Spring,Cauliflower Seeds,Spring,"Pierre's General Store",False Coffee Bean,"Spring,Summer",Coffee Bean,"Summer,Fall","Traveling Cart",False -Corn,"Summer,Fall",Corn Seeds,"Summer,Fall","Pierre's General Store,JojaMart",False -Cranberries,Fall,Cranberry Seeds,Fall,"Pierre's General Store,JojaMart",False -Eggplant,Fall,Eggplant Seeds,Fall,"Pierre's General Store,JojaMart",False -Fairy Rose,Fall,Fairy Seeds,Fall,"Pierre's General Store,JojaMart",False -Garlic,Spring,Garlic Seeds,Spring,"Pierre's General Store,JojaMart",False -Grape,Fall,Grape Starter,Fall,"Pierre's General Store,JojaMart",False -Green Bean,Spring,Bean Starter,Spring,"Pierre's General Store,JojaMart",False -Hops,Summer,Hops Starter,Summer,"Pierre's General Store,JojaMart",False -Hot Pepper,Summer,Pepper Seeds,Summer,"Pierre's General Store,JojaMart",False -Kale,Spring,Kale Seeds,Spring,"Pierre's General Store,JojaMart",False -Melon,Summer,Melon Seeds,Summer,"Pierre's General Store,JojaMart",False -Parsnip,Spring,Parsnip Seeds,Spring,"Pierre's General Store,JojaMart",False +Corn,"Summer,Fall",Corn Seeds,"Summer,Fall","Pierre's General Store",False +Cranberries,Fall,Cranberry Seeds,Fall,"Pierre's General Store",False +Eggplant,Fall,Eggplant Seeds,Fall,"Pierre's General Store",False +Fairy Rose,Fall,Fairy Seeds,Fall,"Pierre's General Store",False +Garlic,Spring,Garlic Seeds,Spring,"Pierre's General Store",False +Grape,Fall,Grape Starter,Fall,"Pierre's General Store",False +Green Bean,Spring,Bean Starter,Spring,"Pierre's General Store",False +Hops,Summer,Hops Starter,Summer,"Pierre's General Store",False +Hot Pepper,Summer,Pepper Seeds,Summer,"Pierre's General Store",False +Kale,Spring,Kale Seeds,Spring,"Pierre's General Store",False +Melon,Summer,Melon Seeds,Summer,"Pierre's General Store",False +Parsnip,Spring,Parsnip Seeds,Spring,"Pierre's General Store",False Pineapple,Summer,Pineapple Seeds,Summer,"Island Trader",True -Poppy,Summer,Poppy Seeds,Summer,"Pierre's General Store,JojaMart",False -Potato,Spring,Potato Seeds,Spring,"Pierre's General Store,JojaMart",False +Poppy,Summer,Poppy Seeds,Summer,"Pierre's General Store",False +Potato,Spring,Potato Seeds,Spring,"Pierre's General Store",False Qi Fruit,"Spring,Summer,Fall,Winter",Qi Bean,"Spring,Summer,Fall,Winter","Qi's Walnut Room",True -Pumpkin,Fall,Pumpkin Seeds,Fall,"Pierre's General Store,JojaMart",False -Radish,Summer,Radish Seeds,Summer,"Pierre's General Store,JojaMart",False -Red Cabbage,Summer,Red Cabbage Seeds,Summer,"Pierre's General Store,JojaMart",False +Pumpkin,Fall,Pumpkin Seeds,Fall,"Pierre's General Store",False +Radish,Summer,Radish Seeds,Summer,"Pierre's General Store",False +Red Cabbage,Summer,Red Cabbage Seeds,Summer,"Pierre's General Store",False Rhubarb,Spring,Rhubarb Seeds,Spring,Oasis,False Starfruit,Summer,Starfruit Seeds,Summer,Oasis,False -Strawberry,Spring,Strawberry Seeds,Spring,"Pierre's General Store,JojaMart",False -Summer Spangle,Summer,Spangle Seeds,Summer,"Pierre's General Store,JojaMart",False -Sunflower,"Summer,Fall",Sunflower Seeds,"Summer,Fall","Pierre's General Store,JojaMart",False +Strawberry,Spring,Strawberry Seeds,Spring,"Pierre's General Store",False +Summer Spangle,Summer,Spangle Seeds,Summer,"Pierre's General Store",False +Sunflower,"Summer,Fall",Sunflower Seeds,"Summer,Fall","Pierre's General Store",False Sweet Gem Berry,Fall,Rare Seed,"Spring,Summer",Traveling Cart,False Taro Root,Summer,Taro Tuber,Summer,"Island Trader",True -Tomato,Summer,Tomato Seeds,Summer,"Pierre's General Store,JojaMart",False -Tulip,Spring,Tulip Bulb,Spring,"Pierre's General Store,JojaMart",False -Unmilled Rice,Spring,Rice Shoot,Spring,"Pierre's General Store,JojaMart",False -Wheat,"Summer,Fall",Wheat Seeds,"Summer,Fall","Pierre's General Store,JojaMart",False -Yam,Fall,Yam Seeds,Fall,"Pierre's General Store,JojaMart",False +Tomato,Summer,Tomato Seeds,Summer,"Pierre's General Store",False +Tulip,Spring,Tulip Bulb,Spring,"Pierre's General Store",False +Unmilled Rice,Spring,Rice Shoot,Spring,"Pierre's General Store",False +Wheat,"Summer,Fall",Wheat Seeds,"Summer,Fall","Pierre's General Store",False +Yam,Fall,Yam Seeds,Fall,"Pierre's General Store",False diff --git a/worlds/stardew_valley/items.py b/worlds/stardew_valley/items.py index 197ba61d49a7..46788f3f337a 100644 --- a/worlds/stardew_valley/items.py +++ b/worlds/stardew_valley/items.py @@ -134,6 +134,7 @@ def load_item_csv(): ItemData(None, Event.can_construct_buildings, ItemClassification.progression), ItemData(None, Event.start_dark_talisman_quest, ItemClassification.progression), ItemData(None, Event.can_ship_items, ItemClassification.progression), + ItemData(None, Event.can_shop_at_pierre, ItemClassification.progression), ] all_items: List[ItemData] = load_item_csv() + events diff --git a/worlds/stardew_valley/logic/logic.py b/worlds/stardew_valley/logic/logic.py index f61f13c5659c..fed032303dbc 100644 --- a/worlds/stardew_valley/logic/logic.py +++ b/worlds/stardew_valley/logic/logic.py @@ -309,7 +309,7 @@ def __init__(self, player: int, options: StardewValleyOptions): Gift.movie_ticket: self.money.can_spend_at(Region.movie_ticket_stand, 1000), Gift.pearl: (self.has(Fish.blobfish) & self.building.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove), Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months, - Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200), + Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200) & self.relationship.has_hearts(NPC.krobus, 10), Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal), Ingredient.oil: self.money.can_spend_at(Region.pierre_store, 200) | (self.has(Machine.oil_maker) & (self.has(Vegetable.corn) | self.has(Flower.sunflower) | self.has(Seed.sunflower))), Ingredient.qi_seasoning: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 10), diff --git a/worlds/stardew_valley/logic/money_logic.py b/worlds/stardew_valley/logic/money_logic.py index 7325374002fa..92945a3636a8 100644 --- a/worlds/stardew_valley/logic/money_logic.py +++ b/worlds/stardew_valley/logic/money_logic.py @@ -47,7 +47,7 @@ def can_have_earned_total(self, amount: int) -> StardewRule: if amount < 10000: return shipping_rule - seed_rules = self.logic.region.can_reach_any((Region.pierre_store, Region.oasis)) + seed_rules = self.logic.received(Event.can_shop_at_pierre) if amount < 40000: return shipping_rule & seed_rules diff --git a/worlds/stardew_valley/regions.py b/worlds/stardew_valley/regions.py index e0c9aae4a1fd..4284b438f806 100644 --- a/worlds/stardew_valley/regions.py +++ b/worlds/stardew_valley/regions.py @@ -533,7 +533,7 @@ def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionD def create_regions(region_factory: RegionFactory, random: Random, world_options: StardewValleyOptions) -> Tuple[ - Dict[str, Region], Dict[str, str]]: + Dict[str, Region], Dict[str, Entrance], Dict[str, str]]: entrances_data, regions_data = create_final_connections_and_regions(world_options) regions_by_name: Dict[str: Region] = {region_name: region_factory(region_name, regions_data[region_name].exits) for region_name in regions_data} entrances_by_name: Dict[str: Entrance] = {entrance.name: entrance for region in regions_by_name.values() for entrance in region.exits @@ -544,7 +544,7 @@ def create_regions(region_factory: RegionFactory, random: Random, world_options: for connection in connections: if connection.name in entrances_by_name: entrances_by_name[connection.name].connect(regions_by_name[connection.destination]) - return regions_by_name, randomized_data + return regions_by_name, entrances_by_name, randomized_data def randomize_connections(random: Random, world_options: StardewValleyOptions, regions_by_name: Dict[str, RegionData], diff --git a/worlds/stardew_valley/strings/ap_names/event_names.py b/worlds/stardew_valley/strings/ap_names/event_names.py index ec5ddd1477da..08b9d8f8131c 100644 --- a/worlds/stardew_valley/strings/ap_names/event_names.py +++ b/worlds/stardew_valley/strings/ap_names/event_names.py @@ -3,3 +3,4 @@ class Event: can_construct_buildings = "Can Construct Buildings" start_dark_talisman_quest = "Start Dark Talisman Quest" can_ship_items = "Can Ship Items" + can_shop_at_pierre = "Can Shop At Pierre's" diff --git a/worlds/stardew_valley/test/long/TestOptionsLong.py b/worlds/stardew_valley/test/long/TestOptionsLong.py index 84319f3649c5..84a5c218d5a2 100644 --- a/worlds/stardew_valley/test/long/TestOptionsLong.py +++ b/worlds/stardew_valley/test/long/TestOptionsLong.py @@ -5,6 +5,8 @@ from .option_names import options_to_include from ..checks.world_checks import basic_checks from .. import setup_solo_multiworld, SVTestCase, SVTestBase +from ... import Goal +from ...options import EntranceRandomization, SpecialOrderLocations, Monstersanity def get_option_choices(option) -> Dict[str, int]: @@ -37,11 +39,17 @@ def test_given_option_pair_when_generate_then_basic_checks(self): basic_checks(self, multiworld) -class TestDynamicOptionDebug(SVTestBase): - options = { - "goal": "gourmet_chef", - "friendsanity": "bachelors" - } +class TestDynamicOptionDebug(SVTestCase): def test_option_pair_debug(self): - basic_checks(self, self.multiworld) + options = { + SpecialOrderLocations.internal_name: SpecialOrderLocations.option_board_qi, + Monstersanity.internal_name: Monstersanity.option_one_per_monster, + } + for i in range(1): + # seed = int(random() * pow(10, 18) - 1) + seed = 823942126251776128 + with self.subTest(f"Seed: {seed}"): + print(f"Seed: {seed}") + multiworld = setup_solo_multiworld(options, seed) + basic_checks(self, multiworld) From b5a78b0564ab655f0490e9865a27791c76a6913e Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 25 Jan 2024 00:19:53 -0600 Subject: [PATCH 471/482] Fix Ginger Island Acces Rules --- worlds/stardew_valley/data/locations.csv | 4 ++-- worlds/stardew_valley/mods/mod_regions.py | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index 943495fbfe2a..a4ec1f89620f 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2756,8 +2756,8 @@ id,region,name,tags,mod_name 8054,Shipping,Shipsanity: Meteor Carp,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded 8055,Shipping,Shipsanity: Minnow,"SHIPSANITY,SHIPSANITY_FISH",Stardew Valley Expanded 8056,Shipping,Shipsanity: Mixed Berry Pie,SHIPSANITY,Stardew Valley Expanded -8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded -8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded +8057,Shipping,Shipsanity: Monster Fruit,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded +8058,Shipping,Shipsanity: Monster Mushroom,"SHIPSANITY,SHIPSANITY_CROP,SHIPSANITY_FULL_SHIPMENT,GINGER_ISLAND",Stardew Valley Expanded 8059,Shipping,Shipsanity: Mushroom Berry Rice,SHIPSANITY,Stardew Valley Expanded 8060,Shipping,Shipsanity: Mushroom Colony,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",Stardew Valley Expanded 8061,Shipping,Shipsanity: Ornate Treasure Chest,"SHIPSANITY,GINGER_ISLAND",Stardew Valley Expanded diff --git a/worlds/stardew_valley/mods/mod_regions.py b/worlds/stardew_valley/mods/mod_regions.py index 17cfb5a280ba..df0a12f6ef18 100644 --- a/worlds/stardew_valley/mods/mod_regions.py +++ b/worlds/stardew_valley/mods/mod_regions.py @@ -221,7 +221,7 @@ ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town), ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), - ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside), + ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.GINGER_ISLAND), ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp), @@ -240,14 +240,13 @@ ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), ConnectionData(SVEEntrance.grove_to_spring_warp, SVERegion.grove_spring_warp), ConnectionData(SVEEntrance.spring_warp_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.guild_to_mines, Region.mines, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA), ConnectionData(SVEEntrance.mountain_to_guild_summit, SVERegion.guild_summit), - ConnectionData(SVEEntrance.summit_to_boat, SVERegion.marlon_boat), ConnectionData(SVEEntrance.forest_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.secret_woods_to_west, SVERegion.forest_west), ConnectionData(SVEEntrance.west_to_aurora, SVERegion.aurora_vineyard, flag=RandomizationFlag.NON_PROGRESSION), @@ -258,20 +257,20 @@ ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION), - ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder), - ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder, flag=RandomizationFlag.GINGER_ISLAND), + ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop), ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop), ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop), ConnectionData(SVEEntrance.use_isaac_shop, SVERegion.isaac_shop), - ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(SVEEntrance.railroad_to_grampleton_station, SVERegion.grampleton_station), ConnectionData(SVEEntrance.grampleton_station_to_grampleton_suburbs, SVERegion.grampleton_suburbs), ConnectionData(SVEEntrance.grampleton_suburbs_to_scarlett_house, SVERegion.scarlett_house, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.first_slash_guild_to_hallway, SVERegion.first_slash_hallway, flag=RandomizationFlag.BUILDINGS), - ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room, flag=RandomizationFlag.BUILDINGS), + ConnectionData(SVEEntrance.first_slash_guild_to_hallway, SVERegion.first_slash_hallway, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), + ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND), ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.fish_shop_to_willy_bedroom, SVERegion.willy_bedroom, flag=RandomizationFlag.BUILDINGS), ConnectionData(SVEEntrance.museum_to_gunther_bedroom, SVERegion.gunther_bedroom, flag=RandomizationFlag.BUILDINGS), From d36d24d80b04bca6626357f2fe98e85f662b85ef Mon Sep 17 00:00:00 2001 From: Witchybun Date: Thu, 25 Jan 2024 20:32:25 -0600 Subject: [PATCH 472/482] Fix Void Soul GI reqs and naming --- worlds/stardew_valley/data/items.csv | 2 +- worlds/stardew_valley/data/locations.csv | 2 +- worlds/stardew_valley/strings/ap_names/mods/mod_items.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index cfcb6adea203..560548fcb3e2 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -810,7 +810,7 @@ id,name,classification,groups,mod_name 10501,Marlon's Boat Paddle,progression,GINGER_ISLAND,Stardew Valley Expanded 10502,Diamond Wand,filler,"WEAPON,DEPRECATED",Stardew Valley Expanded 10503,Iridium Bomb,progression,,Stardew Valley Expanded -10504,Krobus' Protection,useful,,Stardew Valley Expanded +10504,Void Spirit Peace Agreement,useful,GINGER_ISLAND,Stardew Valley Expanded 10505,Kittyfish Spell,progression,,Stardew Valley Expanded 10506,Nexus: Adventurer's Guild Runes,progression,MOD_WARP,Stardew Valley Expanded 10507,Nexus: Junimo Woods Runes,progression,MOD_WARP,Stardew Valley Expanded diff --git a/worlds/stardew_valley/data/locations.csv b/worlds/stardew_valley/data/locations.csv index a4ec1f89620f..d18072971fba 100644 --- a/worlds/stardew_valley/data/locations.csv +++ b/worlds/stardew_valley/data/locations.csv @@ -2619,7 +2619,7 @@ id,region,name,tags,mod_name 7509,Grandpa's Shed Interior,Grandpa's Shed,"STORY_QUEST",Stardew Valley Expanded 7510,Aurora Vineyard,Aurora Vineyard,"STORY_QUEST",Stardew Valley Expanded 7511,Lance's House Main,Monster Crops,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded -7512,Sewer,Void Soul Retrieval,"STORY_QUEST",Stardew Valley Expanded +7512,Sewer,Void Soul Retrieval,"STORY_QUEST,GINGER_ISLAND",Stardew Valley Expanded 7513,Fairhaven Farm,Andy's Cellar,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7514,Adventurer's Guild,A Mysterious Venture,SPECIAL_ORDER_BOARD,Stardew Valley Expanded 7515,Jenkins' Residence,An Elegant Reception,SPECIAL_ORDER_BOARD,Stardew Valley Expanded diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 2b4423a384af..82064a36b97a 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -16,7 +16,7 @@ class SkillLevel: class SVEQuestItem: aurora_vineyard_tablet = "Aurora Vineyard Tablet" iridium_bomb = "Iridium Bomb" - void_soul = "Krobus' Protection" + void_soul = "Void Spirit Peace Agreement" kittyfish_spell = "Kittyfish Spell" scarlett_job_offer = "Scarlett's Job Offer" morgan_schooling = "Morgan's Schooling" From 7c105745b0bc0efd9aebdd5c9824b6ebf7234ccb Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 22:53:56 -0500 Subject: [PATCH 473/482] - Fragments of the past should just require bone fragments --- worlds/stardew_valley/logic/special_order_logic.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/stardew_valley/logic/special_order_logic.py b/worlds/stardew_valley/logic/special_order_logic.py index 4f6ef4d4bc0b..e0b1a7e2fb27 100644 --- a/worlds/stardew_valley/logic/special_order_logic.py +++ b/worlds/stardew_valley/logic/special_order_logic.py @@ -62,8 +62,7 @@ def initialize_rules(self): self.logic.has_all(Mineral.ruby, Mineral.topaz, Mineral.emerald, Mineral.jade, Mineral.amethyst, ArtisanGood.cloth)), SpecialOrder.gifts_for_george: self.logic.season.has(Season.spring) & self.logic.has(Forageable.leek), - SpecialOrder.fragments_of_the_past: self.logic.region.can_reach(Region.dig_site) & self.logic.tool.has_tool(Tool.pickaxe) & - self.logic.monster.can_kill(Monster.skeleton), + SpecialOrder.fragments_of_the_past: self.logic.monster.can_kill(Monster.skeleton), SpecialOrder.gus_famous_omelet: self.logic.has(AnimalProduct.any_egg), SpecialOrder.crop_order: self.logic.ability.can_farm_perfectly() & self.logic.received(Event.can_ship_items), SpecialOrder.community_cleanup: self.logic.skill.can_crab_pot, From cad0d3df40bcb835cd2e9304d12a3f729af89b39 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Thu, 25 Jan 2024 23:08:02 -0500 Subject: [PATCH 474/482] - Revert changes before doing a PR --- BaseClasses.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 654d56100af6..38598d42d999 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -651,17 +651,15 @@ def __init__(self, parent: MultiWorld): def update_reachable_regions(self, player: int): self.stale[player] = False - rrp = self.reachable_regions[player] - bc = self.blocked_connections[player] + reachable_regions = self.reachable_regions[player] + blocked_connections = self.blocked_connections[player] queue = deque(self.blocked_connections[player]) - start = self.multiworld.get_region('Menu', player) - - rrp_at_start = len(rrp) + start = self.multiworld.get_region("Menu", player) # init on first call - this can't be done on construction since the regions don't exist yet - if start not in rrp: - rrp.add(start) - bc.update(start.exits) + if start not in reachable_regions: + reachable_regions.add(start) + blocked_connections.update(start.exits) queue.extend(start.exits) # run BFS on all connections, and keep track of those blocked by missing items From 8ca6f059fba12356de2e66c3f7256013e016baa0 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 26 Jan 2024 10:43:06 -0500 Subject: [PATCH 475/482] - Made some items useful instead of filler --- worlds/stardew_valley/data/items.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/data/items.csv b/worlds/stardew_valley/data/items.csv index 560548fcb3e2..fdd08437f356 100644 --- a/worlds/stardew_valley/data/items.csv +++ b/worlds/stardew_valley/data/items.csv @@ -679,20 +679,20 @@ id,name,classification,groups,mod_name 5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5215,Iridium Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5216,Scarecrow,filler,RESOURCE_PACK, -5217,Deluxe Scarecrow,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5217,Deluxe Scarecrow,useful,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5218,Furnace,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5219,Charcoal Kiln,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK", -5224,Horse Flute,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5225,Pierre's Missing Stocklist,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5224,Horse Flute,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5225,Pierre's Missing Stocklist,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5227,Enricher,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5228,Pressure Nozzle,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5229,Deconstructor,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", -5230,Key To The Town,filler,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", +5230,Key To The Town,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5231,Galaxy Soul,filler,"GINGER_ISLAND,RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5232,Mushroom Tree Seed,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", 5233,Resource Pack: 20 Magic Bait,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL", From 6cb5ecb883b88dfe67c2ca87c2e23c2d934ddbd9 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Fri, 26 Jan 2024 10:43:18 -0500 Subject: [PATCH 476/482] - Split long tests from fill tests --- worlds/stardew_valley/test/__init__.py | 7 +++++-- worlds/stardew_valley/test/mods/TestMods.py | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/worlds/stardew_valley/test/__init__.py b/worlds/stardew_valley/test/__init__.py index 80e563121ae3..0b83a2dabac7 100644 --- a/worlds/stardew_valley/test/__init__.py +++ b/worlds/stardew_valley/test/__init__.py @@ -201,7 +201,7 @@ class SVTestCase(unittest.TestCase): world: StardewValleyWorld player: ClassVar[int] = 1 # Set False to not skip some 'extra' tests - skip_extra_tests: bool = True + skip_base_tests: bool = True # Set False to run tests that take long skip_long_tests: bool = True @@ -210,6 +210,9 @@ class SVTestCase(unittest.TestCase): @classmethod def setUpClass(cls) -> None: super().setUpClass() + base_tests_key = "base" + if base_tests_key in os.environ: + cls.skip_base_tests = not bool(os.environ[base_tests_key]) long_tests_key = "long" if long_tests_key in os.environ: cls.skip_long_tests = not bool(os.environ[long_tests_key]) @@ -225,7 +228,7 @@ def world_setup(self, *args, **kwargs): @property def run_default_tests(self) -> bool: - if self.skip_long_tests: + if self.skip_base_tests: return False # world_setup is overridden, so it'd always run default tests when importing SVTestBase is_not_stardew_test = type(self) is not SVTestBase diff --git a/worlds/stardew_valley/test/mods/TestMods.py b/worlds/stardew_valley/test/mods/TestMods.py index 16ca5d09d8b9..bf24fce72603 100644 --- a/worlds/stardew_valley/test/mods/TestMods.py +++ b/worlds/stardew_valley/test/mods/TestMods.py @@ -44,8 +44,6 @@ def test_given_mod_names_when_generate_paired_with_entrance_randomizer_then_basi multiworld = setup_solo_multiworld({EntranceRandomization.internal_name: EntranceRandomization.options[option], Mods: mod}) basic_checks(self, multiworld) check_stray_mod_items(mod, self, multiworld) - # if self.skip_extra_tests: - # return # assume the rest will work as well def test_allsanity_all_mods_when_generate_then_basic_checks(self): multi_world = setup_solo_multiworld(allsanity_options_with_mods()) From 5d922c0cb5e59272ad440f05f70e0e4236d139ed Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 28 Jan 2024 18:03:00 -0500 Subject: [PATCH 477/482] - Add randomized entrances to the spoiler log output --- worlds/stardew_valley/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index f2be4d5a23a3..dc779503b1b1 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -14,7 +14,7 @@ from .logic.logic import StardewLogic from .logic.time_logic import MAX_MONTHS from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \ - BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems + BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems, EntranceRandomization from .presets import sv_options_presets from .regions import create_regions from .rules import set_rules @@ -338,6 +338,12 @@ def get_filler_item_rules(self): else: return self.options.trap_items != TrapItems.option_no_traps, self.options.exclude_ginger_island == ExcludeGingerIsland.option_true + def generate_output(self, output_directory: str): + if self.options.entrance_randomization == EntranceRandomization.option_disabled: + return + for original_entrance, replaced_entrance in self.randomized_entrances.items(): + self.multiworld.spoiler.set_entrance(original_entrance, replaced_entrance, "entrance", self.player) + def fill_slot_data(self) -> Dict[str, Any]: bundles = dict() From 9d4f5b9a4e5258a26351a0c2613cae8e04169f2c Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 28 Jan 2024 23:29:01 -0500 Subject: [PATCH 478/482] - Changed imports to be relative - Moved test file - Removed hard coded seed from stability test - Removed unused initialization of the number_progression_items variable --- worlds/stardew_valley/__init__.py | 1 - .../stardew_valley/test/{ => long}/TestRandomWorlds.py | 10 +++++----- worlds/stardew_valley/test/stability/TestStability.py | 4 +++- 3 files changed, 8 insertions(+), 7 deletions(-) rename worlds/stardew_valley/test/{ => long}/TestRandomWorlds.py (86%) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index dc779503b1b1..74c4efb60f0f 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -140,7 +140,6 @@ def register_indirect_connections(self, world_regions, world_entrances): self.multiworld.register_indirect_condition(walnut_room, world_entrances[EntranceName.enter_dangerous_skull_cavern]) def create_items(self): - self.total_progression_items = 0 self.precollect_starting_season() items_to_exclude = [excluded_items for excluded_items in self.multiworld.precollected_items[self.player] diff --git a/worlds/stardew_valley/test/TestRandomWorlds.py b/worlds/stardew_valley/test/long/TestRandomWorlds.py similarity index 86% rename from worlds/stardew_valley/test/TestRandomWorlds.py rename to worlds/stardew_valley/test/long/TestRandomWorlds.py index db5e0278c06f..62ad7d7c1cc1 100644 --- a/worlds/stardew_valley/test/TestRandomWorlds.py +++ b/worlds/stardew_valley/test/long/TestRandomWorlds.py @@ -3,12 +3,12 @@ from BaseClasses import MultiWorld from Options import NamedRange, Range -from worlds.stardew_valley.test import setup_solo_multiworld, SVTestCase -from worlds.stardew_valley.test.checks.goal_checks import assert_goal_world_is_valid -from worlds.stardew_valley.test.checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ +from .. import setup_solo_multiworld, SVTestCase +from ..checks.goal_checks import assert_goal_world_is_valid +from ..checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \ assert_festivals_give_access_to_deluxe_scarecrow, assert_has_festival_recipes -from worlds.stardew_valley.test.checks.world_checks import assert_same_number_items_locations, assert_victory_exists -from worlds.stardew_valley.test.long.option_names import options_to_include +from ..checks.world_checks import assert_same_number_items_locations, assert_victory_exists +from .option_names import options_to_include def get_option_choices(option) -> Dict[str, int]: diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py index 7710b1788daa..978b58a117ae 100644 --- a/worlds/stardew_valley/test/stability/TestStability.py +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -3,6 +3,7 @@ import subprocess import sys import unittest +from random import random from BaseClasses import get_seed @@ -17,7 +18,8 @@ class TestGenerationIsStable(unittest.TestCase): """ def test_all_locations_and_items_are_the_same_between_two_generations(self): - seed = get_seed(33778671150797368040) + # seed = get_seed(33778671150797368040) # troubleshooting seed + seed = random.randrange(sys.maxsize) output_a = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) output_b = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) From 5d53a9f8da646d5803e1c46ba354481d3978cdb7 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 28 Jan 2024 23:30:23 -0500 Subject: [PATCH 479/482] - Fixed bad get_seed() --- worlds/stardew_valley/options.py | 12 ++++++------ .../stardew_valley/test/stability/TestStability.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 07e7ca3fa2b4..02240a3d59ac 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -7,12 +7,12 @@ class Goal(Choice): """What's your goal with this play-through? - Community Center: Complete the Community Center. - Grandpa's Evaluation: Succeed Grandpa's evaluation with 4 lit candles. - Bottom of the Mines: Reach level 120 in the mineshaft. - Cryptic Note: Complete the quest "Cryptic Note" where Mr Qi asks you to reach floor 100 in the Skull Cavern. - Master Angler: Catch every fish in the game. Pairs well with Fishsanity. - Complete Collection: Complete the museum by donating every possible item. Pairs well with Museumsanity. + Community Center: Complete the Community Center + Grandpa's Evaluation: Succeed Grandpa's evaluation with 4 lit candles + Bottom of the Mines: Reach level 120 in the mineshaft + Cryptic Note: Complete the quest "Cryptic Note" where Mr Qi asks you to reach floor 100 in the Skull Cavern + Master Angler: Catch every fish in the game. Pairs well with Fishsanity + Complete Collection: Complete the museum by donating every possible item. Pairs well with Museumsanity Full House: Get married and have two children. Pairs well with Friendsanity. Greatest Walnut Hunter: Find all 130 Golden Walnuts Protector of the Valley: Complete all the monster slayer goals. Pairs well with Monstersanity diff --git a/worlds/stardew_valley/test/stability/TestStability.py b/worlds/stardew_valley/test/stability/TestStability.py index 978b58a117ae..32543b50b4d6 100644 --- a/worlds/stardew_valley/test/stability/TestStability.py +++ b/worlds/stardew_valley/test/stability/TestStability.py @@ -19,7 +19,7 @@ class TestGenerationIsStable(unittest.TestCase): def test_all_locations_and_items_are_the_same_between_two_generations(self): # seed = get_seed(33778671150797368040) # troubleshooting seed - seed = random.randrange(sys.maxsize) + seed = get_seed() output_a = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) output_b = subprocess.check_output([sys.executable, '-m', 'worlds.stardew_valley.test.stability.StabilityOutputScript', '--seed', str(seed)]) From 7c979cc914a6dfa2a66aa6358ecd350005d9d7dd Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Sun, 28 Jan 2024 23:35:29 -0500 Subject: [PATCH 480/482] - Improved descriptions for the goal options --- worlds/stardew_valley/options.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 02240a3d59ac..0419c15298f4 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -11,18 +11,18 @@ class Goal(Choice): Grandpa's Evaluation: Succeed Grandpa's evaluation with 4 lit candles Bottom of the Mines: Reach level 120 in the mineshaft Cryptic Note: Complete the quest "Cryptic Note" where Mr Qi asks you to reach floor 100 in the Skull Cavern - Master Angler: Catch every fish in the game. Pairs well with Fishsanity + Master Angler: Catch every fish. Adapts to chosen Fishsanity option Complete Collection: Complete the museum by donating every possible item. Pairs well with Museumsanity - Full House: Get married and have two children. Pairs well with Friendsanity. + Full House: Get married and have two children. Pairs well with Friendsanity Greatest Walnut Hunter: Find all 130 Golden Walnuts - Protector of the Valley: Complete all the monster slayer goals. Pairs well with Monstersanity - Full Shipment: Ship every item in the collection tab. Pairs well with Shipsanity - Gourmet Chef: Cook every recipe. Pairs well with Chefsanity and Cooksanity - Craft Master: Craft every item. Pairs well with Craftsanity + Protector of the Valley: Complete all the monster slayer goals. Adapts to Monstersanity + Full Shipment: Ship every item in the collection tab. Adapts to Shipsanity + Gourmet Chef: Cook every recipe. Adapts to Cooksanity + Craft Master: Craft every item. Adapts to Craftsanity Legend: Earn 10 000 000g Mystery of the Stardrops: Find every stardrop Allsanity: Complete every check in your slot - Perfection: Attain Perfection, based on the vanilla definition. + Perfection: Attain Perfection, based on the vanilla definition """ internal_name = "goal" display_name = "Goal" From 696a166463285a391224adcb2c3bc3e7211ae540 Mon Sep 17 00:00:00 2001 From: Alex Gilbert Date: Wed, 31 Jan 2024 14:17:46 -0500 Subject: [PATCH 481/482] - Moved spoiler interactions to the correct stages - Added bundles to the spoiler log --- worlds/stardew_valley/__init__.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/__init__.py b/worlds/stardew_valley/__init__.py index 74c4efb60f0f..b79703021bcc 100644 --- a/worlds/stardew_valley/__init__.py +++ b/worlds/stardew_valley/__init__.py @@ -1,5 +1,5 @@ import logging -from typing import Dict, Any, Iterable, Optional, Union, List +from typing import Dict, Any, Iterable, Optional, Union, List, TextIO from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld from Options import PerGameCommonOptions @@ -337,14 +337,38 @@ def get_filler_item_rules(self): else: return self.options.trap_items != TrapItems.option_no_traps, self.options.exclude_ginger_island == ExcludeGingerIsland.option_true - def generate_output(self, output_directory: str): + def write_spoiler_header(self, spoiler_handle: TextIO) -> None: + """Write to the spoiler header. If individual it's right at the end of that player's options, + if as stage it's right under the common header before per-player options.""" + self.add_entrances_to_spoiler_log() + + def write_spoiler(self, spoiler_handle: TextIO) -> None: + """Write to the spoiler "middle", this is after the per-player options and before locations, + meant for useful or interesting info.""" + self.add_bundles_to_spoiler_log(spoiler_handle) + + def add_bundles_to_spoiler_log(self, spoiler_handle: TextIO): + if self.options.bundle_randomization == BundleRandomization.option_vanilla: + return + player_name = self.multiworld.get_player_name(self.player) + spoiler_handle.write(f"\n\nCommunity Center ({player_name}):\n") + for room in self.modified_bundles: + for bundle in room.bundles: + spoiler_handle.write(f"\t[{room.name}] {bundle.name} ({bundle.number_required} required):\n") + for i, item in enumerate(bundle.items): + if "Basic" in item.quality: + quality = "" + else: + quality = f" ({item.quality.split(' ')[0]})" + spoiler_handle.write(f"\t\t{item.amount}x {item.item_name}{quality}\n") + + def add_entrances_to_spoiler_log(self): if self.options.entrance_randomization == EntranceRandomization.option_disabled: return for original_entrance, replaced_entrance in self.randomized_entrances.items(): self.multiworld.spoiler.set_entrance(original_entrance, replaced_entrance, "entrance", self.player) def fill_slot_data(self) -> Dict[str, Any]: - bundles = dict() for room in self.modified_bundles: bundles[room.name] = dict() From 1bd85947be78c8a0f5772437a149c1deb3430437 Mon Sep 17 00:00:00 2001 From: Witchybun Date: Sun, 4 Feb 2024 04:36:41 -0600 Subject: [PATCH 482/482] Remove Diamond Wand, Fix Andy's Cellar Logic --- worlds/stardew_valley/mods/logic/special_orders_logic.py | 6 ++++-- worlds/stardew_valley/strings/ap_names/mods/mod_items.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/stardew_valley/mods/logic/special_orders_logic.py b/worlds/stardew_valley/mods/logic/special_orders_logic.py index 082ae9719786..e51a23d50254 100644 --- a/worlds/stardew_valley/mods/logic/special_orders_logic.py +++ b/worlds/stardew_valley/mods/logic/special_orders_logic.py @@ -8,10 +8,12 @@ from ...logic.crafting_logic import CraftingLogicMixin from ...logic.crop_logic import CropLogicMixin from ...logic.has_logic import HasLogicMixin +from ...logic.received_logic import ReceivedLogicMixin from ...logic.region_logic import RegionLogicMixin from ...logic.relationship_logic import RelationshipLogicMixin from ...logic.season_logic import SeasonLogicMixin from ...logic.wallet_logic import WalletLogicMixin +from ...strings.ap_names.community_upgrade_names import CommunityUpgrade from ...strings.artisan_good_names import ArtisanGood from ...strings.craftable_names import Consumable, Edible, Bomb from ...strings.crop_names import Fruit @@ -33,7 +35,7 @@ def __init__(self, *args, **kwargs): class ModSpecialOrderLogic(BaseLogic[Union[ActionLogicMixin, ArtisanLogicMixin, CraftingLogicMixin, CropLogicMixin, HasLogicMixin, RegionLogicMixin, -RelationshipLogicMixin, SeasonLogicMixin, WalletLogicMixin]]): +ReceivedLogicMixin, RelationshipLogicMixin, SeasonLogicMixin, WalletLogicMixin]]): def get_modded_special_orders_rules(self): special_orders = {} if ModNames.juna in self.options.mods: @@ -48,7 +50,7 @@ def get_modded_special_orders_rules(self): if ModNames.sve in self.options.mods: special_orders.update({ ModSpecialOrder.andys_cellar: self.logic.has(Material.stone) & self.logic.has(Material.wood) & self.logic.has(Material.hardwood) & - self.logic.has(MetalBar.iron) & + self.logic.has(MetalBar.iron) & self.logic.received(CommunityUpgrade.movie_theater, 1) & self.logic.region.can_reach(SVERegion.fairhaven_farm), ModSpecialOrder.a_mysterious_venture: self.logic.has(Bomb.cherry_bomb) & self.logic.has(Bomb.bomb) & self.logic.has(Bomb.mega_bomb) & self.logic.region.can_reach(Region.adventurer_guild), diff --git a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py index 82064a36b97a..ccc2765544a6 100644 --- a/worlds/stardew_valley/strings/ap_names/mods/mod_items.py +++ b/worlds/stardew_valley/strings/ap_names/mods/mod_items.py @@ -26,7 +26,7 @@ class SVEQuestItem: grandpa_shed = "Grandpa's Shed" sve_quest_items: List[str] = [aurora_vineyard_tablet, iridium_bomb, void_soul, kittyfish_spell, scarlett_job_offer, morgan_schooling, grandpa_shed] - sve_quest_items_ginger_island: List[str] = [diamond_wand, marlon_boat_paddle, fable_reef_portal] + sve_quest_items_ginger_island: List[str] = [marlon_boat_paddle, fable_reef_portal] class SVELocation: